Skip to content

Commit 79d024f

Browse files
authored
Merge pull request #3 from PHPOffice/master
Sync Up With Base
2 parents 7d58ba8 + 5a92a5f commit 79d024f

39 files changed

+545
-226
lines changed

.scrutinizer.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ build:
1818

1919
tools:
2020
external_code_coverage:
21-
timeout: 3600
21+
timeout: 600
2222

2323
build_failure_conditions:
2424
- 'elements.rating(<= C).new.exists' # No new classes/methods with a rating of C or worse allowed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
1919
- Fix RATE, PRICE, XIRR, and XNPV Functions [#1456](https://github.com/PHPOffice/PhpSpreadsheet/pull/1456)
2020
- Save Excel 2010+ functions properly in XLSX [#1461](https://github.com/PHPOffice/PhpSpreadsheet/pull/1461)
2121
- Several improvements in HTML writer [#1464](https://github.com/PHPOffice/PhpSpreadsheet/pull/1464)
22+
- Fix incorrect behaviour when saving XLSX file with drawings [#1462](https://github.com/PHPOffice/PhpSpreadsheet/pull/1462),
23+
- Fix Crash while trying setting a cell the value "123456\n" [#1476](https://github.com/PHPOffice/PhpSpreadsheet/pull/1481)
2224

2325
### Changed
2426

samples/Basic/07_Reader.php

+1
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@
1717

1818
// Save
1919
$helper->write($spreadsheet, __FILE__);
20+
unlink($filename);

samples/Basic/16_Csv.php

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
<?php
22

3-
use PhpOffice\PhpSpreadsheet\IOFactory;
3+
use PhpOffice\PhpSpreadsheet\Reader\Csv as CsvReader;
4+
use PhpOffice\PhpSpreadsheet\Writer\Csv as CsvWriter;
45

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

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

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

2123
/** @var \PhpOffice\PhpSpreadsheet\Reader\Csv $reader */
22-
$reader = IOFactory::createReader('Csv')->setDelimiter(',')
24+
$reader = new CsvReader();
25+
$reader->setDelimiter(',')
2326
->setEnclosure('"')
2427
->setSheetIndex(0);
2528

2629
$callStartTime = microtime(true);
2730
$spreadsheetFromCSV = $reader->load($filename);
2831
$helper->logRead('Csv', $filename, $callStartTime);
32+
unlink($filename);
2933

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

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

3943
$callStartTime = microtime(true);

samples/Basic/20_Read_Xls.php

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
$callStartTime = microtime(true);
1818
$spreadsheet = IOFactory::load($filename);
1919
$helper->logRead('Xls', $filename, $callStartTime);
20+
unlink($filename);
2021

2122
// Save
2223
$helper->write($spreadsheet, __FILE__);

samples/Basic/24_Readfilter.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PhpOffice\PhpSpreadsheet;
44

55
use PhpOffice\PhpSpreadsheet\Reader\IReadFilter;
6+
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
67
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
78

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

3132
$helper->log('Load from Xlsx file');
32-
$reader = IOFactory::createReader('Xlsx');
33+
$reader = new XlsxReader();
3334
$reader->setReadFilter(new MyReadFilter());
3435
$callStartTime = microtime(true);
3536
$spreadsheet = $reader->load($filename);
37+
unlink($filename);
3638
$helper->logRead('Xlsx', $filename, $callStartTime);
3739
$helper->log('Remove unnecessary rows');
3840
$spreadsheet->getActiveSheet()->removeRow(2, 18);

samples/Basic/28_Iterator.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
<?php
22

3-
use PhpOffice\PhpSpreadsheet\IOFactory;
4-
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
3+
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XLsxReader;
4+
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XLsxWriter;
55

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

88
$sampleSpreadsheet = require __DIR__ . '/../templates/sampleSpreadsheet.php';
99
$filename = $helper->getTemporaryFilename();
10-
$writer = new Xlsx($sampleSpreadsheet);
10+
$writer = new XlsxWriter($sampleSpreadsheet);
1111
$callStartTime = microtime(true);
1212
$writer->save($filename);
1313
$helper->logWrite($writer, $filename, $callStartTime);
1414

1515
$callStartTime = microtime(true);
16-
$reader = IOFactory::createReader('Xlsx');
16+
$reader = new XlsxReader();
1717
$spreadsheet = $reader->load($filename);
1818
$helper->logRead('Xlsx', $filename, $callStartTime);
19+
unlink($filename);
1920
$helper->log('Iterate worksheets');
2021
foreach ($spreadsheet->getWorksheetIterator() as $worksheet) {
2122
$helper->log('Worksheet - ' . $worksheet->getTitle());

samples/Basic/44_Worksheet_info.php

+2
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,5 @@
2424

2525
$helper->log('Worksheet Names:');
2626
var_dump($sheetInfo);
27+
28+
unlink($filename);

samples/Chart/34_Chart_update.php

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
<?php
22

3-
use PhpOffice\PhpSpreadsheet\IOFactory;
4-
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
3+
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
4+
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
55

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

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

1415
$helper->log('Load from Xlsx file');
15-
$reader = IOFactory::createReader('Xlsx');
16+
$reader = new XlsxReader();
1617
$reader->setIncludeCharts(true);
1718
$spreadsheet = $reader->load($filename);
19+
unlink($filename);
1820

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

3234
// Save Excel 2007 file
3335
$filename = $helper->getFilename(__FILE__);
34-
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
36+
$writer = new XlsxWriter($spreadsheet);
3537
$writer->setIncludeCharts(true);
3638
$callStartTime = microtime(true);
3739
$writer->save($filename);

src/PhpSpreadsheet/Calculation/Calculation.php

+40-30
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ class Calculation
3737
const RETURN_ARRAY_AS_VALUE = 'value';
3838
const RETURN_ARRAY_AS_ARRAY = 'array';
3939

40+
const FORMULA_OPEN_FUNCTION_BRACE = '{';
41+
const FORMULA_CLOSE_FUNCTION_BRACE = '}';
42+
const FORMULA_STRING_QUOTE = '"';
43+
4044
private static $returnArrayAsType = self::RETURN_ARRAY_AS_VALUE;
4145

4246
/**
@@ -2593,11 +2597,11 @@ public static function translateSeparator($fromSeparator, $toSeparator, $formula
25932597
for ($i = 0; $i < $strlen; ++$i) {
25942598
$chr = mb_substr($formula, $i, 1);
25952599
switch ($chr) {
2596-
case '{':
2600+
case self::FORMULA_OPEN_FUNCTION_BRACE:
25972601
$inBraces = true;
25982602

25992603
break;
2600-
case '}':
2604+
case self::FORMULA_CLOSE_FUNCTION_BRACE:
26012605
$inBraces = false;
26022606

26032607
break;
@@ -2626,10 +2630,10 @@ private static function translateFormula(array $from, array $to, $formula, $from
26262630
if (self::$localeLanguage !== 'en_us') {
26272631
$inBraces = false;
26282632
// If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
2629-
if (strpos($formula, '"') !== false) {
2633+
if (strpos($formula, self::FORMULA_STRING_QUOTE) !== false) {
26302634
// So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
26312635
// the formula
2632-
$temp = explode('"', $formula);
2636+
$temp = explode(self::FORMULA_STRING_QUOTE, $formula);
26332637
$i = false;
26342638
foreach ($temp as &$value) {
26352639
// Only count/replace in alternating array entries
@@ -2640,7 +2644,7 @@ private static function translateFormula(array $from, array $to, $formula, $from
26402644
}
26412645
unset($value);
26422646
// Then rebuild the formula string
2643-
$formula = implode('"', $temp);
2647+
$formula = implode(self::FORMULA_STRING_QUOTE, $temp);
26442648
} else {
26452649
// If there's no quoted strings, then we do a simple count/replace
26462650
$formula = preg_replace($from, $to, $formula);
@@ -2741,7 +2745,7 @@ public static function wrapResult($value)
27412745
return $value;
27422746
}
27432747
// Return strings wrapped in quotes
2744-
return '"' . $value . '"';
2748+
return self::FORMULA_STRING_QUOTE . $value . self::FORMULA_STRING_QUOTE;
27452749
// Convert numeric errors to NaN error
27462750
} elseif ((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) {
27472751
return Functions::NAN();
@@ -2760,7 +2764,7 @@ public static function wrapResult($value)
27602764
public static function unwrapResult($value)
27612765
{
27622766
if (is_string($value)) {
2763-
if ((isset($value[0])) && ($value[0] == '"') && (substr($value, -1) == '"')) {
2767+
if ((isset($value[0])) && ($value[0] == self::FORMULA_STRING_QUOTE) && (substr($value, -1) == self::FORMULA_STRING_QUOTE)) {
27642768
return substr($value, 1, -1);
27652769
}
27662770
// Convert numeric errors to NAN error
@@ -3227,8 +3231,8 @@ private function showValue($value)
32273231
}
32283232

32293233
return '{ ' . implode($rpad, $returnMatrix) . ' }';
3230-
} elseif (is_string($value) && (trim($value, '"') == $value)) {
3231-
return '"' . $value . '"';
3234+
} elseif (is_string($value) && (trim($value, self::FORMULA_STRING_QUOTE) == $value)) {
3235+
return self::FORMULA_STRING_QUOTE . $value . self::FORMULA_STRING_QUOTE;
32323236
} elseif (is_bool($value)) {
32333237
return ($value) ? self::$localeBoolean['TRUE'] : self::$localeBoolean['FALSE'];
32343238
}
@@ -3282,34 +3286,34 @@ private function showTypeDetails($value)
32823286
*/
32833287
private function convertMatrixReferences($formula)
32843288
{
3285-
static $matrixReplaceFrom = ['{', ';', '}'];
3289+
static $matrixReplaceFrom = [self::FORMULA_OPEN_FUNCTION_BRACE, ';', self::FORMULA_CLOSE_FUNCTION_BRACE];
32863290
static $matrixReplaceTo = ['MKMATRIX(MKMATRIX(', '),MKMATRIX(', '))'];
32873291

32883292
// Convert any Excel matrix references to the MKMATRIX() function
3289-
if (strpos($formula, '{') !== false) {
3293+
if (strpos($formula, self::FORMULA_OPEN_FUNCTION_BRACE) !== false) {
32903294
// If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
3291-
if (strpos($formula, '"') !== false) {
3295+
if (strpos($formula, self::FORMULA_STRING_QUOTE) !== false) {
32923296
// So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
32933297
// the formula
3294-
$temp = explode('"', $formula);
3298+
$temp = explode(self::FORMULA_STRING_QUOTE, $formula);
32953299
// Open and Closed counts used for trapping mismatched braces in the formula
32963300
$openCount = $closeCount = 0;
32973301
$i = false;
32983302
foreach ($temp as &$value) {
32993303
// Only count/replace in alternating array entries
33003304
if ($i = !$i) {
3301-
$openCount += substr_count($value, '{');
3302-
$closeCount += substr_count($value, '}');
3305+
$openCount += substr_count($value, self::FORMULA_OPEN_FUNCTION_BRACE);
3306+
$closeCount += substr_count($value, self::FORMULA_CLOSE_FUNCTION_BRACE);
33033307
$value = str_replace($matrixReplaceFrom, $matrixReplaceTo, $value);
33043308
}
33053309
}
33063310
unset($value);
33073311
// Then rebuild the formula string
3308-
$formula = implode('"', $temp);
3312+
$formula = implode(self::FORMULA_STRING_QUOTE, $temp);
33093313
} else {
33103314
// If there's no quoted strings, then we do a simple count/replace
3311-
$openCount = substr_count($formula, '{');
3312-
$closeCount = substr_count($formula, '}');
3315+
$openCount = substr_count($formula, self::FORMULA_OPEN_FUNCTION_BRACE);
3316+
$closeCount = substr_count($formula, self::FORMULA_CLOSE_FUNCTION_BRACE);
33133317
$formula = str_replace($matrixReplaceFrom, $matrixReplaceTo, $formula);
33143318
}
33153319
// Trap for mismatched braces and trigger an appropriate error
@@ -3715,9 +3719,9 @@ private function _parseFormula($formula, ?Cell $pCell = null)
37153719
}
37163720

37173721
$localeConstant = false;
3718-
if ($opCharacter == '"') {
3722+
if ($opCharacter == self::FORMULA_STRING_QUOTE) {
37193723
// UnEscape any quotes within the string
3720-
$val = self::wrapResult(str_replace('""', '"', self::unwrapResult($val)));
3724+
$val = self::wrapResult(str_replace('""', self::FORMULA_STRING_QUOTE, self::unwrapResult($val)));
37213725
} elseif (is_numeric($val)) {
37223726
if ((strpos($val, '.') !== false) || (stripos($val, 'e') !== false) || ($val > PHP_INT_MAX) || ($val < -PHP_INT_MAX)) {
37233727
$val = (float) $val;
@@ -4058,7 +4062,7 @@ private function processTokenStack($tokens, $cellID = null, ?Cell $pCell = null)
40584062
$result = '#VALUE!';
40594063
}
40604064
} else {
4061-
$result = '"' . str_replace('""', '"', self::unwrapResult($operand1) . self::unwrapResult($operand2)) . '"';
4065+
$result = self::FORMULA_STRING_QUOTE . str_replace('""', self::FORMULA_STRING_QUOTE, self::unwrapResult($operand1) . self::unwrapResult($operand2)) . self::FORMULA_STRING_QUOTE;
40624066
}
40634067
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($result));
40644068
$stack->push('Value', $result);
@@ -4078,9 +4082,15 @@ private function processTokenStack($tokens, $cellID = null, ?Cell $pCell = null)
40784082
$cellIntersect[$row] = array_intersect_key($operand1[$row], $operand2[$row]);
40794083
}
40804084
}
4081-
$cellRef = Coordinate::stringFromColumnIndex(min($oCol) + 1) . min($oRow) . ':' . Coordinate::stringFromColumnIndex(max($oCol) + 1) . max($oRow);
4082-
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($cellIntersect));
4083-
$stack->push('Value', $cellIntersect, $cellRef);
4085+
if (count(Functions::flattenArray($cellIntersect)) === 0) {
4086+
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($cellIntersect));
4087+
$stack->push('Error', Functions::null(), null);
4088+
} else {
4089+
$cellRef = Coordinate::stringFromColumnIndex(min($oCol) + 1) . min($oRow) . ':' .
4090+
Coordinate::stringFromColumnIndex(max($oCol) + 1) . max($oRow);
4091+
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($cellIntersect));
4092+
$stack->push('Value', $cellIntersect, $cellRef);
4093+
}
40844094

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

43484358
return false;
@@ -4402,10 +4412,10 @@ private function executeBinaryComparisonOperation($cellID, $operand1, $operand2,
44024412
}
44034413

44044414
// Simple validate the two operands if they are string values
4405-
if (is_string($operand1) && $operand1 > '' && $operand1[0] == '"') {
4415+
if (is_string($operand1) && $operand1 > '' && $operand1[0] == self::FORMULA_STRING_QUOTE) {
44064416
$operand1 = self::unwrapResult($operand1);
44074417
}
4408-
if (is_string($operand2) && $operand2 > '' && $operand2[0] == '"') {
4418+
if (is_string($operand2) && $operand2 > '' && $operand2[0] == self::FORMULA_STRING_QUOTE) {
44094419
$operand2 = self::unwrapResult($operand2);
44104420
}
44114421

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

45764586
return false;

src/PhpSpreadsheet/Calculation/MathTrig.php

+2
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,8 @@ public static function SUM(...$args)
13391339
// Is it a numeric value?
13401340
if ((is_numeric($arg)) && (!is_string($arg))) {
13411341
$returnValue += $arg;
1342+
} elseif (Functions::isError($arg)) {
1343+
return $arg;
13421344
}
13431345
}
13441346

src/PhpSpreadsheet/Cell/DefaultValueBinder.php

+2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ public static function dataTypeForValue($pValue)
6565
return DataType::TYPE_STRING;
6666
} elseif ((strpos($pValue, '.') === false) && ($pValue > PHP_INT_MAX)) {
6767
return DataType::TYPE_STRING;
68+
} elseif (!is_numeric($pValue)) {
69+
return DataType::TYPE_STRING;
6870
}
6971

7072
return DataType::TYPE_NUMERIC;

0 commit comments

Comments
 (0)