diff --git a/Examples/.gitignore b/Examples/.gitignore index 1888a98f..10192af2 100644 --- a/Examples/.gitignore +++ b/Examples/.gitignore @@ -1,3 +1,5 @@ - *.xls -*.xlsx \ No newline at end of file +*.xlsx +*.csv +*.jpg +*.pdf \ No newline at end of file diff --git a/Examples/01simple.php b/Examples/01simple.php index 5ff6fc13..b4a62494 100644 --- a/Examples/01simple.php +++ b/Examples/01simple.php @@ -78,6 +78,21 @@ $objPHPExcel->getActiveSheet() ->setWrapText(true); +$value = "-ValueA\n-Value B\n-Value C"; +$objPHPExcel->getActiveSheet() + ->setCellValue('A10', $value); +$objPHPExcel->getActiveSheet() + ->getRowDimension(10) + ->setRowHeight(-1); +$objPHPExcel->getActiveSheet() + ->getStyle('A10') + ->getAlignment() + ->setWrapText(true); +$objPHPExcel->getActiveSheet() + ->getStyle('A10') + ->setQuotePrefix(true); + + // Rename worksheet echo date('H:i:s') , " Rename worksheet" , EOL; $objPHPExcel->getActiveSheet() diff --git a/composer.json b/composer.json index 940deec1..68c1da44 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ } ], "require": { - "php": ">=5.4.0", + "php": "^5.4|^7.0", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*" diff --git a/src/PhpSpreadsheet/Calculation.php b/src/PhpSpreadsheet/Calculation.php index 269fabcf..2b12ee7d 100644 --- a/src/PhpSpreadsheet/Calculation.php +++ b/src/PhpSpreadsheet/Calculation.php @@ -203,10 +203,10 @@ class Calculation /** * Epsilon Precision used for comparisons in calculations * - * @var integer + * @var float * */ - private $delta = 0.0000000000001; + private $delta = 0.1e-12; /** @@ -1490,7 +1490,7 @@ class Calculation 'OFFSET' => array( 'category' => Calculation\Categories::CATEGORY_LOOKUP_AND_REFERENCE, 'functionCall' => '\\PHPExcel\\Calculation\\LookupRef::OFFSET', - 'argumentCount' => '3,5', + 'argumentCount' => '3-5', 'passCellReference' => true, 'passByReference' => array(true) ), @@ -2061,14 +2061,10 @@ class Calculation ); - private function __construct(Spreadsheet $spreadsheet = null) + public function __construct(Spreadsheet $spreadsheet = null) { $this->delta = 1 * pow(10, 0 - ini_get('precision')); - if ($spreadsheet !== null) { - self::$spreadsheetSets[$spreadsheet->getID()] = $this; - } - $this->spreadsheet = $spreadsheet; $this->cyclicReferenceStack = new CalcEngine\CyclicReferenceStack(); $this->_debugLog = new CalcEngine\Logger($this->cyclicReferenceStack); @@ -2097,10 +2093,10 @@ class Calculation public static function getInstance(Spreadsheet $spreadsheet = null) { if ($spreadsheet !== null) { - if (isset(self::$spreadsheetSets[$spreadsheet->getID()])) { - return self::$spreadsheetSets[$spreadsheet->getID()]; + $instance = $workbook->getCalculationEngine(); + if (isset($instance)) { + return $instance; } - return new Calculation($spreadsheet); } if (!isset(self::$instance) || (self::$instance === null)) { @@ -2116,13 +2112,9 @@ class Calculation * @access public * @param Spreadsheet $spreadsheet Injected spreadsheet identifying the instance to unset */ - public static function unsetInstance(Spreadsheet $spreadsheet = null) + public function __destruct() { - if ($spreadsheet !== null) { - if (isset(self::$spreadsheetSets[$spreadsheet->getID()])) { - unset(self::$spreadsheetSets[$spreadsheet->getID()]); - } - } + $this->workbook = null; } /** diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index 126b8f07..ce50f91f 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -2139,8 +2139,8 @@ class Financial if ((!is_array($values)) && (!is_array($dates))) { return Functions::VALUE(); } - $values = Functions::flattenArray($values); - $dates = Functions::flattenArray($dates); + $values = Functions::flattenArray($values); + $dates = Functions::flattenArray($dates); $guess = Functions::flattenSingleValue($guess); if (count($values) != count($dates)) { return Functions::NaN(); diff --git a/src/PhpSpreadsheet/Calculation/Functions.php b/src/PhpSpreadsheet/Calculation/Functions.php index c0dc853b..dfbff0a5 100644 --- a/src/PhpSpreadsheet/Calculation/Functions.php +++ b/src/PhpSpreadsheet/Calculation/Functions.php @@ -546,10 +546,8 @@ class Functions case 'float': case 'integer': return $value; - break; case 'boolean': return (integer) $value; - break; case 'string': // Errors if ((strlen($value) > 0) && ($value{0} == '#')) { diff --git a/src/PhpSpreadsheet/Reader/Excel2003XML.php b/src/PhpSpreadsheet/Reader/Excel2003XML.php index 8ba1c0f6..51d696fb 100644 --- a/src/PhpSpreadsheet/Reader/Excel2003XML.php +++ b/src/PhpSpreadsheet/Reader/Excel2003XML.php @@ -406,11 +406,7 @@ class Excel2003XML extends BaseReader implements IReader $style_ss = $style->attributes($namespaces['ss']); $styleID = (string) $style_ss['ID']; // echo 'Style ID = '.$styleID.'
'; - if ($styleID == 'Default') { - $this->styles['Default'] = array(); - } else { - $this->styles[$styleID] = $this->styles['Default']; - } + $this->styles[$styleID] = (isset($this->styles['Default'])) ? $this->styles['Default'] : array(); foreach ($style as $styleType => $styleData) { $styleAttributes = $styleData->attributes($namespaces['ss']); // echo $styleType.'
'; diff --git a/src/PhpSpreadsheet/Reader/Excel2007.php b/src/PhpSpreadsheet/Reader/Excel2007.php index 27b3c9bb..e1331c26 100644 --- a/src/PhpSpreadsheet/Reader/Excel2007.php +++ b/src/PhpSpreadsheet/Reader/Excel2007.php @@ -339,10 +339,17 @@ class Excel2007 extends BaseReader implements IReader } $fileName = \PHPExcel\Shared\File::realpath($fileName); + // Sadly, some 3rd party xlsx generators don't use consistent case for filenaming + // so we need to load case-insensitively from the zip file + // Apache POI fixes - $contents = $archive->getFromName($fileName); + $contents = $archive->getFromIndex( + $archive->locateName($fileName, ZIPARCHIVE::FL_NOCASE) + ); if ($contents === false) { - $contents = $archive->getFromName(substr($fileName, 1)); + $contents = $archive->getFromIndex( + $archive->locateName(substr($fileName, 1), ZIPARCHIVE::FL_NOCASE) + ); } return $contents; diff --git a/src/PhpSpreadsheet/Reader/Excel2007/Chart.php b/src/PhpSpreadsheet/Reader/Excel2007/Chart.php index 81c9b4b7..ae86bbbb 100644 --- a/src/PhpSpreadsheet/Reader/Excel2007/Chart.php +++ b/src/PhpSpreadsheet/Reader/Excel2007/Chart.php @@ -346,10 +346,6 @@ class Chart } } - if (empty($seriesVal)) { - $seriesVal = null; - } - return array( 'formatCode' => $formatCode, 'pointCount' => $pointCount, diff --git a/src/PhpSpreadsheet/Reader/Excel5.php b/src/PhpSpreadsheet/Reader/Excel5.php index 7243a717..cf2cfb78 100644 --- a/src/PhpSpreadsheet/Reader/Excel5.php +++ b/src/PhpSpreadsheet/Reader/Excel5.php @@ -1733,16 +1733,16 @@ class Excel5 extends BaseReader implements IReader if ($length != 54) { throw new Exception('Unexpected file pass record length'); } - + $recordData = $this->readRecordData($this->data, $this->pos + 4, $length); - + // move stream pointer to next record $this->pos += 4 + $length; - + if (!$this->verifyPassword('VelvetSweatshop', substr($recordData, 6, 16), substr($recordData, 22, 16), substr($recordData, 38, 16), $this->md5Ctxt)) { throw new Exception('Decryption password incorrect'); } - + $this->encryption = self::MS_BIFF_CRYPTO_RC4; // Decryption required from the record after next onwards diff --git a/src/PhpSpreadsheet/Reader/HTML.php b/src/PhpSpreadsheet/Reader/HTML.php index 7efc4496..e24478f8 100644 --- a/src/PhpSpreadsheet/Reader/HTML.php +++ b/src/PhpSpreadsheet/Reader/HTML.php @@ -486,7 +486,7 @@ class HTML extends BaseReader implements IReader // Create a new DOM object $dom = new domDocument; // Reload the HTML file into the DOM object - $loaded = $dom->loadHTML($this->securityScanFile($pFilename)); + $loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanFile($pFilename), 'HTML-ENTITIES', 'UTF-8')); if ($loaded === false) { throw new Exception('Failed to load ', $pFilename, ' as a DOM Document'); } diff --git a/src/PhpSpreadsheet/Shared/ZipArchive.php b/src/PhpSpreadsheet/Shared/ZipArchive.php index 03fe528b..981eeebd 100644 --- a/src/PhpSpreadsheet/Shared/ZipArchive.php +++ b/src/PhpSpreadsheet/Shared/ZipArchive.php @@ -110,17 +110,19 @@ class ZipArchive */ public function locateName($fileName) { + $fileName = strtolower($fileName); + $list = $this->zip->listContent(); $listCount = count($list); - $list_index = -1; + $index = -1; for ($i = 0; $i < $listCount; ++$i) { if (strtolower($list[$i]["filename"]) == strtolower($fileName) || strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) { - $list_index = $i; + $index = $i; break; } } - return ($list_index > -1); + return ($index > -1) ? $index : false; } /** @@ -131,36 +133,32 @@ class ZipArchive */ public function getFromName($fileName) { - $list = $this->zip->listContent(); - $listCount = count($list); - $list_index = -1; - for ($i = 0; $i < $listCount; ++$i) { - if (strtolower($list[$i]["filename"]) == strtolower($fileName) || - strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) { - $list_index = $i; - break; + $index = $this->locateName($fileName); + + if ($index !== false) { + $extracted = $this->getFromIndex($index); + } else { + $fileName = substr($fileName, 1); + $index = $this->locateName($fileName); + if ($index === false) { + return false; } + $extracted = $this->zip->getFromIndex($index); } - $extracted = ""; - if ($list_index != -1) { - $extracted = $this->zip->extractByIndex($list_index, PCLZIP_OPT_EXTRACT_AS_STRING); - } else { - $filename = substr($fileName, 1); - $list_index = -1; - for ($i = 0; $i < $listCount; ++$i) { - if (strtolower($list[$i]["filename"]) == strtolower($fileName) || - strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) { - $list_index = $i; - break; - } - } - $extracted = $this->zip->extractByIndex($list_index, PCLZIP_OPT_EXTRACT_AS_STRING); - } + $contents = $extracted; if ((is_array($extracted)) && ($extracted != 0)) { $contents = $extracted[0]["content"]; } return $contents; } + + public function getFromIndex($index) { + $extracted = $this->zip->extractByIndex($index, PCLZIP_OPT_EXTRACT_AS_STRING); + $contents = ''; + if ((is_array($extracted)) && ($extracted != 0)) { + $contents = $extracted[0]["content"]; + } + } } diff --git a/src/PhpSpreadsheet/Spreadsheet.php b/src/PhpSpreadsheet/Spreadsheet.php index 0223b78c..a2d27a23 100644 --- a/src/PhpSpreadsheet/Spreadsheet.php +++ b/src/PhpSpreadsheet/Spreadsheet.php @@ -360,7 +360,7 @@ class Spreadsheet public function __construct() { $this->uniqueID = uniqid(); - $this->calculationEngine = Calculation::getInstance($this); + $this->calculationEngine = new Calculation($this); // Initialise worksheet collection and add one worksheet $this->workSheetCollection = array(); @@ -391,7 +391,7 @@ class Spreadsheet */ public function __destruct() { - Calculation::unsetInstance($this); + $this->calculationEngine = null; $this->disconnectWorksheets(); } diff --git a/src/PhpSpreadsheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet.php index f1f5256c..78cc071c 100644 --- a/src/PhpSpreadsheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet.php @@ -863,10 +863,10 @@ class Worksheet implements IComparable $this->title = $pValue; $this->dirty = true; - if ($this->parent) { + if ($this->parent && $this->parent->getCalculationEngine()) { // New title $newTitle = $this->getTitle(); - Calculation::getInstance($this->parent) + $this->parent->getCalculationEngine() ->renameCalculationCacheForWorksheet($oldTitle, $newTitle); if ($updateFormulaCellReferences) { ReferenceHelper::getInstance()->updateNamedFormulas($this->parent, $oldTitle, $newTitle); diff --git a/src/PhpSpreadsheet/Worksheet/ColumnIterator.php b/src/PhpSpreadsheet/Worksheet/ColumnIterator.php index 9146c982..a8e82914 100644 --- a/src/PhpSpreadsheet/Worksheet/ColumnIterator.php +++ b/src/PhpSpreadsheet/Worksheet/ColumnIterator.php @@ -66,7 +66,7 @@ class ColumnIterator implements \Iterator * @param string $startColumn The column address at which to start iterating * @param string $endColumn Optionally, the column address at which to stop iterating */ - public function __construct(\PHPExcel\Worksheet $subject = null, $startColumn = 'A', $endColumn = null) + public function __construct(\PHPExcel\Worksheet $subject, $startColumn = 'A', $endColumn = null) { // Set subject $this->subject = $subject; @@ -87,11 +87,19 @@ class ColumnIterator implements \Iterator * * @param integer $startColumn The column address at which to start iterating * @return ColumnIterator + * @throws PHPExcel_Exception */ public function resetStart($startColumn = 'A') { $startColumnIndex = \PHPExcel\Cell::columnIndexFromString($startColumn) - 1; + if ($startColumnIndex > PHPExcel_Cell::columnIndexFromString($this->subject->getHighestColumn()) - 1) { + throw new PHPExcel_Exception("Start column ({$startColumn}) is beyond highest column ({$this->subject->getHighestColumn()})"); + } + $this->startColumn = $startColumnIndex; + if ($this->endColumn < $this->startColumn) { + $this->endColumn = $this->startColumn; + } $this->seek($startColumn); return $this; diff --git a/src/PhpSpreadsheet/Worksheet/RowIterator.php b/src/PhpSpreadsheet/Worksheet/RowIterator.php index d5bc0cc8..80c887f8 100644 --- a/src/PhpSpreadsheet/Worksheet/RowIterator.php +++ b/src/PhpSpreadsheet/Worksheet/RowIterator.php @@ -66,7 +66,7 @@ class RowIterator implements \Iterator * @param integer $startRow The row number at which to start iterating * @param integer $endRow Optionally, the row number at which to stop iterating */ - public function __construct(\PHPExcel\Worksheet $subject = null, $startRow = 1, $endRow = null) + public function __construct(\PHPExcel\Worksheet $subject, $startRow = 1, $endRow = null) { // Set subject $this->subject = $subject; @@ -87,10 +87,18 @@ class RowIterator implements \Iterator * * @param integer $startRow The row number at which to start iterating * @return RowIterator + * @throws PHPExcel_Exception */ public function resetStart($startRow = 1) { + if ($startRow > $this->subject->getHighestRow()) { + throw new PHPExcel_Exception("Start row ({$startRow}) is beyond highest row ({$this->subject->getHighestRow()})"); + } + $this->startRow = $startRow; + if ($this->endRow < $this->startRow) { + $this->endRow = $this->startRow; + } $this->seek($startRow); return $this; diff --git a/src/PhpSpreadsheet/Writer/Excel2007.php b/src/PhpSpreadsheet/Writer/Excel2007.php index 0f91b9e0..738b2600 100644 --- a/src/PhpSpreadsheet/Writer/Excel2007.php +++ b/src/PhpSpreadsheet/Writer/Excel2007.php @@ -290,7 +290,7 @@ class Excel2007 extends BaseWriter implements IWriter $charts = $this->spreadSheet->getSheet($i)->getChartCollection(); if (count($charts) > 0) { foreach ($charts as $chart) { - $objZip->addFromString('xl/charts/chart' . ($chartCount + 1) . '.xml', $this->getWriterPart('Chart')->writeChart($chart)); + $objZip->addFromString('xl/charts/chart' . ($chartCount + 1) . '.xml', $this->getWriterPart('Chart')->writeChart($chart, $this->preCalculateFormulas)); $chartCount++; } } diff --git a/src/PhpSpreadsheet/Writer/Excel2007/Chart.php b/src/PhpSpreadsheet/Writer/Excel2007/Chart.php index d4afb4fc..35a36a5e 100644 --- a/src/PhpSpreadsheet/Writer/Excel2007/Chart.php +++ b/src/PhpSpreadsheet/Writer/Excel2007/Chart.php @@ -28,6 +28,8 @@ namespace PHPExcel\Writer\Excel2007; */ class Chart extends WriterPart { + protected $calculateCellValues; + /** * Write charts to XML format * @@ -36,8 +38,10 @@ class Chart extends WriterPart * @return string XML Output * @throws \PHPExcel\Writer\Exception */ - public function writeChart(PHPExcel_Chart $pChart = null) + public function writeChart(PHPExcel_Chart $pChart = null, $calculateCellValues = true) { + $this->calculateCellValues = $calculateCellValues; + // Create XML writer $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { @@ -46,7 +50,9 @@ class Chart extends WriterPart $objWriter = new \PHPExcel\Shared\XMLWriter(\PHPExcel\Shared\XMLWriter::STORAGE_MEMORY); } // Ensure that data series values are up-to-date before we save - $pChart->refresh(); + if ($this->calculateCellValues) { + $pChart->refresh(); + } // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); diff --git a/src/PhpSpreadsheet/Writer/Excel2007/Rels.php b/src/PhpSpreadsheet/Writer/Excel2007/Rels.php index ed8298d5..57332bc0 100644 --- a/src/PhpSpreadsheet/Writer/Excel2007/Rels.php +++ b/src/PhpSpreadsheet/Writer/Excel2007/Rels.php @@ -89,7 +89,7 @@ class Rels extends WriterPart ); // a custom UI in workbook ? if ($pPHPExcel->hasRibbon()) { - $this->_writeRelationShip( + $this->writeRelationShip( $objWriter, 5, 'http://schemas.microsoft.com/office/2006/relationships/ui/extensibility', @@ -163,7 +163,7 @@ class Rels extends WriterPart // Relationships for vbaProject if needed // id : just after the last sheet if ($pPHPExcel->hasMacros()) { - $this->_writeRelationShip( + $this->writeRelationShip( $objWriter, ($i + 1 + 3), 'http://schemas.microsoft.com/office/2006/relationships/vbaProject',