All writers can write to stream
This commit is contained in:
parent
9cdbddf3bf
commit
fcf7820467
|
@ -22,7 +22,6 @@ namespace PhpOffice\PhpSpreadsheet\Shared\OLE\PPS;
|
||||||
//
|
//
|
||||||
use PhpOffice\PhpSpreadsheet\Shared\OLE;
|
use PhpOffice\PhpSpreadsheet\Shared\OLE;
|
||||||
use PhpOffice\PhpSpreadsheet\Shared\OLE\PPS;
|
use PhpOffice\PhpSpreadsheet\Shared\OLE\PPS;
|
||||||
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for creating Root PPS's for OLE containers.
|
* Class for creating Root PPS's for OLE containers.
|
||||||
|
@ -33,23 +32,11 @@ use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
|
||||||
*/
|
*/
|
||||||
class Root extends PPS
|
class Root extends PPS
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Directory for temporary files.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $tempDirectory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var resource
|
* @var resource
|
||||||
*/
|
*/
|
||||||
private $fileHandle;
|
private $fileHandle;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $tempFilename;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
|
@ -67,8 +54,6 @@ class Root extends PPS
|
||||||
*/
|
*/
|
||||||
public function __construct($time_1st, $time_2nd, $raChild)
|
public function __construct($time_1st, $time_2nd, $raChild)
|
||||||
{
|
{
|
||||||
$this->tempDirectory = \PhpOffice\PhpSpreadsheet\Shared\File::sysGetTempDir();
|
|
||||||
|
|
||||||
parent::__construct(null, OLE::ascToUcs('Root Entry'), OLE::OLE_PPS_TYPE_ROOT, null, null, null, $time_1st, $time_2nd, null, $raChild);
|
parent::__construct(null, OLE::ascToUcs('Root Entry'), OLE::OLE_PPS_TYPE_ROOT, null, null, null, $time_1st, $time_2nd, null, $raChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,14 +64,14 @@ class Root extends PPS
|
||||||
* If a resource pointer to a stream created by fopen() is passed
|
* If a resource pointer to a stream created by fopen() is passed
|
||||||
* it will be used, but you have to close such stream by yourself.
|
* it will be used, but you have to close such stream by yourself.
|
||||||
*
|
*
|
||||||
* @param resource|string $filename the name of the file or stream where to save the OLE container
|
* @param resource $fileHandle the name of the file or stream where to save the OLE container
|
||||||
*
|
|
||||||
* @throws WriterException
|
|
||||||
*
|
*
|
||||||
* @return bool true on success
|
* @return bool true on success
|
||||||
*/
|
*/
|
||||||
public function save($filename)
|
public function save($fileHandle)
|
||||||
{
|
{
|
||||||
|
$this->fileHandle = $fileHandle;
|
||||||
|
|
||||||
// Initial Setting for saving
|
// Initial Setting for saving
|
||||||
$this->bigBlockSize = pow(
|
$this->bigBlockSize = pow(
|
||||||
2,
|
2,
|
||||||
|
@ -97,23 +82,6 @@ class Root extends PPS
|
||||||
(isset($this->smallBlockSize)) ? self::adjust2($this->smallBlockSize) : 6
|
(isset($this->smallBlockSize)) ? self::adjust2($this->smallBlockSize) : 6
|
||||||
);
|
);
|
||||||
|
|
||||||
if (is_resource($filename)) {
|
|
||||||
$this->fileHandle = $filename;
|
|
||||||
} elseif ($filename == '-' || $filename == '') {
|
|
||||||
if ($this->tempDirectory === null) {
|
|
||||||
$this->tempDirectory = \PhpOffice\PhpSpreadsheet\Shared\File::sysGetTempDir();
|
|
||||||
}
|
|
||||||
$this->tempFilename = tempnam($this->tempDirectory, 'OLE_PPS_Root');
|
|
||||||
$this->fileHandle = fopen($this->tempFilename, 'w+b');
|
|
||||||
if ($this->fileHandle == false) {
|
|
||||||
throw new WriterException("Can't create temporary file.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->fileHandle = fopen($filename, 'wb');
|
|
||||||
}
|
|
||||||
if ($this->fileHandle == false) {
|
|
||||||
throw new WriterException("Can't open $filename. It may be in use or protected.");
|
|
||||||
}
|
|
||||||
// Make an array of PPS's (for Save)
|
// Make an array of PPS's (for Save)
|
||||||
$aList = [];
|
$aList = [];
|
||||||
PPS::_savePpsSetPnt($aList, [$this]);
|
PPS::_savePpsSetPnt($aList, [$this]);
|
||||||
|
@ -132,10 +100,6 @@ class Root extends PPS
|
||||||
// Write Big Block Depot and BDList and Adding Header informations
|
// Write Big Block Depot and BDList and Adding Header informations
|
||||||
$this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt);
|
$this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt);
|
||||||
|
|
||||||
if (!is_resource($filename)) {
|
|
||||||
fclose($this->fileHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,16 @@ abstract class BaseWriter implements IWriter
|
||||||
*/
|
*/
|
||||||
private $diskCachingDirectory = './';
|
private $diskCachingDirectory = './';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var resource
|
||||||
|
*/
|
||||||
|
protected $fileHandle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $shouldCloseFile;
|
||||||
|
|
||||||
public function getIncludeCharts()
|
public function getIncludeCharts()
|
||||||
{
|
{
|
||||||
return $this->includeCharts;
|
return $this->includeCharts;
|
||||||
|
@ -83,4 +93,39 @@ abstract class BaseWriter implements IWriter
|
||||||
{
|
{
|
||||||
return $this->diskCachingDirectory;
|
return $this->diskCachingDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open file handle.
|
||||||
|
*
|
||||||
|
* @param resource|string $filename
|
||||||
|
*/
|
||||||
|
public function openFileHandle($filename): void
|
||||||
|
{
|
||||||
|
if (is_resource($filename)) {
|
||||||
|
$this->fileHandle = $filename;
|
||||||
|
$this->shouldCloseFile = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileHandle = fopen($filename, 'wb+');
|
||||||
|
if ($fileHandle === false) {
|
||||||
|
throw new Exception('Could not open file ' . $filename . ' for writing.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->fileHandle = $fileHandle;
|
||||||
|
$this->shouldCloseFile = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close file handle only we opened it ourselves.
|
||||||
|
*/
|
||||||
|
protected function maybeCloseFileHandle(): void
|
||||||
|
{
|
||||||
|
if ($this->shouldCloseFile) {
|
||||||
|
if (!fclose($this->fileHandle)) {
|
||||||
|
throw new Exception('Could not close file after writing.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,11 +131,6 @@ class Csv extends BaseWriter
|
||||||
$this->writeLine($fileHandle, $cellsArray[0]);
|
$this->writeLine($fileHandle, $cellsArray[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close file
|
|
||||||
rewind($fileHandle);
|
|
||||||
|
|
||||||
fclose($fileHandle);
|
|
||||||
|
|
||||||
Calculation::setArrayReturnType($saveArrayReturnType);
|
Calculation::setArrayReturnType($saveArrayReturnType);
|
||||||
Calculation::getInstance($this->spreadsheet)->getDebugLog()->setWriteDebugLog($saveDebugLog);
|
Calculation::getInstance($this->spreadsheet)->getDebugLog()->setWriteDebugLog($saveDebugLog);
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,32 +164,23 @@ class Html extends BaseWriter
|
||||||
$this->buildCSS(!$this->useInlineCss);
|
$this->buildCSS(!$this->useInlineCss);
|
||||||
|
|
||||||
// Open file
|
// Open file
|
||||||
if (is_resource($pFilename)) {
|
$this->openFileHandle($pFilename);
|
||||||
$fileHandle = $pFilename;
|
|
||||||
} else {
|
|
||||||
$fileHandle = fopen($pFilename, 'wb+');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($fileHandle === false) {
|
|
||||||
throw new WriterException("Could not open file $pFilename for writing.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write headers
|
// Write headers
|
||||||
fwrite($fileHandle, $this->generateHTMLHeader(!$this->useInlineCss));
|
fwrite($this->fileHandle, $this->generateHTMLHeader(!$this->useInlineCss));
|
||||||
|
|
||||||
// Write navigation (tabs)
|
// Write navigation (tabs)
|
||||||
if ((!$this->isPdf) && ($this->generateSheetNavigationBlock)) {
|
if ((!$this->isPdf) && ($this->generateSheetNavigationBlock)) {
|
||||||
fwrite($fileHandle, $this->generateNavigation());
|
fwrite($this->fileHandle, $this->generateNavigation());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write data
|
// Write data
|
||||||
fwrite($fileHandle, $this->generateSheetData());
|
fwrite($this->fileHandle, $this->generateSheetData());
|
||||||
|
|
||||||
// Write footer
|
// Write footer
|
||||||
fwrite($fileHandle, $this->generateHTMLFooter());
|
fwrite($this->fileHandle, $this->generateHTMLFooter());
|
||||||
|
|
||||||
// Close file
|
$this->maybeCloseFileHandle();
|
||||||
fclose($fileHandle);
|
|
||||||
|
|
||||||
Calculation::setArrayReturnType($saveArrayReturnType);
|
Calculation::setArrayReturnType($saveArrayReturnType);
|
||||||
Calculation::getInstance($this->spreadsheet)->getDebugLog()->setWriteDebugLog($saveDebugLog);
|
Calculation::getInstance($this->spreadsheet)->getDebugLog()->setWriteDebugLog($saveDebugLog);
|
||||||
|
|
|
@ -32,11 +32,6 @@ class Ods extends BaseWriter
|
||||||
*/
|
*/
|
||||||
private $spreadSheet;
|
private $spreadSheet;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var resource
|
|
||||||
*/
|
|
||||||
private $fileHandle;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new Ods.
|
* Create a new Ods.
|
||||||
*
|
*
|
||||||
|
@ -93,25 +88,7 @@ class Ods extends BaseWriter
|
||||||
// garbage collect
|
// garbage collect
|
||||||
$this->spreadSheet->garbageCollect();
|
$this->spreadSheet->garbageCollect();
|
||||||
|
|
||||||
$originalFilename = $pFilename;
|
$this->openFileHandle($pFilename);
|
||||||
if (is_resource($pFilename)) {
|
|
||||||
$this->fileHandle = $pFilename;
|
|
||||||
} else {
|
|
||||||
// If $pFilename is php://output or php://stdout, make it a temporary file...
|
|
||||||
if (in_array(strtolower($pFilename), ['php://output', 'php://stdout'], true)) {
|
|
||||||
$pFilename = @tempnam(File::sysGetTempDir(), 'phpxltmp');
|
|
||||||
if ($pFilename === '') {
|
|
||||||
$pFilename = $originalFilename;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$fileHandle = fopen($pFilename, 'wb+');
|
|
||||||
if ($fileHandle === false) {
|
|
||||||
throw new WriterException('Could not open file ' . $pFilename . ' for writing.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->fileHandle = $fileHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
$zip = $this->createZip();
|
$zip = $this->createZip();
|
||||||
|
|
||||||
|
@ -130,23 +107,7 @@ class Ods extends BaseWriter
|
||||||
throw new WriterException('Could not close resource.');
|
throw new WriterException('Could not close resource.');
|
||||||
}
|
}
|
||||||
|
|
||||||
rewind($this->fileHandle);
|
$this->maybeCloseFileHandle();
|
||||||
|
|
||||||
// If a temporary file was used, copy it to the correct file stream
|
|
||||||
if ($originalFilename !== $pFilename) {
|
|
||||||
$destinationFileHandle = fopen($originalFilename, 'wb+');
|
|
||||||
if (!is_resource($destinationFileHandle)) {
|
|
||||||
throw new WriterException("Could not open resource $originalFilename for writing.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream_copy_to_stream($this->fileHandle, $destinationFileHandle) === false) {
|
|
||||||
throw new WriterException("Could not copy temporary zip file $pFilename to $originalFilename.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_string($pFilename) && !unlink($pFilename)) {
|
|
||||||
throw new WriterException('Could not unlink temporary zip file.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -255,17 +255,14 @@ abstract class Pdf extends Html
|
||||||
Calculation::setArrayReturnType(Calculation::RETURN_ARRAY_AS_VALUE);
|
Calculation::setArrayReturnType(Calculation::RETURN_ARRAY_AS_VALUE);
|
||||||
|
|
||||||
// Open file
|
// Open file
|
||||||
$fileHandle = fopen($pFilename, 'w');
|
$this->openFileHandle($pFilename);
|
||||||
if ($fileHandle === false) {
|
|
||||||
throw new WriterException("Could not open file $pFilename for writing.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set PDF
|
// Set PDF
|
||||||
$this->isPdf = true;
|
$this->isPdf = true;
|
||||||
// Build CSS
|
// Build CSS
|
||||||
$this->buildCSS(true);
|
$this->buildCSS(true);
|
||||||
|
|
||||||
return $fileHandle;
|
return $this->fileHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -275,8 +272,7 @@ abstract class Pdf extends Html
|
||||||
*/
|
*/
|
||||||
protected function restoreStateAfterSave($fileHandle)
|
protected function restoreStateAfterSave($fileHandle)
|
||||||
{
|
{
|
||||||
// Close file
|
$this->maybeCloseFileHandle();
|
||||||
fclose($fileHandle);
|
|
||||||
|
|
||||||
Calculation::setArrayReturnType($this->saveArrayReturnType);
|
Calculation::setArrayReturnType($this->saveArrayReturnType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ class Mpdf extends Pdf
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create PDF
|
// Create PDF
|
||||||
$config = ['tempDir' => $this->tempDir];
|
$config = ['tempDir' => $this->tempDir . '/mpdf'];
|
||||||
$pdf = $this->createExternalWriterInstance($config);
|
$pdf = $this->createExternalWriterInstance($config);
|
||||||
$ortmp = $orientation;
|
$ortmp = $orientation;
|
||||||
$pdf->_setPageSize(strtoupper($paperSize), $ortmp);
|
$pdf->_setPageSize(strtoupper($paperSize), $ortmp);
|
||||||
|
|
|
@ -221,7 +221,9 @@ class Xls extends BaseWriter
|
||||||
|
|
||||||
$root = new Root(time(), time(), $arrRootData);
|
$root = new Root(time(), time(), $arrRootData);
|
||||||
// save the OLE file
|
// save the OLE file
|
||||||
$root->save($pFilename);
|
$this->openFileHandle($pFilename);
|
||||||
|
$root->save($this->fileHandle);
|
||||||
|
$this->maybeCloseFileHandle();
|
||||||
|
|
||||||
Functions::setReturnDateType($saveDateReturnType);
|
Functions::setReturnDateType($saveDateReturnType);
|
||||||
Calculation::getInstance($this->spreadsheet)->getDebugLog()->setWriteDebugLog($saveDebugLog);
|
Calculation::getInstance($this->spreadsheet)->getDebugLog()->setWriteDebugLog($saveDebugLog);
|
||||||
|
|
|
@ -107,11 +107,6 @@ class Xlsx extends BaseWriter
|
||||||
*/
|
*/
|
||||||
private $drawingHashTable;
|
private $drawingHashTable;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var resource
|
|
||||||
*/
|
|
||||||
private $fileHandle;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new Xlsx Writer.
|
* Create a new Xlsx Writer.
|
||||||
*
|
*
|
||||||
|
@ -184,25 +179,7 @@ class Xlsx extends BaseWriter
|
||||||
// garbage collect
|
// garbage collect
|
||||||
$this->spreadSheet->garbageCollect();
|
$this->spreadSheet->garbageCollect();
|
||||||
|
|
||||||
$originalFilename = $pFilename;
|
$this->openFileHandle($pFilename);
|
||||||
if (is_resource($pFilename)) {
|
|
||||||
$this->fileHandle = $pFilename;
|
|
||||||
} else {
|
|
||||||
// If $pFilename is php://output or php://stdout, make it a temporary file...
|
|
||||||
if (in_array(strtolower($pFilename), ['php://output', 'php://stdout'], true)) {
|
|
||||||
$pFilename = @tempnam(File::sysGetTempDir(), 'phpxltmp');
|
|
||||||
if ($pFilename === '') {
|
|
||||||
$pFilename = $originalFilename;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$fileHandle = fopen($pFilename, 'wb+');
|
|
||||||
if ($fileHandle === false) {
|
|
||||||
throw new WriterException('Could not open file ' . $pFilename . ' for writing.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->fileHandle = $fileHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
$saveDebugLog = Calculation::getInstance($this->spreadSheet)->getDebugLog()->getWriteDebugLog();
|
$saveDebugLog = Calculation::getInstance($this->spreadSheet)->getDebugLog()->getWriteDebugLog();
|
||||||
Calculation::getInstance($this->spreadSheet)->getDebugLog()->setWriteDebugLog(false);
|
Calculation::getInstance($this->spreadSheet)->getDebugLog()->setWriteDebugLog(false);
|
||||||
|
@ -425,23 +402,7 @@ class Xlsx extends BaseWriter
|
||||||
throw new WriterException('Could not close resource.');
|
throw new WriterException('Could not close resource.');
|
||||||
}
|
}
|
||||||
|
|
||||||
rewind($this->fileHandle);
|
$this->maybeCloseFileHandle();
|
||||||
|
|
||||||
// If a temporary file was used, copy it to the correct file stream
|
|
||||||
if ($originalFilename !== $pFilename) {
|
|
||||||
$destinationFileHandle = fopen($originalFilename, 'wb+');
|
|
||||||
if (!is_resource($destinationFileHandle)) {
|
|
||||||
throw new WriterException("Could not open resource $originalFilename for writing.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream_copy_to_stream($this->fileHandle, $destinationFileHandle) === false) {
|
|
||||||
throw new WriterException("Could not copy temporary zip file $pFilename to $originalFilename.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_string($pFilename) && !unlink($pFilename)) {
|
|
||||||
throw new WriterException('Could not unlink temporary zip file.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw new WriterException('PhpSpreadsheet object unassigned.');
|
throw new WriterException('PhpSpreadsheet object unassigned.');
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Functional;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class StreamTest extends TestCase
|
||||||
|
{
|
||||||
|
public function providerFormats(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Xls'],
|
||||||
|
['Xlsx'],
|
||||||
|
['Ods'],
|
||||||
|
['Csv'],
|
||||||
|
['Html'],
|
||||||
|
['Tcpdf'],
|
||||||
|
['Dompdf'],
|
||||||
|
['Mpdf'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerFormats
|
||||||
|
*
|
||||||
|
* @param string $format
|
||||||
|
*/
|
||||||
|
public function testAllWritersCanWriteToStream(string $format): void
|
||||||
|
{
|
||||||
|
$spreadsheet = new Spreadsheet();
|
||||||
|
$spreadsheet->getActiveSheet()->setCellValue('A1', 'foo');
|
||||||
|
$writer = IOFactory::createWriter($spreadsheet, $format);
|
||||||
|
|
||||||
|
$stream = fopen('php://memory', 'wb+');
|
||||||
|
self::assertSame(0, fstat($stream)['size']);
|
||||||
|
|
||||||
|
$writer->save($stream);
|
||||||
|
|
||||||
|
self::assertIsResource($stream, 'should not close the stream for further usage out of PhpSpreadsheet');
|
||||||
|
self::assertGreaterThan(0, fstat($stream)['size'], 'something should have been written to the stream');
|
||||||
|
self::assertGreaterThan(0, ftell($stream), 'should not be rewinded, because not all streams support it');
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue