Compare commits

...
34 Commits
Author SHA1 Message Date
Adrien Loison 3edb056286 Merge pull request #60 from Lewiscowles1986/Update-XLSX-Reader
Separated getCellValue into multiple functions
2015-07-06 10:12:35 -07:00
Lewis Cowles edc0c22009 Update XLSX.php 2015-07-06 12:10:41 +01:00
Adrien Loison 0319e578cb Update README.md 2015-07-02 16:19:55 -07:00
Lewis 1e2452934c Additional tests for Cell Types 2015-07-02 19:35:23 +01:00
Lewis 3e1793d852 Changes made to XLSX.php 2015-07-02 17:56:55 +01:00
Lewis Cowles c1b1bd0b76 Separated getCellValue into multiple functions
Author:    Lewis Cowles <lewiscowles@me.com>
Committer: Lewis <lewis@chromebook>
	modified:   src/Spout/Reader/XLSX.php
2015-07-02 17:41:00 +01:00
Adrien Loison cf239905d7 Merge pull request #61 from box/coveralls_support
Adding coveralls.io support
2015-07-01 16:20:46 -07:00
Adrien Loison 7c8f9293cc Adding coveralls.io support
Updated TravisCI config, using:
- http://docs.travis-ci.com/user/languages/php/
- https://github.com/satooshi/php-coveralls#travis-ci

Removed automatic code coverage execution when running phpunit
Added coveralls.io badge
2015-07-01 16:15:58 -07:00
Adrien Loison 503ba97e9d Merge pull request #59 from box/fix_xlsx_writer_on_windows
Fix XLSX Writer on Windows plaftorms
2015-07-01 15:29:10 -07:00
Adrien Loison b3df57d2e5 Fix XLSX Writer on Windows plaftorms
A bug was introduced, preventing Spout to create valid XLSX files on Windows.
This commits reverts the changes that introduced DIRECTORY_SEPARATOR everywhere
and fixes the original issue with the writer by normalizing paths when creating
the zipped file.
2015-07-01 15:24:58 -07:00
Adrien Loison c6ebf115fc Merge pull request #58 from box/improve_xml_security
Prevent entity loading when reading XML
2015-07-01 14:19:49 -07:00
Adrien Loison 7d922e6776 Prevent entity loading when reading XML
Added LIBXML_NOENT option when reading a XML file
libxml_disable_entity_loader(true) cannot be used because it disables
the use of XMLReader::open()... see https://bugs.php.net/bug.php?id=62577
2015-07-01 14:07:15 -07:00
Adrien Loison d4cf853270 Merge pull request #48 from box/add_support_for_more_cell_types
Add support for more cell types
2015-06-03 11:24:43 -07:00
Adrien Loison 8bac924d48 Add support for more cell types
Added proper support for booleans, dates, numbers, errors.
Added unescaping of the read string.
Fixed a bug when cells did not have any values => now returns empty string.
2015-06-03 11:19:21 -07:00
Adrien Loison 591d86cf07 Merge pull request #46 from box/remove_version_from_composer_json
Remove version from composer.json
2015-06-02 21:47:09 -07:00
Adrien Loison ba4a55292d Remove version from composer.json 2015-06-02 19:48:37 -07:00
Adrien Loison d617a50b85 Merge pull request #44 from box/bump_to_v1.0.9
Bump to version 1.0.9
2015-05-29 09:50:21 -07:00
Adrien Loison 92981fa80b Bump to version 1.0.9 2015-05-29 09:42:38 -07:00
Adrien Loison 766c733466 Update README.md
Added question about charts and formulas in the FAQ
2015-05-29 09:39:36 -07:00
Adrien Loison 46cae76546 Update README.md
Added new badges
2015-05-29 09:30:40 -07:00
Adrien Loison 03be58b84d Merge pull request #43 from box/support_files_with_formulas
Add support for files containing formulas
2015-05-29 09:08:48 -07:00
Adrien Loison b21bb86682 Add support for files containing formulas
Formulas will be skipped on reading.
The result of the formulas will be kept though.
2015-05-29 09:01:28 -07:00
Adrien Loison 8a45cec220 Merge pull request #42 from box/support_files_without_shared_strings
Support XLSX that don't have a sharedStrings.xml file
2015-05-28 18:06:09 -07:00
Adrien Loison 04d41d7c9f Support XLSX that don't have a sharedStrings.xml file 2015-05-28 17:59:30 -07:00
Adrien Loison f8f194bc8f Merge pull request #37 from box/bump_to_version_1.0.8
Bump to version 1.0.8
2015-05-12 21:13:03 -07:00
Adrien Loison 044ad11596 Bump to version 1.0.8 2015-05-12 21:09:22 -07:00
Adrien Loison 935ba1fb5e Merge pull request #36 from box/fix_zip_path_windows
Fix issue with directory separators for zip:// on Windows
2015-05-12 21:08:38 -07:00
Adrien Loison fb0175d633 Fix issue with directory separators for zip:// on Windows
Replaced "/" by DIRECTORY_SEPARATOR every time it was used with zip://
2015-05-12 20:51:57 -07:00
Adrien Loison 69190cd855 Merge pull request #34 from box/bump_version_to_1.0.7
Bump version to 1.0.7
2015-04-29 13:53:38 -07:00
Adrien Loison 13a53fb43f Bump version to 1.0.7 2015-04-29 11:56:25 -07:00
Adrien Loison a848be52de Merge pull request #33 from box/improve_code_coverage
Improve code coverage
2015-04-29 11:55:37 -07:00
Adrien Loison 52faef0168 Merge pull request #32 from box/rename_number_to_index
Rename *Number to *Index
2015-04-29 11:55:26 -07:00
Adrien Loison 3b4dfba38e Improve code coverage 2015-04-29 11:39:21 -07:00
Adrien Loison cfd3e0ffa3 Rename *Number to *Index 2015-04-29 10:48:31 -07:00
25 changed files with 462 additions and 151 deletions

No files matched your search

+7 -3
View File
@@ -8,7 +8,11 @@ php:
- hhvm - hhvm
install: install:
- composer self-update - composer install --no-interaction
- composer install --prefer-source
script: phpunit script:
- mkdir -p build/logs
- php vendor/bin/phpunit --coverage-clover build/logs/clover.xml
after_script:
- php vendor/bin/coveralls -v
+12 -3
View File
@@ -1,11 +1,15 @@
# Spout # Spout
[![Latest Stable Version](https://poser.pugx.org/box/spout/v/stable)](https://packagist.org/packages/box/spout)
[![Project Status](http://opensource.box.com/badges/active.svg)](http://opensource.box.com/badges)
[![Build Status](https://travis-ci.org/box/spout.png?branch=master)](http://travis-ci.org/box/spout)
[![Coverage Status](https://coveralls.io/repos/box/spout/badge.svg?branch=master)](https://coveralls.io/r/box/spout?branch=master)
[![Total Downloads](https://poser.pugx.org/box/spout/downloads)](https://packagist.org/packages/box/spout)
[![License](https://poser.pugx.org/box/spout/license)](https://packagist.org/packages/box/spout)
Spout is a PHP library to read and write CSV and XLSX files, in a fast and scalable way. Spout is a PHP library to read and write CSV and XLSX files, in a fast and scalable way.
Contrary to other file readers or writers, it is capable of processing very large files while keeping the memory usage really low (less than 10MB). Contrary to other file readers or writers, it is capable of processing very large files while keeping the memory usage really low (less than 10MB).
[![Build Status](https://travis-ci.org/box/spout.png?branch=master)](http://travis-ci.org/box/spout)
[![Project Status](http://opensource.box.com/badges/active.svg)](http://opensource.box.com/badges)
## Installation ## Installation
@@ -248,6 +252,11 @@ Here are a few numbers regarding the performance of Spout:
| Read XLSX (using shared strings) | 1 second | 1-2 minutes | 35-40 minutes | | Read XLSX (using shared strings) | 1 second | 1-2 minutes | 35-40 minutes |
| Write XLSX | 1 second | 20-25 seconds | 8-10 minutes | | Write XLSX | 1 second | 20-25 seconds | 8-10 minutes |
#### Does Spout support charts or formulas?
No. This is a compromise to keep memory usage low. Charts and formulas requires data to be kept in memory in order to be used.
So the larger the file would be, the more memory would be consumed, preventing your code to scale well.
## Support ## Support
+2 -2
View File
@@ -2,7 +2,6 @@
"name": "box/spout", "name": "box/spout",
"description": "PHP Library to read and write CSV and XLSX files, in a fast and scalable way", "description": "PHP Library to read and write CSV and XLSX files, in a fast and scalable way",
"type": "library", "type": "library",
"version": "1.0.6",
"keywords": ["php","read","write","csv","xlsx","excel","spreadsheet","scale","memory","stream","ooxml"], "keywords": ["php","read","write","csv","xlsx","excel","spreadsheet","scale","memory","stream","ooxml"],
"license": "Apache-2.0", "license": "Apache-2.0",
"homepage": "https://www.github.com/box/spout", "homepage": "https://www.github.com/box/spout",
@@ -19,7 +18,8 @@
"ext-simplexml": "*" "ext-simplexml": "*"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": ">=3.7" "phpunit/phpunit": ">=3.7",
"satooshi/php-coveralls": "^0.6.1"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
-4
View File
@@ -14,10 +14,6 @@
</testsuite> </testsuite>
</testsuites> </testsuites>
<logging>
<log type="coverage-html" target="tests/coverage/"/>
</logging>
<filter> <filter>
<whitelist> <whitelist>
<directory suffix=".php">src/</directory> <directory suffix=".php">src/</directory>
+2 -2
View File
@@ -36,7 +36,7 @@ class FileSystemHelper
{ {
$this->throwIfOperationNotInBaseFolder($parentFolderPath); $this->throwIfOperationNotInBaseFolder($parentFolderPath);
$folderPath = $parentFolderPath . DIRECTORY_SEPARATOR . $folderName; $folderPath = $parentFolderPath . '/' . $folderName;
$wasCreationSuccessful = mkdir($folderPath, 0777, true); $wasCreationSuccessful = mkdir($folderPath, 0777, true);
if (!$wasCreationSuccessful) { if (!$wasCreationSuccessful) {
@@ -60,7 +60,7 @@ class FileSystemHelper
{ {
$this->throwIfOperationNotInBaseFolder($parentFolderPath); $this->throwIfOperationNotInBaseFolder($parentFolderPath);
$filePath = $parentFolderPath . DIRECTORY_SEPARATOR . $fileName; $filePath = $parentFolderPath . '/' . $fileName;
$wasCreationSuccessful = file_put_contents($filePath, $fileContents); $wasCreationSuccessful = file_put_contents($filePath, $fileContents);
if (!$wasCreationSuccessful) { if (!$wasCreationSuccessful) {
@@ -91,6 +91,21 @@ class GlobalFunctionsHelper
return fgetcsv($handle, $length, $delimiter, $enclosure); return fgetcsv($handle, $length, $delimiter, $enclosure);
} }
/**
* Wrapper around global function fputcsv()
* @see fputcsv()
*
* @param resource $handle
* @param array $fields
* @param string|void $delimiter
* @param string|void $enclosure
* @return int
*/
public function fputcsv($handle, array $fields, $delimiter = null, $enclosure = null)
{
return fputcsv($handle, $fields, $delimiter, $enclosure);
}
/** /**
* Wrapper around global function fclose() * Wrapper around global function fclose()
* @see fclose() * @see fclose()
+1 -1
View File
@@ -14,7 +14,7 @@ use Box\Spout\Reader\Exception\EndOfFileReachedException;
*/ */
abstract class AbstractReader implements ReaderInterface abstract class AbstractReader implements ReaderInterface
{ {
/** @var int Used to keep track of the row number */ /** @var int Used to keep track of the row index */
protected $currentRowIndex = 0; protected $currentRowIndex = 0;
/** @var bool Indicates whether the stream is currently open */ /** @var bool Indicates whether the stream is currently open */
@@ -71,6 +71,24 @@ class SharedStringsHelper
$this->tempFolder = $this->fileSystemHelper->createFolder($rootTempFolder, uniqid('sharedstrings')); $this->tempFolder = $this->fileSystemHelper->createFolder($rootTempFolder, uniqid('sharedstrings'));
} }
/**
* Returns whether the XLSX file contains a shared strings XML file
*
* @return bool
*/
public function hasSharedStrings()
{
$hasSharedStrings = false;
$zip = new \ZipArchive();
if ($zip->open($this->filePath) === true) {
$hasSharedStrings = ($zip->locateName(self::SHARED_STRINGS_XML_FILE_PATH) !== false);
$zip->close();
}
return $hasSharedStrings;
}
/** /**
* Builds an in-memory array containing all the shared strings of the worksheet. * Builds an in-memory array containing all the shared strings of the worksheet.
* All the strings are stored in a XML file, located at 'xl/sharedStrings.xml'. * All the strings are stored in a XML file, located at 'xl/sharedStrings.xml'.
@@ -93,8 +111,8 @@ class SharedStringsHelper
$this->tempFilePointer = null; $this->tempFilePointer = null;
$escaper = new \Box\Spout\Common\Escaper\XLSX(); $escaper = new \Box\Spout\Common\Escaper\XLSX();
$sharedStringsFilePath = 'zip://' . $this->filePath . '#' . self::SHARED_STRINGS_XML_FILE_PATH; $sharedStringsFilePath = $this->getSharedStringsFilePath();
if ($xmlReader->open($sharedStringsFilePath, null, LIBXML_NONET) === false) { if ($xmlReader->open($sharedStringsFilePath, null, LIBXML_NOENT|LIBXML_NONET) === false) {
throw new IOException('Could not open "' . self::SHARED_STRINGS_XML_FILE_PATH . '".'); throw new IOException('Could not open "' . self::SHARED_STRINGS_XML_FILE_PATH . '".');
} }
@@ -143,6 +161,14 @@ class SharedStringsHelper
$xmlReader->close(); $xmlReader->close();
} }
/**
* @return string The path to the shared strings XML file
*/
protected function getSharedStringsFilePath()
{
return 'zip://' . $this->filePath . '#' . self::SHARED_STRINGS_XML_FILE_PATH;
}
/** /**
* Removes nodes that should not be read, like the pronunciation of the Kanji characters. * Removes nodes that should not be read, like the pronunciation of the Kanji characters.
* By keeping them, their text content would be added to the read string. * By keeping them, their text content would be added to the read string.
@@ -223,7 +249,7 @@ class SharedStringsHelper
protected function getSharedStringTempFilePath($sharedStringIndex) protected function getSharedStringTempFilePath($sharedStringIndex)
{ {
$numTempFile = intval($sharedStringIndex / self::MAX_NUM_STRINGS_PER_TEMP_FILE); $numTempFile = intval($sharedStringIndex / self::MAX_NUM_STRINGS_PER_TEMP_FILE);
return $this->tempFolder . DIRECTORY_SEPARATOR . 'sharedstrings' . $numTempFile; return $this->tempFolder . '/sharedstrings' . $numTempFile;
} }
/** /**
@@ -91,12 +91,12 @@ class WorksheetHelper
* default to the data sheet XML file name ("xl/worksheets/sheet2.xml" => "sheet2"). * default to the data sheet XML file name ("xl/worksheets/sheet2.xml" => "sheet2").
* *
* @param string $sheetDataXMLFilePath Path of the sheet data XML file as in [Content_Types].xml * @param string $sheetDataXMLFilePath Path of the sheet data XML file as in [Content_Types].xml
* @param int $sheetNumberZeroBased Index of the sheet, based on order in [Content_Types].xml (zero-based) * @param int $sheetIndexZeroBased Index of the sheet, based on order in [Content_Types].xml (zero-based)
* @return \Box\Spout\Reader\Sheet Sheet instance * @return \Box\Spout\Reader\Sheet Sheet instance
*/ */
protected function getSheet($sheetDataXMLFilePath, $sheetNumberZeroBased) protected function getSheet($sheetDataXMLFilePath, $sheetIndexZeroBased)
{ {
$sheetId = $sheetNumberZeroBased + 1; $sheetId = $sheetIndexZeroBased + 1;
$sheetName = $this->getDefaultSheetName($sheetDataXMLFilePath); $sheetName = $this->getDefaultSheetName($sheetDataXMLFilePath);
/* /*
@@ -126,7 +126,7 @@ class WorksheetHelper
} }
} }
return new Sheet($sheetId, $sheetNumberZeroBased, $sheetName); return new Sheet($sheetId, $sheetIndexZeroBased, $sheetName);
} }
/** /**
@@ -204,6 +204,6 @@ class WorksheetHelper
*/ */
public function hasNextWorksheet($currentWorksheet, $allWorksheets) public function hasNextWorksheet($currentWorksheet, $allWorksheets)
{ {
return ($currentWorksheet === null || ($currentWorksheet->getWorksheetNumber() + 1 < count($allWorksheets))); return ($currentWorksheet === null || ($currentWorksheet->getWorksheetIndex() + 1 < count($allWorksheets)));
} }
} }
+9 -8
View File
@@ -13,26 +13,27 @@ class Worksheet
/** @var \Box\Spout\Reader\Sheet The "external" sheet */ /** @var \Box\Spout\Reader\Sheet The "external" sheet */
protected $externalSheet; protected $externalSheet;
/** @var int Worksheet number, based on the order of appareance in [Content_Types].xml (zero-based) */ /** @var int Worksheet index, based on the order of appareance in [Content_Types].xml (zero-based) */
protected $worksheetNumber; protected $worksheetIndex;
/** @var string Path of the XML file containing the worksheet data */ /** @var string Path of the XML file containing the worksheet data */
protected $dataXmlFilePath; protected $dataXmlFilePath;
/**\ /**\
* @param \Box\Spout\Reader\Sheet $externalSheet The associated "external" sheet * @param \Box\Spout\Reader\Sheet $externalSheet The associated "external" sheet
* @param int $worksheetNumber Worksheet number, based on the order of appareance in [Content_Types].xml (zero-based) * @param int $worksheetIndex Worksheet index, based on the order of appareance in [Content_Types].xml (zero-based)
* @param string $dataXmlFilePath Path of the XML file containing the worksheet data * @param string $dataXmlFilePath Path of the XML file containing the worksheet data
*/ */
public function __construct($externalSheet, $worksheetNumber, $dataXmlFilePath) public function __construct($externalSheet, $worksheetIndex, $dataXmlFilePath)
{ {
$this->externalSheet = $externalSheet; $this->externalSheet = $externalSheet;
$this->worksheetNumber = $worksheetNumber; $this->worksheetIndex = $worksheetIndex;
$this->dataXmlFilePath = $dataXmlFilePath; $this->dataXmlFilePath = $dataXmlFilePath;
} }
/** /**
* @return string Path of the XML file containing the worksheet data, without the leading slash * @return string Path of the XML file containing the worksheet data,
* without the leading slash.
*/ */
public function getDataXmlFilePath() public function getDataXmlFilePath()
{ {
@@ -50,8 +51,8 @@ class Worksheet
/** /**
* @return int * @return int
*/ */
public function getWorksheetNumber() public function getWorksheetIndex()
{ {
return $this->worksheetNumber; return $this->worksheetIndex;
} }
} }
+8 -8
View File
@@ -13,21 +13,21 @@ class Sheet
/** @var int ID of the sheet */ /** @var int ID of the sheet */
protected $id; protected $id;
/** @var int Number of the sheet, based on order of creation (zero-based) */ /** @var int Index of the sheet, based on order of creation (zero-based) */
protected $number; protected $index;
/** @var string Name of the sheet */ /** @var string Name of the sheet */
protected $name; protected $name;
/** /**
* @param int $sheetId ID of the sheet * @param int $sheetId ID of the sheet
* @param int $sheetNumber Number of the sheet, based on order of creation (zero-based) * @param int $sheetIndex Index of the sheet, based on order of creation (zero-based)
* @param string $sheetName Name of the sheet * @param string $sheetName Name of the sheet
*/ */
function __construct($sheetId, $sheetNumber, $sheetName) function __construct($sheetId, $sheetIndex, $sheetName)
{ {
$this->id = $sheetId; $this->id = $sheetId;
$this->number = $sheetNumber; $this->index = $sheetIndex;
$this->name = $sheetName; $this->name = $sheetName;
} }
@@ -40,11 +40,11 @@ class Sheet
} }
/** /**
* @return int Number of the sheet, based on order of creation (zero-based) * @return int Index of the sheet, based on order of creation (zero-based)
*/ */
public function getNumber() public function getIndex()
{ {
return $this->number; return $this->index;
} }
/** /**
+166 -27
View File
@@ -19,6 +19,14 @@ use Box\Spout\Reader\Helper\XLSX\WorksheetHelper;
*/ */
class XLSX extends AbstractReader class XLSX extends AbstractReader
{ {
const CELL_TYPE_INLINE_STRING = 'inlineStr';
const CELL_TYPE_STR = 'str';
const CELL_TYPE_SHARED_STRING = 's';
const CELL_TYPE_BOOLEAN = 'b';
const CELL_TYPE_NUMERIC = 'n';
const CELL_TYPE_DATE = 'd';
const CELL_TYPE_ERROR = 'e';
/** @var string Real path of the file to read */ /** @var string Real path of the file to read */
protected $filePath; protected $filePath;
@@ -72,8 +80,12 @@ class XLSX extends AbstractReader
$this->zip = new \ZipArchive(); $this->zip = new \ZipArchive();
if ($this->zip->open($filePath) === true) { if ($this->zip->open($filePath) === true) {
// Extracts all the strings from the worksheets for easy access in the future $this->sharedStringsHelper = new SharedStringsHelper($filePath, $this->tempFolder);
$this->extractSharedStrings($filePath);
if ($this->sharedStringsHelper->hasSharedStrings()) {
// Extracts all the strings from the worksheets for easy access in the future
$this->sharedStringsHelper->extractSharedStrings();
}
// Fetch all available worksheets // Fetch all available worksheets
$this->worksheetHelper = new WorksheetHelper($filePath, $this->globalFunctionsHelper); $this->worksheetHelper = new WorksheetHelper($filePath, $this->globalFunctionsHelper);
@@ -87,19 +99,6 @@ class XLSX extends AbstractReader
} }
} }
/**
* Builds an in-memory array containing all the shared strings of the worksheets.
*
* @param string $filePath Path of the XLSX file to be read
* @return void
* @throws \Box\Spout\Common\Exception\IOException If sharedStrings XML file can't be read
*/
protected function extractSharedStrings($filePath)
{
$this->sharedStringsHelper = new SharedStringsHelper($filePath, $this->tempFolder);
$this->sharedStringsHelper->extractSharedStrings();
}
/** /**
* Returns whether another worksheet exists after the current worksheet. * Returns whether another worksheet exists after the current worksheet.
* *
@@ -132,8 +131,8 @@ class XLSX extends AbstractReader
if ($this->currentWorksheet === null) { if ($this->currentWorksheet === null) {
$nextWorksheet = $this->worksheets[0]; $nextWorksheet = $this->worksheets[0];
} else { } else {
$currentWorksheetNumber = $this->currentWorksheet->getWorksheetNumber(); $currentWorksheetIndex = $this->currentWorksheet->getWorksheetIndex();
$nextWorksheet = $this->worksheets[$currentWorksheetNumber + 1]; $nextWorksheet = $this->worksheets[$currentWorksheetIndex + 1];
} }
$this->initXmlReaderForWorksheetData($nextWorksheet); $this->initXmlReaderForWorksheetData($nextWorksheet);
@@ -167,7 +166,7 @@ class XLSX extends AbstractReader
$worksheetDataXMLFilePath = $worksheet->getDataXmlFilePath(); $worksheetDataXMLFilePath = $worksheet->getDataXmlFilePath();
$worksheetDataFilePath = 'zip://' . $this->filePath . '#' . $worksheetDataXMLFilePath; $worksheetDataFilePath = 'zip://' . $this->filePath . '#' . $worksheetDataXMLFilePath;
if ($this->xmlReader->open($worksheetDataFilePath, null, LIBXML_NONET) === false) { if ($this->xmlReader->open($worksheetDataFilePath, null, LIBXML_NOENT|LIBXML_NONET) === false) {
throw new IOException('Could not open "' . $worksheetDataXMLFilePath . '".'); throw new IOException('Could not open "' . $worksheetDataXMLFilePath . '".');
} }
} }
@@ -186,6 +185,7 @@ class XLSX extends AbstractReader
throw new BadUsageException('You must call nextSheet() before calling hasNextRow() or nextRow()'); throw new BadUsageException('You must call nextSheet() before calling hasNextRow() or nextRow()');
} }
$escaper = new \Box\Spout\Common\Escaper\XLSX();
$isInsideRowTag = false; $isInsideRowTag = false;
$rowData = []; $rowData = [];
@@ -197,6 +197,7 @@ class XLSX extends AbstractReader
$lastCellIndex = $matches[1]; $lastCellIndex = $matches[1];
$this->numberOfColumns = CellHelper::getColumnIndexFromCellIndex($lastCellIndex) + 1; $this->numberOfColumns = CellHelper::getColumnIndexFromCellIndex($lastCellIndex) + 1;
} }
} else if ($this->xmlReader->nodeType == \XMLReader::ELEMENT && $this->xmlReader->name === 'row') { } else if ($this->xmlReader->nodeType == \XMLReader::ELEMENT && $this->xmlReader->name === 'row') {
// Start of the row description // Start of the row description
$isInsideRowTag = true; $isInsideRowTag = true;
@@ -209,20 +210,15 @@ class XLSX extends AbstractReader
$numberOfColumnsForRow = intval($numberOfColumnsForRow); $numberOfColumnsForRow = intval($numberOfColumnsForRow);
} }
$rowData = ($numberOfColumnsForRow !== 0) ? array_fill(0, $numberOfColumnsForRow, '') : []; $rowData = ($numberOfColumnsForRow !== 0) ? array_fill(0, $numberOfColumnsForRow, '') : [];
} else if ($isInsideRowTag && $this->xmlReader->nodeType == \XMLReader::ELEMENT && $this->xmlReader->name === 'c') { } else if ($isInsideRowTag && $this->xmlReader->nodeType == \XMLReader::ELEMENT && $this->xmlReader->name === 'c') {
// Start of a cell description // Start of a cell description
$currentCellIndex = $this->xmlReader->getAttribute('r'); $currentCellIndex = $this->xmlReader->getAttribute('r');
$currentColumnIndex = CellHelper::getColumnIndexFromCellIndex($currentCellIndex); $currentColumnIndex = CellHelper::getColumnIndexFromCellIndex($currentCellIndex);
$node = $this->xmlReader->expand();
$hasSharedString = ($this->xmlReader->getAttribute('t') === 's'); $node = $this->xmlReader->expand();
if ($hasSharedString) { $rowData[$currentColumnIndex] = $this->getCellValue($node, $escaper);
$sharedStringIndex = intval($node->nodeValue);
$rowData[$currentColumnIndex] = $this->sharedStringsHelper->getStringAtIndex($sharedStringIndex);
} else {
// for inline strings or numbers, just get the value
$rowData[$currentColumnIndex] = trim($node->nodeValue);
}
} else if ($this->xmlReader->nodeType == \XMLReader::END_ELEMENT && $this->xmlReader->name === 'row') { } else if ($this->xmlReader->nodeType == \XMLReader::END_ELEMENT && $this->xmlReader->name === 'row') {
// End of the row description // End of the row description
// If needed, we fill the empty cells // If needed, we fill the empty cells
@@ -235,6 +231,149 @@ class XLSX extends AbstractReader
return ($rowData !== []) ? $rowData : null; return ($rowData !== []) ? $rowData : null;
} }
/**
* Returns the cell's string value from a node's nested value node
*
* @param \DOMNode $node
* @return string The value associated with the cell
*/
protected function getVNodeValue($node)
{
// for cell types having a "v" tag containing the value.
// if not, the returned value should be empty string.
$vNode = $node->getElementsByTagName('v')->item(0);
if ($vNode !== null) {
return $vNode->nodeValue;
}
return "";
}
/**
* Returns the cell String value where string is inline.
*
* @param \DOMNode $node
* @param \Box\Spout\Common\Escaper\XLSX $escaper
* @return string The value associated with the cell (null when the cell has an error)
*/
protected function formatInlineStringCellValue($node, $escaper)
{
// inline strings are formatted this way:
// <c r="A1" t="inlineStr"><is><t>[INLINE_STRING]</t></is></c>
$tNode = $node->getElementsByTagName('t')->item(0);
$escapedCellValue = trim($tNode->nodeValue);
$cellValue = $escaper->unescape($escapedCellValue);
return $cellValue;
}
/**
* Returns the cell String value from shared-strings file using nodeValue index.
*
* @param string $nodeValue
* @param \Box\Spout\Common\Escaper\XLSX $escaper
* @return string The value associated with the cell (null when the cell has an error)
*/
protected function formatSharedStringCellValue($nodeValue, $escaper)
{
// shared strings are formatted this way:
// <c r="A1" t="s"><v>[SHARED_STRING_INDEX]</v></c>
$sharedStringIndex = intval($nodeValue);
$escapedCellValue = $this->sharedStringsHelper->getStringAtIndex($sharedStringIndex);
$cellValue = $escaper->unescape($escapedCellValue);
return $cellValue;
}
/**
* Returns the cell String value, where string is stored in value node.
*
* @param string $nodeValue
* @param \Box\Spout\Common\Escaper\XLSX $escaper
* @return string The value associated with the cell (null when the cell has an error)
*/
protected function formatStrCellValue($nodeValue, $escaper)
{
$escapedCellValue = trim($nodeValue);
$cellValue = $escaper->unescape($escapedCellValue);
return $cellValue;
}
/**
* Returns the cell Numeric value from string of nodeValue.
*
* @param string $nodeValue
* @param \Box\Spout\Common\Escaper\XLSX $escaper
* @return int|float The value associated with the cell
*/
protected function formatNumericCellValue($nodeValue)
{
$cellValue = is_int($nodeValue) ? intval($nodeValue) : floatval($nodeValue);
return $cellValue;
}
/**
* Returns the cell Boolean value from a specific node's Value.
*
* @param string $nodeValue
* @return bool The value associated with the cell
*/
protected function formatBooleanCellValue($nodeValue)
{
// !! is similar to boolval()
$cellValue = !!$nodeValue;
return $cellValue;
}
/**
* Returns a cell's PHP Date value, associated to the given stored nodeValue.
*
* @param string $nodeValue
* @param \Box\Spout\Common\Escaper\XLSX $escaper
* @return DateTime|null The value associated with the cell (null when the cell has an error)
*/
protected function formatDateCellValue($nodeValue)
{
try { // Mitigate thrown Exception on invalid date-time format (http://php.net/manual/en/datetime.construct.php)
$cellValue = new \DateTime($nodeValue);
return $cellValue;
} catch (\Exception $e) {
return null;
}
}
/**
* Returns the (unescaped) correctly marshalled, cell value associated to the given XML node.
*
* @param \DOMNode $node
* @param \Box\Spout\Common\Escaper\XLSX $escaper
* @return string|int|float|bool|null The value associated with the cell (null when the cell has an error)
*/
protected function getCellValue($node, $escaper)
{
// Default cell type is "n"
$cellType = $node->getAttribute('t') ?: 'n';
$vNodeValue = $this->getVNodeValue($node);
if ( ($vNodeValue === "") && ($cellType !== self::CELL_TYPE_INLINE_STRING) ) {
return $vNodeValue;
}
switch ($cellType)
{
case self::CELL_TYPE_INLINE_STRING:
return $this->formatInlineStringCellValue($node, $escaper);
case self::CELL_TYPE_SHARED_STRING:
return $this->formatSharedStringCellValue($vNodeValue, $escaper);
case self::CELL_TYPE_STR:
return $this->formatStrCellValue($vNodeValue, $escaper);
case self::CELL_TYPE_BOOLEAN:
return $this->formatBooleanCellValue($vNodeValue);
case self::CELL_TYPE_NUMERIC:
return $this->formatNumericCellValue($vNodeValue);
case self::CELL_TYPE_DATE:
return $this->formatDateCellValue($vNodeValue);
default:
return null;
}
}
/** /**
* Closes the reader. To be used after reading the file. * Closes the reader. To be used after reading the file.
* *
+1 -1
View File
@@ -73,7 +73,7 @@ class CSV extends AbstractWriter
*/ */
protected function addRowToWriter(array $dataRow) protected function addRowToWriter(array $dataRow)
{ {
$wasWriteSuccessful = fputcsv($this->filePointer, $dataRow, $this->fieldDelimiter, $this->fieldEnclosure); $wasWriteSuccessful = $this->globalFunctionsHelper->fputcsv($this->filePointer, $dataRow, $this->fieldDelimiter, $this->fieldEnclosure);
if ($wasWriteSuccessful === false) { if ($wasWriteSuccessful === false) {
throw new IOException('Unable to write data'); throw new IOException('Unable to write data');
} }
@@ -36,7 +36,7 @@ EOD;
*/ */
public function __construct($xlFolder) public function __construct($xlFolder)
{ {
$sharedStringsFilePath = $xlFolder . DIRECTORY_SEPARATOR . self::SHARED_STRINGS_FILE_NAME; $sharedStringsFilePath = $xlFolder . '/' . self::SHARED_STRINGS_FILE_NAME;
$this->sharedStringsFilePointer = fopen($sharedStringsFilePath, 'w'); $this->sharedStringsFilePointer = fopen($sharedStringsFilePath, 'w');
$this->throwIfSharedStringsFilePointerIsNotAvailable(); $this->throwIfSharedStringsFilePointerIsNotAvailable();
+15 -3
View File
@@ -33,18 +33,30 @@ class ZipHelper
*/ */
protected function addFolderToZip($zip, $folderPath) protected function addFolderToZip($zip, $folderPath)
{ {
$folderRealPath = realpath($folderPath) . DIRECTORY_SEPARATOR; $folderRealPath = $this->getNormalizedRealPath($folderPath) . '/';
$itemIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($folderPath, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST); $itemIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($folderPath, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST);
foreach ($itemIterator as $itemInfo) { foreach ($itemIterator as $itemInfo) {
$itemRealPath = realpath($itemInfo->getPathname()); $itemRealPath = $this->getNormalizedRealPath($itemInfo->getPathname());
$itemLocalPath = str_replace($folderRealPath, '', $itemRealPath); $itemLocalPath = str_replace($folderRealPath, '', $itemRealPath);
if ($itemInfo->isFile()) { if ($itemInfo->isFile()) {
$zip->addFile($itemInfo->getPathname(), $itemLocalPath); $zip->addFile($itemRealPath, $itemLocalPath);
} else if ($itemInfo->isDir()) { } else if ($itemInfo->isDir()) {
$zip->addEmptyDir($itemLocalPath); $zip->addEmptyDir($itemLocalPath);
} }
} }
} }
/**
* Returns canonicalized absolute pathname, containing only forward slashes.
*
* @param string $path Path to normalize
* @return string Normalized and canonicalized path
*/
protected function getNormalizedRealPath($path)
{
$realPath = realpath($path);
return str_replace(DIRECTORY_SEPARATOR, '/', $realPath);
}
} }
+2 -2
View File
@@ -67,8 +67,8 @@ class Workbook
*/ */
public function addNewSheet() public function addNewSheet()
{ {
$newSheetNumber = count($this->worksheets); $newSheetIndex = count($this->worksheets);
$sheet = new Sheet($newSheetNumber); $sheet = new Sheet($newSheetIndex);
$worksheetFilesFolder = $this->fileSystemHelper->getXlWorksheetsFolder(); $worksheetFilesFolder = $this->fileSystemHelper->getXlWorksheetsFolder();
$worksheet = new Worksheet($sheet, $worksheetFilesFolder, $this->sharedStringsHelper, $this->shouldUseInlineStrings); $worksheet = new Worksheet($sheet, $worksheetFilesFolder, $this->sharedStringsHelper, $this->shouldUseInlineStrings);
+3 -3
View File
@@ -56,7 +56,7 @@ EOD;
$this->stringsEscaper = new \Box\Spout\Common\Escaper\XLSX(); $this->stringsEscaper = new \Box\Spout\Common\Escaper\XLSX();
$this->worksheetFilePath = $worksheetFilesFolder . DIRECTORY_SEPARATOR . strtolower($this->externalSheet->getName()) . '.xml'; $this->worksheetFilePath = $worksheetFilesFolder . '/' . strtolower($this->externalSheet->getName()) . '.xml';
$this->startSheet(); $this->startSheet();
} }
@@ -96,8 +96,8 @@ EOD;
*/ */
public function getId() public function getId()
{ {
// sheet number is zero-based, while ID is 1-based // sheet index is zero-based, while ID is 1-based
return $this->externalSheet->getNumber() + 1; return $this->externalSheet->getIndex() + 1;
} }
/** /**
+9 -9
View File
@@ -12,27 +12,27 @@ class Sheet
{ {
const DEFAULT_SHEET_NAME_PREFIX = 'Sheet'; const DEFAULT_SHEET_NAME_PREFIX = 'Sheet';
/** @var int Number of the sheet, based on order of creation (zero-based) */ /** @var int Index of the sheet, based on order of creation (zero-based) */
protected $sheetNumber; protected $index;
/** @var string Name of the sheet */ /** @var string Name of the sheet */
protected $name; protected $name;
/** /**
* @param $sheetNumber Number of the sheet, based on order of creation (zero-based) * @param int $sheetIndex Index of the sheet, based on order of creation (zero-based)
*/ */
function __construct($sheetNumber) function __construct($sheetIndex)
{ {
$this->sheetNumber = $sheetNumber; $this->index = $sheetIndex;
$this->name = self::DEFAULT_SHEET_NAME_PREFIX . ($sheetNumber + 1); $this->name = self::DEFAULT_SHEET_NAME_PREFIX . ($sheetIndex + 1);
} }
/** /**
* @return int Number of the sheet, based on order of creation (zero-based) * @return int Index of the sheet, based on order of creation (zero-based)
*/ */
public function getNumber() public function getIndex()
{ {
return $this->sheetNumber; return $this->index;
} }
/** /**
+52
View File
@@ -0,0 +1,52 @@
<?php
namespace Box\Spout\Reader;
use Box\Spout\Common\Type;
use Box\Spout\TestUsingResource;
/**
* Class SheetTest
*
* @package Box\Spout\Reader
*/
class SheetTest extends \PHPUnit_Framework_TestCase
{
use TestUsingResource;
/**
* @return void
*/
public function testNextSheetShouldReturnCorrectSheetInfos()
{
$sheets = $this->openFileAndReturnSheets('two_sheets_with_custom_names.xlsx');
$this->assertEquals('CustomName1', $sheets[0]->getName());
$this->assertEquals(0, $sheets[0]->getIndex());
$this->assertEquals(1, $sheets[0]->getId());
$this->assertEquals('CustomName2', $sheets[1]->getName());
$this->assertEquals(1, $sheets[1]->getIndex());
$this->assertEquals(2, $sheets[1]->getId());
}
/**
* @param string $fileName
* @return Sheet[]
*/
private function openFileAndReturnSheets($fileName)
{
$resourcePath = $this->getResourcePath($fileName);
$reader = ReaderFactory::create(Type::XLSX);
$reader->open($resourcePath);
$sheets = [];
while ($reader->hasNextSheet()) {
$sheets[] = $reader->nextSheet();
}
$reader->close();
return $sheets;
}
}
+77 -20
View File
@@ -38,6 +38,37 @@ class XLSXTest extends \PHPUnit_Framework_TestCase
$this->getAllRowsForFile($filePath); $this->getAllRowsForFile($filePath);
} }
/**
* @expectedException \Box\Spout\Reader\Exception\ReaderNotOpenedException
*
* @return void
*/
public function testHasNextSheetShouldThrowExceptionIfReaderNotOpened()
{
$reader = ReaderFactory::create(Type::XLSX);
$reader->hasNextSheet();
}
/**
* @expectedException \Box\Spout\Reader\Exception\EndOfWorksheetsReachedException
*
* @return void
*/
public function testNextSheetShouldThrowExceptionIfNoMoreSheetsToRead()
{
$fileName = 'one_sheet_with_shared_strings.xlsx';
$resourcePath = $this->getResourcePath($fileName);
$reader = ReaderFactory::create(Type::XLSX);
$reader->open($resourcePath);
while ($reader->hasNextSheet()) {
$reader->nextSheet();
}
$reader->nextSheet();
}
/** /**
* @return array * @return array
*/ */
@@ -69,6 +100,43 @@ class XLSXTest extends \PHPUnit_Framework_TestCase
} }
} }
/**
* @return void
*/
public function testReadShouldSupportFilesWithoutSharedStringsFile()
{
$allRows = $this->getAllRowsForFile('sheet_with_no_shared_strings_file.xlsx');
$expectedRows = [
[10, 11],
[20, 21],
];
$this->assertEquals($expectedRows, $allRows);
}
/**
* @return void
*/
public function testReadShouldSupportAllCellTypes()
{
$allRows = $this->getAllRowsForFile('sheet_with_all_cell_types.xlsx');
$expectedRows = [
[
's1--A1', 's1--A2',
false, true,
\DateTime::createFromFormat('Y-m-d H:i:s', '2015-06-03 13:21:58'),
\DateTime::createFromFormat('Y-m-d H:i:s', '2015-06-01 00:00:00'),
10, 10.43,
null,
'weird string', // valid 'str' string
null, // invalid date
],
['', '', '', '', '', '', '', '', ''],
];
$this->assertEquals($expectedRows, $allRows);
}
/** /**
* @return void * @return void
*/ */
@@ -184,7 +252,7 @@ class XLSXTest extends \PHPUnit_Framework_TestCase
{ {
$allRows = $this->getAllRowsForFile('billion_laughs_test_file.xlsx'); $allRows = $this->getAllRowsForFile('billion_laughs_test_file.xlsx');
$expectedMaxMemoryUsage = 20 * 1024 * 1024; // 20MB $expectedMaxMemoryUsage = 30 * 1024 * 1024; // 30MB
$this->assertLessThan($expectedMaxMemoryUsage, memory_get_peak_usage(true), 'Entities should not be expanded and therefore consume all the memory.'); $this->assertLessThan($expectedMaxMemoryUsage, memory_get_peak_usage(true), 'Entities should not be expanded and therefore consume all the memory.');
$expectedFirstRow = ['s1--A1', 's1--B1', 's1--C1', 's1--D1', 's1--E1']; $expectedFirstRow = ['s1--A1', 's1--B1', 's1--C1', 's1--D1', 's1--E1'];
@@ -203,27 +271,16 @@ class XLSXTest extends \PHPUnit_Framework_TestCase
/** /**
* @return void * @return void
*/ */
public function testNextSheetShouldReturnCorrectSheetInfos() public function testReadShouldSkipFormulas()
{ {
$resourcePath = $this->getResourcePath('two_sheets_with_custom_names.xlsx'); $allRows = $this->getAllRowsForFile('sheet_with_formulas.xlsx');
$reader = ReaderFactory::create(Type::XLSX);
$reader->open($resourcePath);
/** @var \Box\Spout\Reader\Sheet[] $sheets */ $expectedRows = [
$sheets = []; ['val1', 'val2', 'total1', 'total2'],
while ($reader->hasNextSheet()) { [10, 20, 30, 21],
$sheets[] = $reader->nextSheet(); [11, 21, 32, 41],
} ];
$this->assertEquals($expectedRows, $allRows);
$reader->close();
$this->assertEquals('CustomName1', $sheets[0]->getName());
$this->assertEquals(0, $sheets[0]->getNumber());
$this->assertEquals(1, $sheets[0]->getId());
$this->assertEquals('CustomName2', $sheets[1]->getName());
$this->assertEquals(1, $sheets[1]->getNumber());
$this->assertEquals(2, $sheets[1]->getId());
} }
/** /**
+40 -4
View File
@@ -17,13 +17,13 @@ class SheetTest extends \PHPUnit_Framework_TestCase
/** /**
* @return void * @return void
*/ */
public function testGetSheetNumber() public function testGetSheetIndex()
{ {
$sheets = $this->writeDataAndReturnSheets('test_get_sheet_number.xlsx'); $sheets = $this->writeDataAndReturnSheets('test_get_sheet_index.xlsx');
$this->assertEquals(2, count($sheets), '2 sheets should have been created'); $this->assertEquals(2, count($sheets), '2 sheets should have been created');
$this->assertEquals(0, $sheets[0]->getNumber(), 'The first sheet should be number 0'); $this->assertEquals(0, $sheets[0]->getIndex(), 'The first sheet should be index 0');
$this->assertEquals(1, $sheets[1]->getNumber(), 'The second sheet should be number 1'); $this->assertEquals(1, $sheets[1]->getIndex(), 'The second sheet should be index 1');
} }
/** /**
@@ -38,6 +38,28 @@ class SheetTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('Sheet2', $sheets[1]->getName(), 'Invalid name for the second sheet'); $this->assertEquals('Sheet2', $sheets[1]->getName(), 'Invalid name for the second sheet');
} }
/**
* @return void
*/
public function testSetSheetNameShouldCreateSheetWithCustomName()
{
$fileName = 'test_set_name_should_create_sheet_with_custom_name.xlsx';
$this->createGeneratedFolderIfNeeded($fileName);
$resourcePath = $this->getGeneratedResourcePath($fileName);
$writer = WriterFactory::create(Type::XLSX);
$writer->openToFile($resourcePath);
$customSheetName = 'CustomName';
$sheet = $writer->getCurrentSheet();
$sheet->setName($customSheetName);
$writer->addRow(['xlsx--11', 'xlsx--12']);
$writer->close();
$this->assertSheetNameEquals($customSheetName, $resourcePath, "The sheet name should have been changed to '$customSheetName'");
}
/** /**
* @param string $fileName * @param string $fileName
* @return Sheet[] * @return Sheet[]
@@ -59,4 +81,18 @@ class SheetTest extends \PHPUnit_Framework_TestCase
return $writer->getSheets(); return $writer->getSheets();
} }
/**
* @param string $expectedName
* @param string $resourcePath
* @param string $message
* @return void
*/
private function assertSheetNameEquals($expectedName, $resourcePath, $message = '')
{
$pathToWorkbookFile = $resourcePath . '#xl/workbook.xml';
$xmlContents = file_get_contents('zip://' . $pathToWorkbookFile);
$this->assertContains('<sheet name="' . $expectedName . '"', $xmlContents, $message);
}
} }
+6 -42
View File
@@ -343,28 +343,6 @@ class XLSXTest extends \PHPUnit_Framework_TestCase
$this->assertInlineDataWasWrittenToSheet($fileName, 1, 'control&#039;s _x0015_ &quot;character&quot;'); $this->assertInlineDataWasWrittenToSheet($fileName, 1, 'control&#039;s _x0015_ &quot;character&quot;');
} }
/**
* @return void
*/
public function testSetNameShouldCreateSheetWithCustomName()
{
$fileName = 'test_set_name_should_create_sheet_with_custom_name.xlsx';
$this->createGeneratedFolderIfNeeded($fileName);
$resourcePath = $this->getGeneratedResourcePath($fileName);
$writer = WriterFactory::create(Type::XLSX);
$writer->openToFile($resourcePath);
$customSheetName = 'CustomName';
$sheet = $writer->getCurrentSheet();
$sheet->setName($customSheetName);
$writer->addRow(['xlsx--11', 'xlsx--12']);
$writer->close();
$this->assertSheetNameEquals($customSheetName, $resourcePath, "The sheet name should have been changed to '$customSheetName'");
}
/** /**
* @param array $allRows * @param array $allRows
* @param string $fileName * @param string $fileName
@@ -422,15 +400,15 @@ class XLSXTest extends \PHPUnit_Framework_TestCase
/** /**
* @param string $fileName * @param string $fileName
* @param int $sheetNumber * @param int $sheetIndex
* @param mixed $inlineData * @param mixed $inlineData
* @param string $message * @param string $message
* @return void * @return void
*/ */
private function assertInlineDataWasWrittenToSheet($fileName, $sheetNumber, $inlineData, $message = '') private function assertInlineDataWasWrittenToSheet($fileName, $sheetIndex, $inlineData, $message = '')
{ {
$resourcePath = $this->getGeneratedResourcePath($fileName); $resourcePath = $this->getGeneratedResourcePath($fileName);
$pathToSheetFile = $resourcePath . '#xl/worksheets/sheet' . $sheetNumber . '.xml'; $pathToSheetFile = $resourcePath . '#xl/worksheets/sheet' . $sheetIndex . '.xml';
$xmlContents = file_get_contents('zip://' . $pathToSheetFile); $xmlContents = file_get_contents('zip://' . $pathToSheetFile);
$this->assertContains((string)$inlineData, $xmlContents, $message); $this->assertContains((string)$inlineData, $xmlContents, $message);
@@ -438,15 +416,15 @@ class XLSXTest extends \PHPUnit_Framework_TestCase
/** /**
* @param string $fileName * @param string $fileName
* @param int $sheetNumber * @param int $sheetIndex
* @param mixed $inlineData * @param mixed $inlineData
* @param string $message * @param string $message
* @return void * @return void
*/ */
private function assertInlineDataWasNotWrittenToSheet($fileName, $sheetNumber, $inlineData, $message = '') private function assertInlineDataWasNotWrittenToSheet($fileName, $sheetIndex, $inlineData, $message = '')
{ {
$resourcePath = $this->getGeneratedResourcePath($fileName); $resourcePath = $this->getGeneratedResourcePath($fileName);
$pathToSheetFile = $resourcePath . '#xl/worksheets/sheet' . $sheetNumber . '.xml'; $pathToSheetFile = $resourcePath . '#xl/worksheets/sheet' . $sheetIndex . '.xml';
$xmlContents = file_get_contents('zip://' . $pathToSheetFile); $xmlContents = file_get_contents('zip://' . $pathToSheetFile);
$this->assertNotContains((string)$inlineData, $xmlContents, $message); $this->assertNotContains((string)$inlineData, $xmlContents, $message);
@@ -466,18 +444,4 @@ class XLSXTest extends \PHPUnit_Framework_TestCase
$this->assertContains($sharedString, $xmlContents, $message); $this->assertContains($sharedString, $xmlContents, $message);
} }
/**
* @param string $expectedName
* @param string $resourcePath
* @param string $message
* @return void
*/
private function assertSheetNameEquals($expectedName, $resourcePath, $message = '')
{
$pathToWorkbookFile = $resourcePath . '#xl/workbook.xml';
$xmlContents = file_get_contents('zip://' . $pathToWorkbookFile);
$this->assertContains('<sheet name="' . $expectedName . '"', $xmlContents, $message);
}
} }
Binary file not shown.
Binary file not shown.