Skip to content

Commit

Permalink
Merge pull request #3 from PHPOffice/master
Browse files Browse the repository at this point in the history
Sync Up With Base
  • Loading branch information
oleibman authored May 25, 2020
2 parents 7d58ba8 + 5a92a5f commit 79d024f
Show file tree
Hide file tree
Showing 39 changed files with 545 additions and 226 deletions.
2 changes: 1 addition & 1 deletion .scrutinizer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ build:

tools:
external_code_coverage:
timeout: 3600
timeout: 600

build_failure_conditions:
- 'elements.rating(<= C).new.exists' # No new classes/methods with a rating of C or worse allowed
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
- Fix RATE, PRICE, XIRR, and XNPV Functions [#1456](https://github.com/PHPOffice/PhpSpreadsheet/pull/1456)
- Save Excel 2010+ functions properly in XLSX [#1461](https://github.com/PHPOffice/PhpSpreadsheet/pull/1461)
- Several improvements in HTML writer [#1464](https://github.com/PHPOffice/PhpSpreadsheet/pull/1464)
- Fix incorrect behaviour when saving XLSX file with drawings [#1462](https://github.com/PHPOffice/PhpSpreadsheet/pull/1462),
- Fix Crash while trying setting a cell the value "123456\n" [#1476](https://github.com/PHPOffice/PhpSpreadsheet/pull/1481)

### Changed

Expand Down
1 change: 1 addition & 0 deletions samples/Basic/07_Reader.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@

// Save
$helper->write($spreadsheet, __FILE__);
unlink($filename);
12 changes: 8 additions & 4 deletions samples/Basic/16_Csv.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
<?php

use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Csv as CsvReader;
use PhpOffice\PhpSpreadsheet\Writer\Csv as CsvWriter;

require __DIR__ . '/../Header.php';
$spreadsheet = require __DIR__ . '/../templates/sampleSpreadsheet.php';

$helper->log('Write to CSV format');
/** @var \PhpOffice\PhpSpreadsheet\Writer\Csv $writer */
$writer = IOFactory::createWriter($spreadsheet, 'Csv')->setDelimiter(',')
$writer = new CsvWriter($spreadsheet);
$writer->setDelimiter(',')
->setEnclosure('"')
->setSheetIndex(0);

Expand All @@ -19,21 +21,23 @@
$helper->log('Read from CSV format');

/** @var \PhpOffice\PhpSpreadsheet\Reader\Csv $reader */
$reader = IOFactory::createReader('Csv')->setDelimiter(',')
$reader = new CsvReader();
$reader->setDelimiter(',')
->setEnclosure('"')
->setSheetIndex(0);

$callStartTime = microtime(true);
$spreadsheetFromCSV = $reader->load($filename);
$helper->logRead('Csv', $filename, $callStartTime);
unlink($filename);

// Write Xlsx
$helper->write($spreadsheetFromCSV, __FILE__, ['Xlsx']);

// Write CSV
$filenameCSV = $helper->getFilename(__FILE__, 'csv');
/** @var \PhpOffice\PhpSpreadsheet\Writer\Csv $writerCSV */
$writerCSV = IOFactory::createWriter($spreadsheetFromCSV, 'Csv');
$writerCSV = new CsvWriter($spreadsheetFromCSV);
$writerCSV->setExcelCompatibility(true);

$callStartTime = microtime(true);
Expand Down
1 change: 1 addition & 0 deletions samples/Basic/20_Read_Xls.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
$callStartTime = microtime(true);
$spreadsheet = IOFactory::load($filename);
$helper->logRead('Xls', $filename, $callStartTime);
unlink($filename);

// Save
$helper->write($spreadsheet, __FILE__);
4 changes: 3 additions & 1 deletion samples/Basic/24_Readfilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace PhpOffice\PhpSpreadsheet;

use PhpOffice\PhpSpreadsheet\Reader\IReadFilter;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

require __DIR__ . '/../Header.php';
Expand All @@ -29,10 +30,11 @@ public function readCell($column, $row, $worksheetName = '')
}

$helper->log('Load from Xlsx file');
$reader = IOFactory::createReader('Xlsx');
$reader = new XlsxReader();
$reader->setReadFilter(new MyReadFilter());
$callStartTime = microtime(true);
$spreadsheet = $reader->load($filename);
unlink($filename);
$helper->logRead('Xlsx', $filename, $callStartTime);
$helper->log('Remove unnecessary rows');
$spreadsheet->getActiveSheet()->removeRow(2, 18);
Expand Down
9 changes: 5 additions & 4 deletions samples/Basic/28_Iterator.php
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
<?php

use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XLsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XLsxWriter;

require __DIR__ . '/../Header.php';

$sampleSpreadsheet = require __DIR__ . '/../templates/sampleSpreadsheet.php';
$filename = $helper->getTemporaryFilename();
$writer = new Xlsx($sampleSpreadsheet);
$writer = new XlsxWriter($sampleSpreadsheet);
$callStartTime = microtime(true);
$writer->save($filename);
$helper->logWrite($writer, $filename, $callStartTime);

$callStartTime = microtime(true);
$reader = IOFactory::createReader('Xlsx');
$reader = new XlsxReader();
$spreadsheet = $reader->load($filename);
$helper->logRead('Xlsx', $filename, $callStartTime);
unlink($filename);
$helper->log('Iterate worksheets');
foreach ($spreadsheet->getWorksheetIterator() as $worksheet) {
$helper->log('Worksheet - ' . $worksheet->getTitle());
Expand Down
2 changes: 2 additions & 0 deletions samples/Basic/44_Worksheet_info.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@

$helper->log('Worksheet Names:');
var_dump($sheetInfo);

unlink($filename);
12 changes: 7 additions & 5 deletions samples/Chart/34_Chart_update.php
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
<?php

use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;

require __DIR__ . '/../Header.php';

// Create temporary file that will be read
$sampleSpreadsheet = require __DIR__ . '/../templates/chartSpreadsheet.php';
$filename = $helper->getTemporaryFilename();
$writer = new Xlsx($sampleSpreadsheet);
$writer = new XlsxWriter($sampleSpreadsheet);
$writer->setIncludeCharts(true);
$writer->save($filename);

$helper->log('Load from Xlsx file');
$reader = IOFactory::createReader('Xlsx');
$reader = new XlsxReader();
$reader->setIncludeCharts(true);
$spreadsheet = $reader->load($filename);
unlink($filename);

$helper->log('Update cell data values that are displayed in the chart');
$worksheet = $spreadsheet->getActiveSheet();
Expand All @@ -31,7 +33,7 @@

// Save Excel 2007 file
$filename = $helper->getFilename(__FILE__);
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer = new XlsxWriter($spreadsheet);
$writer->setIncludeCharts(true);
$callStartTime = microtime(true);
$writer->save($filename);
Expand Down
70 changes: 40 additions & 30 deletions src/PhpSpreadsheet/Calculation/Calculation.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ class Calculation
const RETURN_ARRAY_AS_VALUE = 'value';
const RETURN_ARRAY_AS_ARRAY = 'array';

const FORMULA_OPEN_FUNCTION_BRACE = '{';
const FORMULA_CLOSE_FUNCTION_BRACE = '}';
const FORMULA_STRING_QUOTE = '"';

private static $returnArrayAsType = self::RETURN_ARRAY_AS_VALUE;

/**
Expand Down Expand Up @@ -2593,11 +2597,11 @@ public static function translateSeparator($fromSeparator, $toSeparator, $formula
for ($i = 0; $i < $strlen; ++$i) {
$chr = mb_substr($formula, $i, 1);
switch ($chr) {
case '{':
case self::FORMULA_OPEN_FUNCTION_BRACE:
$inBraces = true;

break;
case '}':
case self::FORMULA_CLOSE_FUNCTION_BRACE:
$inBraces = false;

break;
Expand Down Expand Up @@ -2626,10 +2630,10 @@ private static function translateFormula(array $from, array $to, $formula, $from
if (self::$localeLanguage !== 'en_us') {
$inBraces = false;
// If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
if (strpos($formula, '"') !== false) {
if (strpos($formula, self::FORMULA_STRING_QUOTE) !== false) {
// So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
// the formula
$temp = explode('"', $formula);
$temp = explode(self::FORMULA_STRING_QUOTE, $formula);
$i = false;
foreach ($temp as &$value) {
// Only count/replace in alternating array entries
Expand All @@ -2640,7 +2644,7 @@ private static function translateFormula(array $from, array $to, $formula, $from
}
unset($value);
// Then rebuild the formula string
$formula = implode('"', $temp);
$formula = implode(self::FORMULA_STRING_QUOTE, $temp);
} else {
// If there's no quoted strings, then we do a simple count/replace
$formula = preg_replace($from, $to, $formula);
Expand Down Expand Up @@ -2741,7 +2745,7 @@ public static function wrapResult($value)
return $value;
}
// Return strings wrapped in quotes
return '"' . $value . '"';
return self::FORMULA_STRING_QUOTE . $value . self::FORMULA_STRING_QUOTE;
// Convert numeric errors to NaN error
} elseif ((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) {
return Functions::NAN();
Expand All @@ -2760,7 +2764,7 @@ public static function wrapResult($value)
public static function unwrapResult($value)
{
if (is_string($value)) {
if ((isset($value[0])) && ($value[0] == '"') && (substr($value, -1) == '"')) {
if ((isset($value[0])) && ($value[0] == self::FORMULA_STRING_QUOTE) && (substr($value, -1) == self::FORMULA_STRING_QUOTE)) {
return substr($value, 1, -1);
}
// Convert numeric errors to NAN error
Expand Down Expand Up @@ -3227,8 +3231,8 @@ private function showValue($value)
}

return '{ ' . implode($rpad, $returnMatrix) . ' }';
} elseif (is_string($value) && (trim($value, '"') == $value)) {
return '"' . $value . '"';
} elseif (is_string($value) && (trim($value, self::FORMULA_STRING_QUOTE) == $value)) {
return self::FORMULA_STRING_QUOTE . $value . self::FORMULA_STRING_QUOTE;
} elseif (is_bool($value)) {
return ($value) ? self::$localeBoolean['TRUE'] : self::$localeBoolean['FALSE'];
}
Expand Down Expand Up @@ -3282,34 +3286,34 @@ private function showTypeDetails($value)
*/
private function convertMatrixReferences($formula)
{
static $matrixReplaceFrom = ['{', ';', '}'];
static $matrixReplaceFrom = [self::FORMULA_OPEN_FUNCTION_BRACE, ';', self::FORMULA_CLOSE_FUNCTION_BRACE];
static $matrixReplaceTo = ['MKMATRIX(MKMATRIX(', '),MKMATRIX(', '))'];

// Convert any Excel matrix references to the MKMATRIX() function
if (strpos($formula, '{') !== false) {
if (strpos($formula, self::FORMULA_OPEN_FUNCTION_BRACE) !== false) {
// If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
if (strpos($formula, '"') !== false) {
if (strpos($formula, self::FORMULA_STRING_QUOTE) !== false) {
// So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
// the formula
$temp = explode('"', $formula);
$temp = explode(self::FORMULA_STRING_QUOTE, $formula);
// Open and Closed counts used for trapping mismatched braces in the formula
$openCount = $closeCount = 0;
$i = false;
foreach ($temp as &$value) {
// Only count/replace in alternating array entries
if ($i = !$i) {
$openCount += substr_count($value, '{');
$closeCount += substr_count($value, '}');
$openCount += substr_count($value, self::FORMULA_OPEN_FUNCTION_BRACE);
$closeCount += substr_count($value, self::FORMULA_CLOSE_FUNCTION_BRACE);
$value = str_replace($matrixReplaceFrom, $matrixReplaceTo, $value);
}
}
unset($value);
// Then rebuild the formula string
$formula = implode('"', $temp);
$formula = implode(self::FORMULA_STRING_QUOTE, $temp);
} else {
// If there's no quoted strings, then we do a simple count/replace
$openCount = substr_count($formula, '{');
$closeCount = substr_count($formula, '}');
$openCount = substr_count($formula, self::FORMULA_OPEN_FUNCTION_BRACE);
$closeCount = substr_count($formula, self::FORMULA_CLOSE_FUNCTION_BRACE);
$formula = str_replace($matrixReplaceFrom, $matrixReplaceTo, $formula);
}
// Trap for mismatched braces and trigger an appropriate error
Expand Down Expand Up @@ -3715,9 +3719,9 @@ private function _parseFormula($formula, ?Cell $pCell = null)
}

$localeConstant = false;
if ($opCharacter == '"') {
if ($opCharacter == self::FORMULA_STRING_QUOTE) {
// UnEscape any quotes within the string
$val = self::wrapResult(str_replace('""', '"', self::unwrapResult($val)));
$val = self::wrapResult(str_replace('""', self::FORMULA_STRING_QUOTE, self::unwrapResult($val)));
} elseif (is_numeric($val)) {
if ((strpos($val, '.') !== false) || (stripos($val, 'e') !== false) || ($val > PHP_INT_MAX) || ($val < -PHP_INT_MAX)) {
$val = (float) $val;
Expand Down Expand Up @@ -4058,7 +4062,7 @@ private function processTokenStack($tokens, $cellID = null, ?Cell $pCell = null)
$result = '#VALUE!';
}
} else {
$result = '"' . str_replace('""', '"', self::unwrapResult($operand1) . self::unwrapResult($operand2)) . '"';
$result = self::FORMULA_STRING_QUOTE . str_replace('""', self::FORMULA_STRING_QUOTE, self::unwrapResult($operand1) . self::unwrapResult($operand2)) . self::FORMULA_STRING_QUOTE;
}
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($result));
$stack->push('Value', $result);
Expand All @@ -4078,9 +4082,15 @@ private function processTokenStack($tokens, $cellID = null, ?Cell $pCell = null)
$cellIntersect[$row] = array_intersect_key($operand1[$row], $operand2[$row]);
}
}
$cellRef = Coordinate::stringFromColumnIndex(min($oCol) + 1) . min($oRow) . ':' . Coordinate::stringFromColumnIndex(max($oCol) + 1) . max($oRow);
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($cellIntersect));
$stack->push('Value', $cellIntersect, $cellRef);
if (count(Functions::flattenArray($cellIntersect)) === 0) {
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($cellIntersect));
$stack->push('Error', Functions::null(), null);
} else {
$cellRef = Coordinate::stringFromColumnIndex(min($oCol) + 1) . min($oRow) . ':' .
Coordinate::stringFromColumnIndex(max($oCol) + 1) . max($oRow);
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($cellIntersect));
$stack->push('Value', $cellIntersect, $cellRef);
}

break;
}
Expand Down Expand Up @@ -4284,7 +4294,7 @@ private function processTokenStack($tokens, $cellID = null, ?Cell $pCell = null)
$branchStore[$storeKey] = self::$excelConstants[$excelConstant];
}
$this->debugLog->writeDebugLog('Evaluating Constant ', $excelConstant, ' as ', $this->showTypeDetails(self::$excelConstants[$excelConstant]));
} elseif ((is_numeric($token)) || ($token === null) || (is_bool($token)) || ($token == '') || ($token[0] == '"') || ($token[0] == '#')) {
} elseif ((is_numeric($token)) || ($token === null) || (is_bool($token)) || ($token == '') || ($token[0] == self::FORMULA_STRING_QUOTE) || ($token[0] == '#')) {
$stack->push('Value', $token);
if (isset($storeKey)) {
$branchStore[$storeKey] = $token;
Expand Down Expand Up @@ -4329,7 +4339,7 @@ private function validateBinaryOperand(&$operand, &$stack)
if (is_string($operand)) {
// We only need special validations for the operand if it is a string
// Start by stripping off the quotation marks we use to identify true excel string values internally
if ($operand > '' && $operand[0] == '"') {
if ($operand > '' && $operand[0] == self::FORMULA_STRING_QUOTE) {
$operand = self::unwrapResult($operand);
}
// If the string is a numeric value, we treat it as a numeric, so no further testing
Expand All @@ -4342,7 +4352,7 @@ private function validateBinaryOperand(&$operand, &$stack)
return false;
} elseif (!Shared\StringHelper::convertToNumberIfFraction($operand)) {
// If not a numeric or a fraction, then it's a text string, and so can't be used in mathematical binary operations
$stack->push('Value', '#VALUE!');
$stack->push('Error', '#VALUE!');
$this->debugLog->writeDebugLog('Evaluation Result is a ', $this->showTypeDetails('#VALUE!'));

return false;
Expand Down Expand Up @@ -4402,10 +4412,10 @@ private function executeBinaryComparisonOperation($cellID, $operand1, $operand2,
}

// Simple validate the two operands if they are string values
if (is_string($operand1) && $operand1 > '' && $operand1[0] == '"') {
if (is_string($operand1) && $operand1 > '' && $operand1[0] == self::FORMULA_STRING_QUOTE) {
$operand1 = self::unwrapResult($operand1);
}
if (is_string($operand2) && $operand2 > '' && $operand2[0] == '"') {
if (is_string($operand2) && $operand2 > '' && $operand2[0] == self::FORMULA_STRING_QUOTE) {
$operand2 = self::unwrapResult($operand2);
}

Expand Down Expand Up @@ -4570,7 +4580,7 @@ private function executeNumericBinaryOperation($operand1, $operand2, $operation,
case '/':
if ($operand2 == 0) {
// Trap for Divide by Zero error
$stack->push('Value', '#DIV/0!');
$stack->push('Error', '#DIV/0!');
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails('#DIV/0!'));

return false;
Expand Down
2 changes: 2 additions & 0 deletions src/PhpSpreadsheet/Calculation/MathTrig.php
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,8 @@ public static function SUM(...$args)
// Is it a numeric value?
if ((is_numeric($arg)) && (!is_string($arg))) {
$returnValue += $arg;
} elseif (Functions::isError($arg)) {
return $arg;
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/PhpSpreadsheet/Cell/DefaultValueBinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public static function dataTypeForValue($pValue)
return DataType::TYPE_STRING;
} elseif ((strpos($pValue, '.') === false) && ($pValue > PHP_INT_MAX)) {
return DataType::TYPE_STRING;
} elseif (!is_numeric($pValue)) {
return DataType::TYPE_STRING;
}

return DataType::TYPE_NUMERIC;
Expand Down
Loading

0 comments on commit 79d024f

Please sign in to comment.