From 8f7db244de93ddc2fc8afbf377cf2b6de84f83ba Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 16 Jun 2013 10:26:16 +0100 Subject: [PATCH 1/7] Eliminate unnecessary version checks --- .../PHPExcel/Shared/OLE/ChainedBlockStream.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Classes/PHPExcel/Shared/OLE/ChainedBlockStream.php b/Classes/PHPExcel/Shared/OLE/ChainedBlockStream.php index 64cecec..025c6cb 100644 --- a/Classes/PHPExcel/Shared/OLE/ChainedBlockStream.php +++ b/Classes/PHPExcel/Shared/OLE/ChainedBlockStream.php @@ -161,14 +161,15 @@ class PHPExcel_Shared_OLE_ChainedBlockStream */ public function stream_eof() { - $eof = $this->pos >= strlen($this->data); - // Workaround for bug in PHP 5.0.x: http://bugs.php.net/27508 - if (version_compare(PHP_VERSION, '5.0', '>=') && - version_compare(PHP_VERSION, '5.1', '<')) { - - $eof = !$eof; - } - return $eof; +// As we don't support below 5.2 anymore, this is simply redundancy and overhead +// $eof = $this->pos >= strlen($this->data); +// // Workaround for bug in PHP 5.0.x: http://bugs.php.net/27508 +// if (version_compare(PHP_VERSION, '5.0', '>=') && +// version_compare(PHP_VERSION, '5.1', '<')) { +// $eof = !$eof; +// } +// return $eof; + return $this->pos >= strlen($this->data); } /** From a0859fd7d0a445fc2c67a5755ef7d0cdbbdb6b04 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 16 Jun 2013 15:13:05 +0100 Subject: [PATCH 2/7] Fix to number format masking for scientific notation --- Classes/PHPExcel/Style/NumberFormat.php | 5 ++++- .../Calculation/TextData/TEXT.data | 19 +++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Classes/PHPExcel/Style/NumberFormat.php b/Classes/PHPExcel/Style/NumberFormat.php index 3d5b20e..80347bf 100644 --- a/Classes/PHPExcel/Style/NumberFormat.php +++ b/Classes/PHPExcel/Style/NumberFormat.php @@ -673,7 +673,10 @@ class PHPExcel_Style_NumberFormat extends PHPExcel_Style_Supervisor implements P ); $value = preg_replace($number_regex, $value, $format); } else { - if (preg_match('/0([^\d\.]+)0/', $format, $matches)) { + if (preg_match('/0E[+-]0/i', $format)) { + // Scientific format + $value = sprintf('%5.2E', $value); + } elseif (preg_match('/0([^\d\.]+)0/', $format)) { $value = self::_complexNumberFormatMask($value, $format); } else { $sprintf_pattern = "%0$minWidth." . strlen($right) . "f"; diff --git a/unitTests/rawTestData/Calculation/TextData/TEXT.data b/unitTests/rawTestData/Calculation/TextData/TEXT.data index 3087dfa..da18def 100644 --- a/unitTests/rawTestData/Calculation/TextData/TEXT.data +++ b/unitTests/rawTestData/Calculation/TextData/TEXT.data @@ -1,10 +1,13 @@ -123.456, '"$#,##0.00"', "$123.46" -123.456, '"#,##0.00"', "123.46" -123.456, '"#,##0"', "123" -123.456, "00000", "00123" -123456.789, '"$#,##0.00"', '"$123,456.79"' -123456.789, '"#,##0.00"', '"123,456.79"' -123456.789, "0.00E+00", "1.23E05" +123.456, '"$#,##0.00"', "$123.46" +-123.456, '"$#,##0.00"', "$-123.46" +123.456, '"#,##0.00"', "123.46" +123.456, '"#,##0"', "123" +123.456, "00000", "00123" +123456.789, '"$#,##0.00"', '"$123,456.79"' +123456.789, '"#,##0.00"', '"123,456.79"' +123456.789, "0.00E+00", "1.23E05" +-123456.789, "0.00E+00", "-1.23E05" +0.000012345, "0.00E+00", "1.23E-05" "19-Dec-1960", "yyyy-mm-dd", "1960-12-19" "1-Jan-2012", "yyyy-mm-dd", "2012-01-01" -1.75, "# ?/?", "1 3/4" +1.75, "# ?/?", "1 3/4" From 333c811c5e523544a60e0d004f4bd3cb6734dfcb Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 16 Jun 2013 16:24:34 +0100 Subject: [PATCH 3/7] Minor performance tweaks to calculation engine --- Classes/PHPExcel/Calculation.php | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/Classes/PHPExcel/Calculation.php b/Classes/PHPExcel/Calculation.php index a3f7be2..01cfb7c 100644 --- a/Classes/PHPExcel/Calculation.php +++ b/Classes/PHPExcel/Calculation.php @@ -3486,6 +3486,13 @@ class PHPExcel_Calculation { private function _validateBinaryOperand($cellID, &$operand, &$stack) { + if (is_array($operand)) { + if ((count($operand, COUNT_RECURSIVE) - count($operand)) == 1) { + do { + $operand = array_pop($operand); + } while (is_array($operand)); + } + } // Numbers, matrices and booleans can pass straight through, as they're already valid if (is_string($operand)) { // We only need special validations for the operand if it is a string @@ -3591,25 +3598,13 @@ class PHPExcel_Calculation { if (!$this->_validateBinaryOperand($cellID,$operand1,$stack)) return FALSE; if (!$this->_validateBinaryOperand($cellID,$operand2,$stack)) return FALSE; - $executeMatrixOperation = FALSE; // If either of the operands is a matrix, we need to treat them both as matrices // (converting the other operand to a matrix if need be); then perform the required // matrix operation if ((is_array($operand1)) || (is_array($operand2))) { - // Ensure that both operands are arrays/matrices - $executeMatrixOperation = TRUE; - $mSize = array(); - list($mSize[],$mSize[],$mSize[],$mSize[]) = self::_checkMatrixOperands($operand1,$operand2,2); + // Ensure that both operands are arrays/matrices of the same size + self::_checkMatrixOperands($operand1, $operand2, 2); - // But if they're both single cell matrices, then we can treat them as simple values - if (array_sum($mSize) == 4) { - $executeMatrixOperation = FALSE; - $operand1 = $operand1[0][0]; - $operand2 = $operand2[0][0]; - } - } - - if ($executeMatrixOperation) { try { // Convert operand 1 from a PHP array to a matrix $matrix = new PHPExcel_Shared_JAMA_Matrix($operand1); From 90eff17853bfbfce0502bae903a6fc9814ffa097 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 16 Jun 2013 21:34:17 +0100 Subject: [PATCH 4/7] Performance tweaks --- Classes/PHPExcel/Worksheet.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/PHPExcel/Worksheet.php b/Classes/PHPExcel/Worksheet.php index 3094fb3..257fc7a 100644 --- a/Classes/PHPExcel/Worksheet.php +++ b/Classes/PHPExcel/Worksheet.php @@ -1054,7 +1054,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable */ public function setCellValueByColumnAndRow($pColumn = 0, $pRow = 1, $pValue = null, $returnCell = false) { - $cell = $this->getCell(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow)->setValue($pValue); + $cell = $this->getCellByColumnAndRow($pColumn, $pRow)->setValue($pValue); return ($returnCell) ? $cell : $this; } @@ -1086,7 +1086,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable */ public function setCellValueExplicitByColumnAndRow($pColumn = 0, $pRow = 1, $pValue = null, $pDataType = PHPExcel_Cell_DataType::TYPE_STRING, $returnCell = false) { - $cell = $this->getCell(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow)->setValueExplicit($pValue, $pDataType); + $cell = $this->getCellByColumnAndRow($pColumn, $pRow)->setValueExplicit($pValue, $pDataType); return ($returnCell) ? $cell : $this; } From 6216d2855cac16c6adcd8f8f39bb81fd163c9cea Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 16 Jun 2013 21:35:35 +0100 Subject: [PATCH 5/7] Performance tweaks --- Classes/PHPExcel/Worksheet.php | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Classes/PHPExcel/Worksheet.php b/Classes/PHPExcel/Worksheet.php index 3094fb3..19d8953 100644 --- a/Classes/PHPExcel/Worksheet.php +++ b/Classes/PHPExcel/Worksheet.php @@ -1142,18 +1142,15 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $this->_cachedHighestRow = max($this->_cachedHighestRow,$aCoordinates[1]); // Cell needs appropriate xfIndex - $rowDimensions = $this->getRowDimensions(); - $columnDimensions = $this->getColumnDimensions(); + $rowDimension = $this->getRowDimension($aCoordinates[1], FALSE); + $columnDimension = $this->getColumnDimension($aCoordinates[0], FALSE); - if ( isset($rowDimensions[$aCoordinates[1]]) && $rowDimensions[$aCoordinates[1]]->getXfIndex() !== null ) { + if ($rowDimension !== NULL && $rowDimension->getXfIndex() > 0) { // then there is a row dimension with explicit style, assign it to the cell - $cell->setXfIndex($rowDimensions[$aCoordinates[1]]->getXfIndex()); - } else if ( isset($columnDimensions[$aCoordinates[0]]) ) { + $cell->setXfIndex($rowDimension->getXfIndex()); + } elseif ($columnDimension !== NULL && $columnDimension->getXfIndex() > 0) { // then there is a column dimension, assign it to the cell - $cell->setXfIndex($columnDimensions[$aCoordinates[0]]->getXfIndex()); - } else { - // set to default index - $cell->setXfIndex(0); + $cell->setXfIndex($columnDimension->getXfIndex()); } return $cell; @@ -1253,13 +1250,15 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * @param int $pRow Numeric index of the row * @return PHPExcel_Worksheet_RowDimension */ - public function getRowDimension($pRow = 1) + public function getRowDimension($pRow = 1, $create = TRUE) { // Found $found = null; // Get row dimension if (!isset($this->_rowDimensions[$pRow])) { + if (!$create) + return NULL; $this->_rowDimensions[$pRow] = new PHPExcel_Worksheet_RowDimension($pRow); $this->_cachedHighestRow = max($this->_cachedHighestRow,$pRow); @@ -1273,13 +1272,15 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * @param string $pColumn String index of the column * @return PHPExcel_Worksheet_ColumnDimension */ - public function getColumnDimension($pColumn = 'A') + public function getColumnDimension($pColumn = 'A', $create = TRUE) { // Uppercase coordinate $pColumn = strtoupper($pColumn); // Fetch dimensions if (!isset($this->_columnDimensions[$pColumn])) { + if (!$create) + return NULL; $this->_columnDimensions[$pColumn] = new PHPExcel_Worksheet_ColumnDimension($pColumn); if (PHPExcel_Cell::columnIndexFromString($this->_cachedHighestColumn) < PHPExcel_Cell::columnIndexFromString($pColumn)) From 98e5ac2b240471d08586ed6798589c8ee903af30 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Mon, 17 Jun 2013 11:37:29 +0100 Subject: [PATCH 6/7] Performance improvements --- Classes/PHPExcel/Worksheet.php | 87 ++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/Classes/PHPExcel/Worksheet.php b/Classes/PHPExcel/Worksheet.php index 338dcca..bd5dc17 100644 --- a/Classes/PHPExcel/Worksheet.php +++ b/Classes/PHPExcel/Worksheet.php @@ -1123,38 +1123,14 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable // Uppercase coordinate $pCoordinate = strtoupper($pCoordinate); - if (strpos($pCoordinate,':') !== false || strpos($pCoordinate,',') !== false) { + if (strpos($pCoordinate, ':') !== false || strpos($pCoordinate, ',') !== false) { throw new PHPExcel_Exception('Cell coordinate can not be a range of cells.'); - } elseif (strpos($pCoordinate,'$') !== false) { + } elseif (strpos($pCoordinate, '$') !== false) { throw new PHPExcel_Exception('Cell coordinate must not be absolute.'); - } else { - // Create new cell object - - // Coordinates - $aCoordinates = PHPExcel_Cell::coordinateFromString($pCoordinate); - - $cell = $this->_cellCollection->addCacheData($pCoordinate,new PHPExcel_Cell(NULL, PHPExcel_Cell_DataType::TYPE_NULL, $this)); - $this->_cellCollectionIsSorted = false; - - if (PHPExcel_Cell::columnIndexFromString($this->_cachedHighestColumn) < PHPExcel_Cell::columnIndexFromString($aCoordinates[0])) - $this->_cachedHighestColumn = $aCoordinates[0]; - - $this->_cachedHighestRow = max($this->_cachedHighestRow,$aCoordinates[1]); - - // Cell needs appropriate xfIndex - $rowDimension = $this->getRowDimension($aCoordinates[1], FALSE); - $columnDimension = $this->getColumnDimension($aCoordinates[0], FALSE); - - if ($rowDimension !== NULL && $rowDimension->getXfIndex() > 0) { - // then there is a row dimension with explicit style, assign it to the cell - $cell->setXfIndex($rowDimension->getXfIndex()); - } elseif ($columnDimension !== NULL && $columnDimension->getXfIndex() > 0) { - // then there is a column dimension, assign it to the cell - $cell->setXfIndex($columnDimension->getXfIndex()); - } - - return $cell; } + + // Create new cell object + return $this->_createNewCell($pCoordinate); } /** @@ -1169,21 +1145,52 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $columnLetter = PHPExcel_Cell::stringFromColumnIndex($pColumn); $coordinate = $columnLetter . $pRow; - if (!$this->_cellCollection->isDataSet($coordinate)) { - $cell = $this->_cellCollection->addCacheData($coordinate, new PHPExcel_Cell(NULL, PHPExcel_Cell_DataType::TYPE_NULL, $this)); - $this->_cellCollectionIsSorted = false; - - if (PHPExcel_Cell::columnIndexFromString($this->_cachedHighestColumn) < $pColumn) - $this->_cachedHighestColumn = $columnLetter; - - $this->_cachedHighestRow = max($this->_cachedHighestRow,$pRow); - - return $cell; + if ($this->_cellCollection->isDataSet($coordinate)) { + return $this->_cellCollection->getCacheData($coordinate); } - return $this->_cellCollection->getCacheData($coordinate); + return $this->_createNewCell($coordinate); } + /** + * Create a new cell at the specified coordinate + * + * @param string $pCoordinate Coordinate of the cell + * @return PHPExcel_Cell Cell that was created + */ + private function _createNewCell($pCoordinate) + { + $cell = $this->_cellCollection->addCacheData( + $pCoordinate, + new PHPExcel_Cell( + NULL, + PHPExcel_Cell_DataType::TYPE_NULL, + $this + ) + ); + $this->_cellCollectionIsSorted = false; + + // Coordinates + $aCoordinates = PHPExcel_Cell::coordinateFromString($pCoordinate); + if (PHPExcel_Cell::columnIndexFromString($this->_cachedHighestColumn) < PHPExcel_Cell::columnIndexFromString($aCoordinates[0])) + $this->_cachedHighestColumn = $aCoordinates[0]; + $this->_cachedHighestRow = max($this->_cachedHighestRow, $aCoordinates[1]); + + // Cell needs appropriate xfIndex + $rowDimension = $this->getRowDimension($aCoordinates[1], FALSE); + $columnDimension = $this->getColumnDimension($aCoordinates[0], FALSE); + + if ($rowDimension !== NULL && $rowDimension->getXfIndex() > 0) { + // then there is a row dimension with explicit style, assign it to the cell + $cell->setXfIndex($rowDimension->getXfIndex()); + } elseif ($columnDimension !== NULL && $columnDimension->getXfIndex() > 0) { + // then there is a column dimension, assign it to the cell + $cell->setXfIndex($columnDimension->getXfIndex()); + } + + return $cell; + } + /** * Cell at a specific coordinate exists? * From da7cd71be894aabb8d5b70e820e3c9ffec38ea70 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Mon, 17 Jun 2013 12:01:51 +0100 Subject: [PATCH 7/7] Minor performance tweaks --- Classes/PHPExcel/Worksheet.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Classes/PHPExcel/Worksheet.php b/Classes/PHPExcel/Worksheet.php index bd5dc17..4c7b239 100644 --- a/Classes/PHPExcel/Worksheet.php +++ b/Classes/PHPExcel/Worksheet.php @@ -1176,7 +1176,8 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $this->_cachedHighestColumn = $aCoordinates[0]; $this->_cachedHighestRow = max($this->_cachedHighestRow, $aCoordinates[1]); - // Cell needs appropriate xfIndex + // Cell needs appropriate xfIndex from dimensions records + // but don't create dimension records if they don't already exist $rowDimension = $this->getRowDimension($aCoordinates[1], FALSE); $columnDimension = $this->getColumnDimension($aCoordinates[0], FALSE); @@ -1192,7 +1193,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable } /** - * Cell at a specific coordinate exists? + * Does the cell at a specific coordinate exist? * * @param string $pCoordinate Coordinate of the cell * @throws PHPExcel_Exception