From 19ec1b5a60d9bd9dc4967fa4dd3402f4a2207453 Mon Sep 17 00:00:00 2001 From: Armin Preiml Date: Thu, 5 Oct 2023 09:09:25 +0200 Subject: [PATCH] change IReader functions to allow passing of resources --- src/PhpSpreadsheet/Reader/BaseReader.php | 34 +++++++---- src/PhpSpreadsheet/Reader/Csv.php | 29 +++++++--- src/PhpSpreadsheet/Reader/Gnumeric.php | 54 +++++++++++++----- src/PhpSpreadsheet/Reader/Html.php | 38 +++++++++---- src/PhpSpreadsheet/Reader/IReader.php | 8 ++- src/PhpSpreadsheet/Reader/Ods.php | 44 +++++++++++---- src/PhpSpreadsheet/Reader/Slk.php | 26 ++++++--- src/PhpSpreadsheet/Reader/Xls.php | 48 ++++++++++++---- src/PhpSpreadsheet/Reader/Xlsx.php | 56 +++++++++++++------ src/PhpSpreadsheet/Reader/Xml.php | 54 ++++++++++++------ .../PhpSpreadsheetTests/Reader/BaseNoLoad.php | 8 ++- 11 files changed, 287 insertions(+), 112 deletions(-) diff --git a/src/PhpSpreadsheet/Reader/BaseReader.php b/src/PhpSpreadsheet/Reader/BaseReader.php index b8e6a81a9b..ba34ab1d40 100644 --- a/src/PhpSpreadsheet/Reader/BaseReader.php +++ b/src/PhpSpreadsheet/Reader/BaseReader.php @@ -160,7 +160,10 @@ protected function processFlags(int $flags): void } } - protected function loadSpreadsheetFromFile(string $filename): Spreadsheet + /** + * @param string|resource $file + */ + protected function loadSpreadsheetFromFile($file): Spreadsheet { throw new PhpSpreadsheetException('Reader classes must implement their own loadSpreadsheetFromFile() method'); } @@ -168,16 +171,17 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet /** * Loads Spreadsheet from file. * + * @param string|resource $file * @param int $flags the optional second parameter flags may be used to identify specific elements * that should be loaded, but which won't be loaded by default, using these values: * IReader::LOAD_WITH_CHARTS - Include any charts that are defined in the loaded file */ - public function load(string $filename, int $flags = 0): Spreadsheet + public function load($file, int $flags = 0): Spreadsheet { $this->processFlags($flags); try { - return $this->loadSpreadsheetFromFile($filename); + return $this->loadSpreadsheetFromFile($file); } catch (ReaderException $e) { throw $e; } @@ -185,15 +189,21 @@ public function load(string $filename, int $flags = 0): Spreadsheet /** * Open file for reading. + * + * @param string|resource $file */ - protected function openFile(string $filename): void + protected function openFile($file): void { $fileHandle = false; - if ($filename) { - File::assertFile($filename); + if (is_string($file)) { + $filename = $file; + File::assertFile($file); // Open file - $fileHandle = fopen($filename, 'rb'); + $fileHandle = fopen($file, 'rb'); + } elseif (is_resource($file)) { + $filename = 'stream'; + $fileHandle = $file; } if ($fileHandle === false) { throw new ReaderException('Could not open file ' . $filename . ' for reading.'); @@ -204,8 +214,10 @@ protected function openFile(string $filename): void /** * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns). + * + * @param string|resource $file */ - public function listWorksheetInfo(string $filename): array + public function listWorksheetInfo($file): array { throw new PhpSpreadsheetException('Reader classes must implement their own listWorksheetInfo() method'); } @@ -215,11 +227,13 @@ public function listWorksheetInfo(string $filename): array * possibly without parsing the whole file to a Spreadsheet object. * Readers will often have a more efficient method with which * they can override this method. + * + * @param string|resource $file */ - public function listWorksheetNames(string $filename): array + public function listWorksheetNames($file): array { $returnArray = []; - $info = $this->listWorksheetInfo($filename); + $info = $this->listWorksheetInfo($file); foreach ($info as $infoArray) { if (isset($infoArray['worksheetName'])) { $returnArray[] = $infoArray['worksheetName']; diff --git a/src/PhpSpreadsheet/Reader/Csv.php b/src/PhpSpreadsheet/Reader/Csv.php index d5a565a55c..fb59d9ca81 100644 --- a/src/PhpSpreadsheet/Reader/Csv.php +++ b/src/PhpSpreadsheet/Reader/Csv.php @@ -216,11 +216,13 @@ protected function inferSeparator(): void /** * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns). + * + * @param string|resource $file */ - public function listWorksheetInfo(string $filename): array + public function listWorksheetInfo($file): array { // Open file - $this->openFileOrMemory($filename); + $this->openFileOrMemory($file); $fileHandle = $this->fileHandle; // Skip BOM, if any @@ -254,14 +256,16 @@ public function listWorksheetInfo(string $filename): array /** * Loads Spreadsheet from file. + * + * @param string|resource $file */ - protected function loadSpreadsheetFromFile(string $filename): Spreadsheet + protected function loadSpreadsheetFromFile($file): Spreadsheet { // Create new Spreadsheet $spreadsheet = new Spreadsheet(); // Load into this instance - return $this->loadIntoExisting($filename, $spreadsheet); + return $this->loadIntoExisting($file, $spreadsheet); } /** @@ -276,7 +280,10 @@ public function loadSpreadsheetFromString(string $contents): Spreadsheet return $this->loadStringOrFile('data://text/plain,' . urlencode($contents), $spreadsheet, true); } - private function openFileOrMemory(string $filename): void + /** + * @param string|resource $filename + */ + private function openFileOrMemory($filename): void { // Open file $fhandle = $this->canRead($filename); @@ -345,6 +352,8 @@ private function openDataUri(string $filename): void /** * Loads PhpSpreadsheet from file into PhpSpreadsheet instance. + * + * @param string|resource $file */ public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Spreadsheet { @@ -353,6 +362,8 @@ public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Sp /** * Loads PhpSpreadsheet from file into PhpSpreadsheet instance. + * + * @param string|resource $file */ private function loadStringOrFile(string $filename, Spreadsheet $spreadsheet, bool $dataUri): Spreadsheet { @@ -539,11 +550,11 @@ public function getEscapeCharacter(): string /** * Can the current IReader read the file? */ - public function canRead(string $filename): bool + public function canRead($file): bool { // Check if file exists try { - $this->openFile($filename); + $this->openFile($file); } catch (ReaderException) { return false; } @@ -551,13 +562,13 @@ public function canRead(string $filename): bool fclose($this->fileHandle); // Trust file extension if any - $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); + $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION)); if (in_array($extension, ['csv', 'tsv'])) { return true; } // Attempt to guess mimetype - $type = mime_content_type($filename); + $type = mime_content_type($file); $supportedTypes = [ 'application/csv', 'text/csv', diff --git a/src/PhpSpreadsheet/Reader/Gnumeric.php b/src/PhpSpreadsheet/Reader/Gnumeric.php index 729745f140..ebc4fcce6d 100644 --- a/src/PhpSpreadsheet/Reader/Gnumeric.php +++ b/src/PhpSpreadsheet/Reader/Gnumeric.php @@ -76,12 +76,18 @@ public function __construct() /** * Can the current IReader read the file? + * + * @param string|resource $file */ - public function canRead(string $filename): bool + public function canRead($file): bool { + if (is_resource($file)) { + return false; // TODO + } + $data = null; - if (File::testFileNoThrow($filename)) { - $data = $this->gzfileGetContents($filename); + if (File::testFileNoThrow($file)) { + $data = $this->gzfileGetContents($file); if (!str_contains($data, self::NAMESPACE_GNM)) { $data = ''; } @@ -99,16 +105,22 @@ private static function matchXml(XMLReader $xml, string $expectedLocalName): boo /** * Reads names of the worksheets from a file, without parsing the whole file to a Spreadsheet object. + * + * @param string|resource $file */ - public function listWorksheetNames(string $filename): array + public function listWorksheetNames($file): array { - File::assertFile($filename); - if (!$this->canRead($filename)) { - throw new Exception($filename . ' is an invalid Gnumeric file.'); + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + + File::assertFile($file); + if (!$this->canRead($file)) { + throw new Exception($file . ' is an invalid Gnumeric file.'); } $xml = new XMLReader(); - $contents = $this->gzfileGetContents($filename); + $contents = $this->gzfileGetContents($file); $xml->xml($contents, null, Settings::getLibXmlLoaderOptions()); $xml->setParserProperty(2, true); @@ -128,16 +140,22 @@ public function listWorksheetNames(string $filename): array /** * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns). + * + * @param string|resource $file */ - public function listWorksheetInfo(string $filename): array + public function listWorksheetInfo($file): array { - File::assertFile($filename); - if (!$this->canRead($filename)) { - throw new Exception($filename . ' is an invalid Gnumeric file.'); + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + + File::assertFile($file); + if (!$this->canRead($file)) { + throw new Exception($file . ' is an invalid Gnumeric file.'); } $xml = new XMLReader(); - $contents = $this->gzfileGetContents($filename); + $contents = $this->gzfileGetContents($file); $xml->xml($contents, null, Settings::getLibXmlLoaderOptions()); $xml->setParserProperty(2, true); @@ -229,15 +247,21 @@ private static function testSimpleXml(mixed $value): SimpleXMLElement /** * Loads Spreadsheet from file. + * + * @param string|resource $file */ - protected function loadSpreadsheetFromFile(string $filename): Spreadsheet + protected function loadSpreadsheetFromFile($file): Spreadsheet { + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + // Create new Spreadsheet $spreadsheet = new Spreadsheet(); $spreadsheet->removeSheetByIndex(0); // Load into this instance - return $this->loadIntoExisting($filename, $spreadsheet); + return $this->loadIntoExisting($file, $spreadsheet); } /** diff --git a/src/PhpSpreadsheet/Reader/Html.php b/src/PhpSpreadsheet/Reader/Html.php index 6fcf31d7da..7e075d1b46 100644 --- a/src/PhpSpreadsheet/Reader/Html.php +++ b/src/PhpSpreadsheet/Reader/Html.php @@ -138,12 +138,14 @@ public function __construct() /** * Validate that the current file is an HTML file. + * + * @param string|resource $file */ - public function canRead(string $filename): bool + public function canRead($file): bool { // Check if file exists try { - $this->openFile($filename); + $this->openFile($file); } catch (Exception) { return false; } @@ -202,14 +204,16 @@ private static function containsTags(string $data): bool /** * Loads Spreadsheet from file. + * + * @param string|resource $file */ - public function loadSpreadsheetFromFile(string $filename): Spreadsheet + public function loadSpreadsheetFromFile($file): Spreadsheet { // Create new Spreadsheet $spreadsheet = new Spreadsheet(); // Load into this instance - return $this->loadIntoExisting($filename, $spreadsheet); + return $this->loadIntoExisting($file, $spreadsheet); } /** @@ -661,12 +665,18 @@ protected function processDomElement(DOMNode $element, Worksheet $sheet, int &$r /** * Loads PhpSpreadsheet from file into PhpSpreadsheet instance. + * + * @param string|resource $file */ - public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Spreadsheet + public function loadIntoExisting($file, Spreadsheet $spreadsheet): Spreadsheet { + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + // Validate - if (!$this->canRead($filename)) { - throw new Exception($filename . ' is an Invalid HTML file.'); + if (!$this->canRead($file)) { + throw new Exception($file . ' is an Invalid HTML file.'); } // Create a new DOM object @@ -674,7 +684,7 @@ public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Sp // Reload the HTML file into the DOM object try { - $convert = $this->getSecurityScannerOrThrow()->scanFile($filename); + $convert = $this->getSecurityScannerOrThrow()->scanFile($file); $lowend = "\u{80}"; $highend = "\u{10ffff}"; $regexp = "/[$lowend-$highend]/u"; @@ -686,7 +696,7 @@ public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Sp $loaded = false; } if ($loaded === false) { - throw new Exception('Failed to load ' . $filename . ' as a DOM Document', 0, $e ?? null); + throw new Exception('Failed to load ' . $file . ' as a DOM Document', 0, $e ?? null); } self::loadProperties($dom, $spreadsheet); @@ -1152,12 +1162,18 @@ private function setBorderStyle(Style $cellStyle, string $styleValue, string $ty /** * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns). + * + * @param string|resource $file */ - public function listWorksheetInfo(string $filename): array + public function listWorksheetInfo($file): array { + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + $info = []; $spreadsheet = new Spreadsheet(); - $this->loadIntoExisting($filename, $spreadsheet); + $this->loadIntoExisting($file, $spreadsheet); foreach ($spreadsheet->getAllSheets() as $sheet) { $newEntry = ['worksheetName' => $sheet->getTitle()]; $newEntry['lastColumnLetter'] = $sheet->getHighestDataColumn(); diff --git a/src/PhpSpreadsheet/Reader/IReader.php b/src/PhpSpreadsheet/Reader/IReader.php index dadf36ff90..7fc3f19cce 100644 --- a/src/PhpSpreadsheet/Reader/IReader.php +++ b/src/PhpSpreadsheet/Reader/IReader.php @@ -20,8 +20,10 @@ public function __construct(); /** * Can the current IReader read the file? + * + * @param string|resource $file */ - public function canRead(string $filename): bool; + public function canRead($file): bool; /** * Read data only? @@ -132,7 +134,7 @@ public function setReadFilter(IReadFilter $readFilter); /** * Loads PhpSpreadsheet from file. * - * @param string $filename The name of the file to load + * @param string|resource $file A resource or the name of the file to load * @param int $flags Flags that can change the behaviour of the Writer: * self::LOAD_WITH_CHARTS Load any charts that are defined (if the Reader supports Charts) * self::READ_DATA_ONLY Read only data, not style or structure information, from the file @@ -141,5 +143,5 @@ public function setReadFilter(IReadFilter $readFilter); * * @return Spreadsheet */ - public function load(string $filename, int $flags = 0); + public function load($file, int $flags = 0); } diff --git a/src/PhpSpreadsheet/Reader/Ods.php b/src/PhpSpreadsheet/Reader/Ods.php index ceb345dc3f..4d69e7b48e 100644 --- a/src/PhpSpreadsheet/Reader/Ods.php +++ b/src/PhpSpreadsheet/Reader/Ods.php @@ -41,16 +41,22 @@ public function __construct() /** * Can the current IReader read the file? + * + * @param string|resource $file */ - public function canRead(string $filename): bool + public function canRead($file): bool { + if (is_resource($file)) { + return false; // TODO + } + $mimeType = 'UNKNOWN'; // Load file - if (File::testFileNoThrow($filename, '')) { + if (File::testFileNoThrow($file, '')) { $zip = new ZipArchive(); - if ($zip->open($filename) === true) { + if ($zip->open($file) === true) { // check if it is an OOXML archive $stat = $zip->statName('mimetype'); if (!empty($stat) && ($stat['size'] <= 255)) { @@ -87,17 +93,21 @@ public function canRead(string $filename): bool /** * Reads names of the worksheets from a file, without parsing the whole file to a PhpSpreadsheet object. * + * @param string|resource $file * @return string[] */ - public function listWorksheetNames(string $filename): array + public function listWorksheetNames($file): array { - File::assertFile($filename, self::INITIAL_FILE); + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + File::assertFile($file, self::INITIAL_FILE); $worksheetNames = []; $xml = new XMLReader(); $xml->xml( - $this->getSecurityScannerOrThrow()->scanFile('zip://' . realpath($filename) . '#' . self::INITIAL_FILE), + $this->getSecurityScannerOrThrow()->scanFile('zip://' . realpath($file) . '#' . self::INITIAL_FILE), null, Settings::getLibXmlLoaderOptions() ); @@ -135,16 +145,22 @@ public function listWorksheetNames(string $filename): array /** * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns). + * + * @param string|resource $file */ - public function listWorksheetInfo(string $filename): array + public function listWorksheetInfo($file): array { - File::assertFile($filename, self::INITIAL_FILE); + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + + File::assertFile($file, self::INITIAL_FILE); $worksheetInfo = []; $xml = new XMLReader(); $xml->xml( - $this->getSecurityScannerOrThrow()->scanFile('zip://' . realpath($filename) . '#' . self::INITIAL_FILE), + $this->getSecurityScannerOrThrow()->scanFile('zip://' . realpath($file) . '#' . self::INITIAL_FILE), null, Settings::getLibXmlLoaderOptions() ); @@ -228,15 +244,21 @@ private static function getXmlName(XMLReader $xml): string /** * Loads PhpSpreadsheet from file. + * + * @param string|resource $file */ - protected function loadSpreadsheetFromFile(string $filename): Spreadsheet + protected function loadSpreadsheetFromFile($file): Spreadsheet { + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + // Create new Spreadsheet $spreadsheet = new Spreadsheet(); $spreadsheet->removeSheetByIndex(0); // Load into this instance - return $this->loadIntoExisting($filename, $spreadsheet); + return $this->loadIntoExisting($file, $spreadsheet); } /** diff --git a/src/PhpSpreadsheet/Reader/Slk.php b/src/PhpSpreadsheet/Reader/Slk.php index 3b026fe277..314195a0a8 100644 --- a/src/PhpSpreadsheet/Reader/Slk.php +++ b/src/PhpSpreadsheet/Reader/Slk.php @@ -65,11 +65,13 @@ public function __construct() /** * Validate that the current file is a SYLK file. + * + * @param string|resource $file */ - public function canRead(string $filename): bool + public function canRead($file): bool { try { - $this->openFile($filename); + $this->openFile($file); } catch (ReaderException) { return false; } @@ -133,15 +135,19 @@ public function getInputEncoding() /** * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns). */ - public function listWorksheetInfo(string $filename): array + public function listWorksheetInfo($file): array { + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + // Open file - $this->canReadOrBust($filename); + $this->canReadOrBust($file); $fileHandle = $this->fileHandle; rewind($fileHandle); $worksheetInfo = []; - $worksheetInfo[0]['worksheetName'] = basename($filename, '.slk'); + $worksheetInfo[0]['worksheetName'] = basename($file, '.slk'); // loop through one row (line) at a time in the file $rowIndex = 0; @@ -188,14 +194,20 @@ public function listWorksheetInfo(string $filename): array /** * Loads PhpSpreadsheet from file. + * + * @param string|resource $file */ - protected function loadSpreadsheetFromFile(string $filename): Spreadsheet + protected function loadSpreadsheetFromFile($file): Spreadsheet { + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + // Create new Spreadsheet $spreadsheet = new Spreadsheet(); // Load into this instance - return $this->loadIntoExisting($filename, $spreadsheet); + return $this->loadIntoExisting($file, $spreadsheet); } private const COLOR_ARRAY = [ diff --git a/src/PhpSpreadsheet/Reader/Xls.php b/src/PhpSpreadsheet/Reader/Xls.php index 4b4a8e4844..376f5e41d5 100644 --- a/src/PhpSpreadsheet/Reader/Xls.php +++ b/src/PhpSpreadsheet/Reader/Xls.php @@ -428,10 +428,16 @@ public function __construct() /** * Can the current IReader read the file? + * + * @param string|resource $file */ - public function canRead(string $filename): bool + public function canRead($file): bool { - if (File::testFileNoThrow($filename) === false) { + if (is_resource($file)) { + return false; // TODO + } + + if (File::testFileNoThrow($file) === false) { return false; } @@ -440,9 +446,9 @@ public function canRead(string $filename): bool $ole = new OLERead(); // get excel data - $ole->read($filename); + $ole->read($file); if ($ole->wrkbook === null) { - throw new Exception('The filename ' . $filename . ' is not recognised as a Spreadsheet file'); + throw new Exception('The filename ' . $file . ' is not recognised as a Spreadsheet file'); } return true; @@ -467,15 +473,21 @@ public function getCodepage(): string /** * Reads names of the worksheets from a file, without parsing the whole file to a PhpSpreadsheet object. + * + * @param string|resource $file */ - public function listWorksheetNames(string $filename): array + public function listWorksheetNames($file): array { - File::assertFile($filename); + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + + File::assertFile($file); $worksheetNames = []; // Read the OLE file - $this->loadOLE($filename); + $this->loadOLE($file); // total byte size of Excel data (workbook global substream + sheet substreams) $this->dataSize = strlen($this->data); @@ -514,15 +526,21 @@ public function listWorksheetNames(string $filename): array /** * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns). + * + * @param string|resource $file */ - public function listWorksheetInfo(string $filename): array + public function listWorksheetInfo($file): array { - File::assertFile($filename); + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + + File::assertFile($file); $worksheetInfo = []; // Read the OLE file - $this->loadOLE($filename); + $this->loadOLE($file); // total byte size of Excel data (workbook global substream + sheet substreams) $this->dataSize = strlen($this->data); @@ -615,11 +633,17 @@ public function listWorksheetInfo(string $filename): array /** * Loads PhpSpreadsheet from file. + * + * @param string|resource $file */ - protected function loadSpreadsheetFromFile(string $filename): Spreadsheet + protected function loadSpreadsheetFromFile($file): Spreadsheet { + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + // Read the OLE file - $this->loadOLE($filename); + $this->loadOLE($file); // Initialisations $this->spreadsheet = new Spreadsheet(); diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index 3c2b4f244a..99737cc838 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -77,17 +77,23 @@ public function __construct() /** * Can the current IReader read the file? + * + * @param string|resource $file */ - public function canRead(string $filename): bool + public function canRead($file): bool { - if (!File::testFileNoThrow($filename, self::INITIAL_FILE)) { + if (is_resource($file)) { + return false; // TODO + } + + if (!File::testFileNoThrow($file, self::INITIAL_FILE)) { return false; } $result = false; $this->zip = $zip = new ZipArchive(); - if ($zip->open($filename) === true) { + if ($zip->open($file) === true) { [$workbookBasename] = $this->getWorkbookBaseName(); $result = !empty($workbookBasename); @@ -164,15 +170,21 @@ private function loadZipNonamespace(string $filename, string $ns): SimpleXMLElem /** * Reads names of the worksheets from a file, without parsing the whole file to a Spreadsheet object. + * + * @param string|resource $file */ - public function listWorksheetNames(string $filename): array + public function listWorksheetNames($file): array { - File::assertFile($filename, self::INITIAL_FILE); + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + + File::assertFile($file, self::INITIAL_FILE); $worksheetNames = []; $this->zip = $zip = new ZipArchive(); - $zip->open($filename); + $zip->open($file); // The files we're looking at here are small enough that simpleXML is more efficient than XMLReader $rels = $this->loadZip(self::INITIAL_FILE, Namespaces::RELATIONSHIPS); @@ -199,15 +211,21 @@ public function listWorksheetNames(string $filename): array /** * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns). + * + * @param string|resource $file */ - public function listWorksheetInfo(string $filename): array + public function listWorksheetInfo($file): array { - File::assertFile($filename, self::INITIAL_FILE); + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + + File::assertFile($file, self::INITIAL_FILE); $worksheetInfo = []; $this->zip = $zip = new ZipArchive(); - $zip->open($filename); + $zip->open($file); $rels = $this->loadZip(self::INITIAL_FILE, Namespaces::RELATIONSHIPS); foreach ($rels->Relationship as $relx) { @@ -396,10 +414,16 @@ private function getFromZipArchive(ZipArchive $archive, $fileName = '') /** * Loads Spreadsheet from file. + * + * @param string|resource $file */ - protected function loadSpreadsheetFromFile(string $filename): Spreadsheet + protected function loadSpreadsheetFromFile($file): Spreadsheet { - File::assertFile($filename, self::INITIAL_FILE); + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + + File::assertFile($file, self::INITIAL_FILE); // Initialisations $excel = new Spreadsheet(); @@ -410,7 +434,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet $unparsedLoadedData = []; $this->zip = $zip = new ZipArchive(); - $zip->open($filename); + $zip->open($file); // Read the theme first, because we need the colour scheme when reading the styles [$workbookBasename, $xmlNamespaceBase] = $this->getWorkbookBaseName(); @@ -1182,7 +1206,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet $objDrawing->setName($fillImageTitle); $imagePath = str_replace(['../', '/xl/'], 'xl/', $drowingImages[$fillImageRelId]); $objDrawing->setPath( - 'zip://' . File::realpath($filename) . '#' . $imagePath, + 'zip://' . File::realpath($file) . '#' . $imagePath, true, $zip ); @@ -1287,7 +1311,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet $hfImages[$shapeId]->setName((string) $imageData['title']); } - $hfImages[$shapeId]->setPath('zip://' . File::realpath($filename) . '#' . $drawings[(string) $imageData['relid']], false); + $hfImages[$shapeId]->setPath('zip://' . File::realpath($file) . '#' . $drawings[(string) $imageData['relid']], false); $hfImages[$shapeId]->setResizeProportional(false); $hfImages[$shapeId]->setWidth($style['width']); $hfImages[$shapeId]->setHeight($style['height']); @@ -1397,7 +1421,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet ); if (isset($images[$embedImageKey])) { $objDrawing->setPath( - 'zip://' . File::realpath($filename) . '#' + 'zip://' . File::realpath($file) . '#' . $images[$embedImageKey], false ); @@ -1484,7 +1508,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet ); if (isset($images[$embedImageKey])) { $objDrawing->setPath( - 'zip://' . File::realpath($filename) . '#' + 'zip://' . File::realpath($file) . '#' . $images[$embedImageKey], false ); diff --git a/src/PhpSpreadsheet/Reader/Xml.php b/src/PhpSpreadsheet/Reader/Xml.php index 09baf33214..f62f8cec3a 100644 --- a/src/PhpSpreadsheet/Reader/Xml.php +++ b/src/PhpSpreadsheet/Reader/Xml.php @@ -59,8 +59,12 @@ public static function xmlMappings(): array /** * Can the current IReader read the file? */ - public function canRead(string $filename): bool + public function canRead($file): bool { + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + // Office xmlns:o="urn:schemas-microsoft-com:office:office" // Excel xmlns:x="urn:schemas-microsoft-com:office:excel" // XML Spreadsheet xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" @@ -77,7 +81,7 @@ public function canRead(string $filename): bool ]; // Open file - $data = file_get_contents($filename) ?: ''; + $data = file_get_contents($file) ?: ''; // Why? //$data = str_replace("'", '"', $data); // fix headers with single quote @@ -128,19 +132,25 @@ public function trySimpleXMLLoadString(string $filename): SimpleXMLElement|bool /** * Reads names of the worksheets from a file, without parsing the whole file to a Spreadsheet object. + * + * @param string|resource $file */ - public function listWorksheetNames(string $filename): array + public function listWorksheetNames($file): array { - File::assertFile($filename); - if (!$this->canRead($filename)) { - throw new Exception($filename . ' is an Invalid Spreadsheet file.'); + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + + File::assertFile($file); + if (!$this->canRead($file)) { + throw new Exception($file . ' is an Invalid Spreadsheet file.'); } $worksheetNames = []; - $xml = $this->trySimpleXMLLoadString($filename); + $xml = $this->trySimpleXMLLoadString($file); if ($xml === false) { - throw new Exception("Problem reading {$filename}"); + throw new Exception("Problem reading {$file}"); } $xml_ss = $xml->children(self::NAMESPACES_SS); @@ -154,19 +164,25 @@ public function listWorksheetNames(string $filename): array /** * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns). + * + * @param string|resource $file */ - public function listWorksheetInfo(string $filename): array + public function listWorksheetInfo($file): array { - File::assertFile($filename); - if (!$this->canRead($filename)) { - throw new Exception($filename . ' is an Invalid Spreadsheet file.'); + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + + File::assertFile($file); + if (!$this->canRead($file)) { + throw new Exception($file . ' is an Invalid Spreadsheet file.'); } $worksheetInfo = []; - $xml = $this->trySimpleXMLLoadString($filename); + $xml = $this->trySimpleXMLLoadString($file); if ($xml === false) { - throw new Exception("Problem reading {$filename}"); + throw new Exception("Problem reading {$file}"); } $worksheetID = 1; @@ -235,15 +251,21 @@ public function loadSpreadsheetFromString(string $contents): Spreadsheet /** * Loads Spreadsheet from file. + * + * @param string|resource $file */ - protected function loadSpreadsheetFromFile(string $filename): Spreadsheet + protected function loadSpreadsheetFromFile($file): Spreadsheet { + if (is_resource($file)) { + throw new Exception('file as stream not supported'); + } + // Create new Spreadsheet $spreadsheet = new Spreadsheet(); $spreadsheet->removeSheetByIndex(0); // Load into this instance - return $this->loadIntoExisting($filename, $spreadsheet); + return $this->loadIntoExisting($file, $spreadsheet); } /** diff --git a/tests/PhpSpreadsheetTests/Reader/BaseNoLoad.php b/tests/PhpSpreadsheetTests/Reader/BaseNoLoad.php index 1673f2c95b..f52990367a 100644 --- a/tests/PhpSpreadsheetTests/Reader/BaseNoLoad.php +++ b/tests/PhpSpreadsheetTests/Reader/BaseNoLoad.php @@ -8,8 +8,12 @@ class BaseNoLoad extends BaseReader { - public function canRead(string $filename): bool + /** + * @param string|resource $file + * @return bool + */ + public function canRead($file): bool { - return $filename !== ''; + return is_string($file) && $file !== ''; } }