[XLSX] A cell should not contain more than 32,767 characters (#365)
This commit is contained in:
parent
984c9c1f67
commit
521f799366
@ -4,6 +4,7 @@ namespace Box\Spout\Writer\XLSX\Internal;
|
|||||||
|
|
||||||
use Box\Spout\Common\Exception\InvalidArgumentException;
|
use Box\Spout\Common\Exception\InvalidArgumentException;
|
||||||
use Box\Spout\Common\Exception\IOException;
|
use Box\Spout\Common\Exception\IOException;
|
||||||
|
use Box\Spout\Common\Helper\StringHelper;
|
||||||
use Box\Spout\Writer\Common\Helper\CellHelper;
|
use Box\Spout\Writer\Common\Helper\CellHelper;
|
||||||
use Box\Spout\Writer\Common\Internal\WorksheetInterface;
|
use Box\Spout\Writer\Common\Internal\WorksheetInterface;
|
||||||
|
|
||||||
@ -16,6 +17,14 @@ use Box\Spout\Writer\Common\Internal\WorksheetInterface;
|
|||||||
*/
|
*/
|
||||||
class Worksheet implements WorksheetInterface
|
class Worksheet implements WorksheetInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Maximum number of characters a cell can contain
|
||||||
|
* @see https://support.office.com/en-us/article/Excel-specifications-and-limits-16c69c74-3d6a-4aaf-ba35-e6eb276e8eaa [Excel 2007]
|
||||||
|
* @see https://support.office.com/en-us/article/Excel-specifications-and-limits-1672b34d-7043-467e-8e27-269d656771c3 [Excel 2010]
|
||||||
|
* @see https://support.office.com/en-us/article/Excel-specifications-and-limits-ca36e2dc-1f09-4620-b726-67c00b05040f [Excel 2013/2016]
|
||||||
|
*/
|
||||||
|
const MAX_CHARACTERS_PER_CELL = 32767;
|
||||||
|
|
||||||
const SHEET_XML_FILE_HEADER = <<<EOD
|
const SHEET_XML_FILE_HEADER = <<<EOD
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
||||||
@ -39,6 +48,9 @@ EOD;
|
|||||||
/** @var \Box\Spout\Common\Escaper\XLSX Strings escaper */
|
/** @var \Box\Spout\Common\Escaper\XLSX Strings escaper */
|
||||||
protected $stringsEscaper;
|
protected $stringsEscaper;
|
||||||
|
|
||||||
|
/** @var \Box\Spout\Common\Helper\StringHelper String helper */
|
||||||
|
protected $stringHelper;
|
||||||
|
|
||||||
/** @var Resource Pointer to the sheet data file (e.g. xl/worksheets/sheet1.xml) */
|
/** @var Resource Pointer to the sheet data file (e.g. xl/worksheets/sheet1.xml) */
|
||||||
protected $sheetFilePointer;
|
protected $sheetFilePointer;
|
||||||
|
|
||||||
@ -62,6 +74,7 @@ EOD;
|
|||||||
|
|
||||||
/** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */
|
/** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */
|
||||||
$this->stringsEscaper = \Box\Spout\Common\Escaper\XLSX::getInstance();
|
$this->stringsEscaper = \Box\Spout\Common\Escaper\XLSX::getInstance();
|
||||||
|
$this->stringHelper = new StringHelper();
|
||||||
|
|
||||||
$this->worksheetFilePath = $worksheetFilesFolder . '/' . strtolower($this->externalSheet->getName()) . '.xml';
|
$this->worksheetFilePath = $worksheetFilesFolder . '/' . strtolower($this->externalSheet->getName()) . '.xml';
|
||||||
$this->startSheet();
|
$this->startSheet();
|
||||||
@ -192,7 +205,7 @@ EOD;
|
|||||||
* @param mixed $cellValue
|
* @param mixed $cellValue
|
||||||
* @param int $styleId
|
* @param int $styleId
|
||||||
* @return string
|
* @return string
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException If the given value cannot be processed
|
||||||
*/
|
*/
|
||||||
private function getCellXML($rowIndex, $cellNumber, $cellValue, $styleId)
|
private function getCellXML($rowIndex, $cellNumber, $cellValue, $styleId)
|
||||||
{
|
{
|
||||||
@ -201,12 +214,7 @@ EOD;
|
|||||||
$cellXML .= ' s="' . $styleId . '"';
|
$cellXML .= ' s="' . $styleId . '"';
|
||||||
|
|
||||||
if (CellHelper::isNonEmptyString($cellValue)) {
|
if (CellHelper::isNonEmptyString($cellValue)) {
|
||||||
if ($this->shouldUseInlineStrings) {
|
$cellXML .= $this->getCellXMLFragmentForNonEmptyString($cellValue);
|
||||||
$cellXML .= ' t="inlineStr"><is><t>' . $this->stringsEscaper->escape($cellValue) . '</t></is></c>';
|
|
||||||
} else {
|
|
||||||
$sharedStringId = $this->sharedStringsHelper->writeString($cellValue);
|
|
||||||
$cellXML .= ' t="s"><v>' . $sharedStringId . '</v></c>';
|
|
||||||
}
|
|
||||||
} else if (CellHelper::isBoolean($cellValue)) {
|
} else if (CellHelper::isBoolean($cellValue)) {
|
||||||
$cellXML .= ' t="b"><v>' . intval($cellValue) . '</v></c>';
|
$cellXML .= ' t="b"><v>' . intval($cellValue) . '</v></c>';
|
||||||
} else if (CellHelper::isNumeric($cellValue)) {
|
} else if (CellHelper::isNumeric($cellValue)) {
|
||||||
@ -226,6 +234,29 @@ EOD;
|
|||||||
return $cellXML;
|
return $cellXML;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the XML fragment for a cell containing a non empty string
|
||||||
|
*
|
||||||
|
* @param string $cellValue The cell value
|
||||||
|
* @return string The XML fragment representing the cell
|
||||||
|
* @throws InvalidArgumentException If the string exceeds the maximum number of characters allowed per cell
|
||||||
|
*/
|
||||||
|
private function getCellXMLFragmentForNonEmptyString($cellValue)
|
||||||
|
{
|
||||||
|
if ($this->stringHelper->getStringLength($cellValue) > self::MAX_CHARACTERS_PER_CELL) {
|
||||||
|
throw new InvalidArgumentException('Trying to add a value that exceeds the maximum number of characters allowed in a cell (32,767)');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->shouldUseInlineStrings) {
|
||||||
|
$cellXMLFragment = ' t="inlineStr"><is><t>' . $this->stringsEscaper->escape($cellValue) . '</t></is></c>';
|
||||||
|
} else {
|
||||||
|
$sharedStringId = $this->sharedStringsHelper->writeString($cellValue);
|
||||||
|
$cellXMLFragment = ' t="s"><v>' . $sharedStringId . '</v></c>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cellXMLFragment;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the worksheet
|
* Closes the worksheet
|
||||||
*
|
*
|
||||||
|
@ -6,6 +6,7 @@ use Box\Spout\Common\Exception\SpoutException;
|
|||||||
use Box\Spout\Common\Type;
|
use Box\Spout\Common\Type;
|
||||||
use Box\Spout\TestUsingResource;
|
use Box\Spout\TestUsingResource;
|
||||||
use Box\Spout\Writer\WriterFactory;
|
use Box\Spout\Writer\WriterFactory;
|
||||||
|
use Box\Spout\Writer\XLSX\Internal\Worksheet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class WriterTest
|
* Class WriterTest
|
||||||
@ -98,6 +99,19 @@ class WriterTest extends \PHPUnit_Framework_TestCase
|
|||||||
public function testAddRowShouldThrowExceptionIfUnsupportedDataTypePassedIn()
|
public function testAddRowShouldThrowExceptionIfUnsupportedDataTypePassedIn()
|
||||||
{
|
{
|
||||||
$fileName = 'test_add_row_should_throw_exception_if_unsupported_data_type_passed_in.xlsx';
|
$fileName = 'test_add_row_should_throw_exception_if_unsupported_data_type_passed_in.xlsx';
|
||||||
|
$dataRows = [
|
||||||
|
[str_repeat('a', Worksheet::MAX_CHARACTERS_PER_CELL + 1)],
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->writeToXLSXFile($dataRows, $fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Box\Spout\Common\Exception\InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testAddRowShouldThrowExceptionIfWritingStringExceedingMaxNumberOfCharactersAllowedPerCell()
|
||||||
|
{
|
||||||
|
$fileName = 'test_add_row_should_throw_exception_if_string_exceeds_max_num_chars_allowed_per_cell.xlsx';
|
||||||
$dataRows = [
|
$dataRows = [
|
||||||
[new \stdClass()],
|
[new \stdClass()],
|
||||||
];
|
];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user