commit
79d024fec0
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -17,3 +17,4 @@ $helper->logRead('Xlsx', $filename, $callStartTime);
|
|||
|
||||
// Save
|
||||
$helper->write($spreadsheet, __FILE__);
|
||||
unlink($filename);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -19,13 +21,15 @@ $helper->logWrite($writer, $filename, $callStartTime);
|
|||
$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']);
|
||||
|
@ -33,7 +37,7 @@ $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);
|
||||
|
|
|
@ -17,6 +17,7 @@ $helper->logWrite($writer, $filename, $callStartTime);
|
|||
$callStartTime = microtime(true);
|
||||
$spreadsheet = IOFactory::load($filename);
|
||||
$helper->logRead('Xls', $filename, $callStartTime);
|
||||
unlink($filename);
|
||||
|
||||
// Save
|
||||
$helper->write($spreadsheet, __FILE__);
|
||||
|
|
|
@ -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';
|
||||
|
@ -29,10 +30,11 @@ class MyReadFilter implements IReadFilter
|
|||
}
|
||||
|
||||
$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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -24,3 +24,5 @@ var_dump($sheetList);
|
|||
|
||||
$helper->log('Worksheet Names:');
|
||||
var_dump($sheetInfo);
|
||||
|
||||
unlink($filename);
|
||||
|
|
|
@ -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();
|
||||
|
@ -31,7 +33,7 @@ $worksheet->fromArray(
|
|||
|
||||
// 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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -2593,11 +2597,11 @@ class Calculation
|
|||
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;
|
||||
|
@ -2626,10 +2630,10 @@ class Calculation
|
|||
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
|
||||
|
@ -2640,7 +2644,7 @@ class Calculation
|
|||
}
|
||||
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);
|
||||
|
@ -2741,7 +2745,7 @@ class Calculation
|
|||
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();
|
||||
|
@ -2760,7 +2764,7 @@ class Calculation
|
|||
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
|
||||
|
@ -3227,8 +3231,8 @@ class Calculation
|
|||
}
|
||||
|
||||
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'];
|
||||
}
|
||||
|
@ -3282,34 +3286,34 @@ class Calculation
|
|||
*/
|
||||
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
|
||||
|
@ -3715,9 +3719,9 @@ class Calculation
|
|||
}
|
||||
|
||||
$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;
|
||||
|
@ -4058,7 +4062,7 @@ class Calculation
|
|||
$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);
|
||||
|
@ -4078,9 +4082,15 @@ class Calculation
|
|||
$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;
|
||||
}
|
||||
|
@ -4284,7 +4294,7 @@ class Calculation
|
|||
$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;
|
||||
|
@ -4329,7 +4339,7 @@ class Calculation
|
|||
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
|
||||
|
@ -4342,7 +4352,7 @@ class Calculation
|
|||
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;
|
||||
|
@ -4402,10 +4412,10 @@ class Calculation
|
|||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -4570,7 +4580,7 @@ class Calculation
|
|||
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;
|
||||
|
|
|
@ -1339,6 +1339,8 @@ class MathTrig
|
|||
// Is it a numeric value?
|
||||
if ((is_numeric($arg)) && (!is_string($arg))) {
|
||||
$returnValue += $arg;
|
||||
} elseif (Functions::isError($arg)) {
|
||||
return $arg;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,8 @@ class DefaultValueBinder implements IValueBinder
|
|||
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;
|
||||
|
|
|
@ -933,7 +933,12 @@ class Html extends BaseReader
|
|||
*/
|
||||
private function setBorderStyle(Style $cellStyle, $styleValue, $type): void
|
||||
{
|
||||
[, $borderStyle, $color] = explode(' ', $styleValue);
|
||||
if (trim($styleValue) === Border::BORDER_NONE) {
|
||||
$borderStyle = Border::BORDER_NONE;
|
||||
$color = null;
|
||||
} else {
|
||||
[, $borderStyle, $color] = explode(' ', $styleValue);
|
||||
}
|
||||
|
||||
$cellStyle->applyFromArray([
|
||||
'borders' => [
|
||||
|
|
|
@ -1000,12 +1000,13 @@ class Xlsx extends BaseReader
|
|||
Settings::getLibXmlLoaderOptions()
|
||||
);
|
||||
$drawings = [];
|
||||
foreach ($relsVML->Relationship as $ele) {
|
||||
if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
|
||||
$drawings[(string) $ele['Id']] = self::dirAdd($vmlRelationship, $ele['Target']);
|
||||
if (isset($relsVML->Relationship)) {
|
||||
foreach ($relsVML->Relationship as $ele) {
|
||||
if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
|
||||
$drawings[(string) $ele['Id']] = self::dirAdd($vmlRelationship, $ele['Target']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch VML document
|
||||
$vmlDrawing = simplexml_load_string(
|
||||
$this->securityScanner->scan($this->getFromZipArchive($zip, $vmlRelationship)),
|
||||
|
|
|
@ -6,6 +6,65 @@ use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
|
|||
|
||||
class CodePage
|
||||
{
|
||||
private static $pageArray = [
|
||||
0 => 'CP1252', // CodePage is not always correctly set when the xls file was saved by Apple's Numbers program
|
||||
367 => 'ASCII', // ASCII
|
||||
437 => 'CP437', // OEM US
|
||||
//720 => 'notsupported', // OEM Arabic
|
||||
737 => 'CP737', // OEM Greek
|
||||
775 => 'CP775', // OEM Baltic
|
||||
850 => 'CP850', // OEM Latin I
|
||||
852 => 'CP852', // OEM Latin II (Central European)
|
||||
855 => 'CP855', // OEM Cyrillic
|
||||
857 => 'CP857', // OEM Turkish
|
||||
858 => 'CP858', // OEM Multilingual Latin I with Euro
|
||||
860 => 'CP860', // OEM Portugese
|
||||
861 => 'CP861', // OEM Icelandic
|
||||
862 => 'CP862', // OEM Hebrew
|
||||
863 => 'CP863', // OEM Canadian (French)
|
||||
864 => 'CP864', // OEM Arabic
|
||||
865 => 'CP865', // OEM Nordic
|
||||
866 => 'CP866', // OEM Cyrillic (Russian)
|
||||
869 => 'CP869', // OEM Greek (Modern)
|
||||
874 => 'CP874', // ANSI Thai
|
||||
932 => 'CP932', // ANSI Japanese Shift-JIS
|
||||
936 => 'CP936', // ANSI Chinese Simplified GBK
|
||||
949 => 'CP949', // ANSI Korean (Wansung)
|
||||
950 => 'CP950', // ANSI Chinese Traditional BIG5
|
||||
1200 => 'UTF-16LE', // UTF-16 (BIFF8)
|
||||
1250 => 'CP1250', // ANSI Latin II (Central European)
|
||||
1251 => 'CP1251', // ANSI Cyrillic
|
||||
1252 => 'CP1252', // ANSI Latin I (BIFF4-BIFF7)
|
||||
1253 => 'CP1253', // ANSI Greek
|
||||
1254 => 'CP1254', // ANSI Turkish
|
||||
1255 => 'CP1255', // ANSI Hebrew
|
||||
1256 => 'CP1256', // ANSI Arabic
|
||||
1257 => 'CP1257', // ANSI Baltic
|
||||
1258 => 'CP1258', // ANSI Vietnamese
|
||||
1361 => 'CP1361', // ANSI Korean (Johab)
|
||||
10000 => 'MAC', // Apple Roman
|
||||
10001 => 'CP932', // Macintosh Japanese
|
||||
10002 => 'CP950', // Macintosh Chinese Traditional
|
||||
10003 => 'CP1361', // Macintosh Korean
|
||||
10004 => 'MACARABIC', // Apple Arabic
|
||||
10005 => 'MACHEBREW', // Apple Hebrew
|
||||
10006 => 'MACGREEK', // Macintosh Greek
|
||||
10007 => 'MACCYRILLIC', // Macintosh Cyrillic
|
||||
10008 => 'CP936', // Macintosh - Simplified Chinese (GB 2312)
|
||||
10010 => 'MACROMANIA', // Macintosh Romania
|
||||
10017 => 'MACUKRAINE', // Macintosh Ukraine
|
||||
10021 => 'MACTHAI', // Macintosh Thai
|
||||
10029 => 'MACCENTRALEUROPE', // Macintosh Central Europe
|
||||
10079 => 'MACICELAND', // Macintosh Icelandic
|
||||
10081 => 'MACTURKISH', // Macintosh Turkish
|
||||
10082 => 'MACCROATIAN', // Macintosh Croatian
|
||||
21010 => 'UTF-16LE', // UTF-16 (BIFF8) This isn't correct, but some Excel writer libraries erroneously use Codepage 21010 for UTF-16LE
|
||||
32768 => 'MAC', // Apple Roman
|
||||
//32769 => 'unsupported', // ANSI Latin I (BIFF2-BIFF3)
|
||||
65000 => 'UTF-7', // Unicode (UTF-7)
|
||||
65001 => 'UTF-8', // Unicode (UTF-8)
|
||||
];
|
||||
|
||||
/**
|
||||
* Convert Microsoft Code Page Identifier to Code Page Name which iconv
|
||||
* and mbstring understands.
|
||||
|
@ -14,123 +73,20 @@ class CodePage
|
|||
*
|
||||
* @return string Code Page Name
|
||||
*/
|
||||
public static function numberToName($codePage)
|
||||
public static function numberToName(int $codePage): string
|
||||
{
|
||||
switch ($codePage) {
|
||||
case 367:
|
||||
return 'ASCII'; // ASCII
|
||||
case 437:
|
||||
return 'CP437'; // OEM US
|
||||
case 720:
|
||||
throw new PhpSpreadsheetException('Code page 720 not supported.'); // OEM Arabic
|
||||
case 737:
|
||||
return 'CP737'; // OEM Greek
|
||||
case 775:
|
||||
return 'CP775'; // OEM Baltic
|
||||
case 850:
|
||||
return 'CP850'; // OEM Latin I
|
||||
case 852:
|
||||
return 'CP852'; // OEM Latin II (Central European)
|
||||
case 855:
|
||||
return 'CP855'; // OEM Cyrillic
|
||||
case 857:
|
||||
return 'CP857'; // OEM Turkish
|
||||
case 858:
|
||||
return 'CP858'; // OEM Multilingual Latin I with Euro
|
||||
case 860:
|
||||
return 'CP860'; // OEM Portugese
|
||||
case 861:
|
||||
return 'CP861'; // OEM Icelandic
|
||||
case 862:
|
||||
return 'CP862'; // OEM Hebrew
|
||||
case 863:
|
||||
return 'CP863'; // OEM Canadian (French)
|
||||
case 864:
|
||||
return 'CP864'; // OEM Arabic
|
||||
case 865:
|
||||
return 'CP865'; // OEM Nordic
|
||||
case 866:
|
||||
return 'CP866'; // OEM Cyrillic (Russian)
|
||||
case 869:
|
||||
return 'CP869'; // OEM Greek (Modern)
|
||||
case 874:
|
||||
return 'CP874'; // ANSI Thai
|
||||
case 932:
|
||||
return 'CP932'; // ANSI Japanese Shift-JIS
|
||||
case 936:
|
||||
return 'CP936'; // ANSI Chinese Simplified GBK
|
||||
case 949:
|
||||
return 'CP949'; // ANSI Korean (Wansung)
|
||||
case 950:
|
||||
return 'CP950'; // ANSI Chinese Traditional BIG5
|
||||
case 1200:
|
||||
return 'UTF-16LE'; // UTF-16 (BIFF8)
|
||||
case 1250:
|
||||
return 'CP1250'; // ANSI Latin II (Central European)
|
||||
case 1251:
|
||||
return 'CP1251'; // ANSI Cyrillic
|
||||
case 0:
|
||||
// CodePage is not always correctly set when the xls file was saved by Apple's Numbers program
|
||||
case 1252:
|
||||
return 'CP1252'; // ANSI Latin I (BIFF4-BIFF7)
|
||||
case 1253:
|
||||
return 'CP1253'; // ANSI Greek
|
||||
case 1254:
|
||||
return 'CP1254'; // ANSI Turkish
|
||||
case 1255:
|
||||
return 'CP1255'; // ANSI Hebrew
|
||||
case 1256:
|
||||
return 'CP1256'; // ANSI Arabic
|
||||
case 1257:
|
||||
return 'CP1257'; // ANSI Baltic
|
||||
case 1258:
|
||||
return 'CP1258'; // ANSI Vietnamese
|
||||
case 1361:
|
||||
return 'CP1361'; // ANSI Korean (Johab)
|
||||
case 10000:
|
||||
return 'MAC'; // Apple Roman
|
||||
case 10001:
|
||||
return 'CP932'; // Macintosh Japanese
|
||||
case 10002:
|
||||
return 'CP950'; // Macintosh Chinese Traditional
|
||||
case 10003:
|
||||
return 'CP1361'; // Macintosh Korean
|
||||
case 10004:
|
||||
return 'MACARABIC'; // Apple Arabic
|
||||
case 10005:
|
||||
return 'MACHEBREW'; // Apple Hebrew
|
||||
case 10006:
|
||||
return 'MACGREEK'; // Macintosh Greek
|
||||
case 10007:
|
||||
return 'MACCYRILLIC'; // Macintosh Cyrillic
|
||||
case 10008:
|
||||
return 'CP936'; // Macintosh - Simplified Chinese (GB 2312)
|
||||
case 10010:
|
||||
return 'MACROMANIA'; // Macintosh Romania
|
||||
case 10017:
|
||||
return 'MACUKRAINE'; // Macintosh Ukraine
|
||||
case 10021:
|
||||
return 'MACTHAI'; // Macintosh Thai
|
||||
case 10029:
|
||||
return 'MACCENTRALEUROPE'; // Macintosh Central Europe
|
||||
case 10079:
|
||||
return 'MACICELAND'; // Macintosh Icelandic
|
||||
case 10081:
|
||||
return 'MACTURKISH'; // Macintosh Turkish
|
||||
case 10082:
|
||||
return 'MACCROATIAN'; // Macintosh Croatian
|
||||
case 21010:
|
||||
return 'UTF-16LE'; // UTF-16 (BIFF8) This isn't correct, but some Excel writer libraries erroneously use Codepage 21010 for UTF-16LE
|
||||
case 32768:
|
||||
return 'MAC'; // Apple Roman
|
||||
case 32769:
|
||||
throw new PhpSpreadsheetException('Code page 32769 not supported.'); // ANSI Latin I (BIFF2-BIFF3)
|
||||
case 65000:
|
||||
return 'UTF-7'; // Unicode (UTF-7)
|
||||
case 65001:
|
||||
return 'UTF-8'; // Unicode (UTF-8)
|
||||
if (array_key_exists($codePage, self::$pageArray)) {
|
||||
return self::$pageArray[$codePage];
|
||||
}
|
||||
if ($codePage == 720 || $codePage == 32769) {
|
||||
throw new PhpSpreadsheetException("Code page $codePage not supported."); // OEM Arabic
|
||||
}
|
||||
|
||||
throw new PhpSpreadsheetException('Unknown codepage: ' . $codePage);
|
||||
}
|
||||
|
||||
public static function getEncodings(): array
|
||||
{
|
||||
return self::$pageArray;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,10 @@ namespace PhpOffice\PhpSpreadsheet\Shared;
|
|||
|
||||
use DateTimeInterface;
|
||||
use DateTimeZone;
|
||||
use Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
|
||||
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
|
||||
|
||||
class Date
|
||||
|
@ -97,17 +97,18 @@ class Date
|
|||
* @param DateTimeZone|string $timeZone The timezone to set for all Excel datetimestamp to PHP DateTime Object conversions
|
||||
*
|
||||
* @return bool Success or failure
|
||||
* @return bool Success or failure
|
||||
*/
|
||||
public static function setDefaultTimezone($timeZone)
|
||||
{
|
||||
if ($timeZone = self::validateTimeZone($timeZone)) {
|
||||
try {
|
||||
$timeZone = self::validateTimeZone($timeZone);
|
||||
self::$defaultTimeZone = $timeZone;
|
||||
|
||||
return true;
|
||||
$retval = true;
|
||||
} catch (PhpSpreadsheetException $e) {
|
||||
$retval = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,17 +131,17 @@ class Date
|
|||
* @param DateTimeZone|string $timeZone The timezone to validate, either as a timezone string or object
|
||||
*
|
||||
* @return DateTimeZone The timezone as a timezone object
|
||||
* @return DateTimeZone The timezone as a timezone object
|
||||
*/
|
||||
protected static function validateTimeZone($timeZone)
|
||||
private static function validateTimeZone($timeZone)
|
||||
{
|
||||
if (is_object($timeZone) && $timeZone instanceof DateTimeZone) {
|
||||
if ($timeZone instanceof DateTimeZone) {
|
||||
return $timeZone;
|
||||
} elseif (is_string($timeZone)) {
|
||||
}
|
||||
if (in_array($timeZone, DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC))) {
|
||||
return new DateTimeZone($timeZone);
|
||||
}
|
||||
|
||||
throw new Exception('Invalid timezone');
|
||||
throw new PhpSpreadsheetException('Invalid timezone');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -316,7 +317,7 @@ class Date
|
|||
*/
|
||||
public static function isDateTime(Cell $pCell)
|
||||
{
|
||||
return is_numeric($pCell->getValue()) &&
|
||||
return is_numeric($pCell->getCalculatedValue()) &&
|
||||
self::isDateTimeFormat(
|
||||
$pCell->getWorksheet()->getStyle(
|
||||
$pCell->getCoordinate()
|
||||
|
|
|
@ -23,7 +23,7 @@ class TimeZone
|
|||
*/
|
||||
private static function validateTimeZone($timezone)
|
||||
{
|
||||
return in_array($timezone, DateTimeZone::listIdentifiers());
|
||||
return in_array($timezone, DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,10 +73,6 @@ class TimeZone
|
|||
$timezone = self::$timezone;
|
||||
}
|
||||
|
||||
if ($timezone == 'UST') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$objTimezone = new DateTimeZone($timezone);
|
||||
$transitions = $objTimezone->getTransitions($timestamp, $timestamp);
|
||||
|
||||
|
|
|
@ -183,7 +183,6 @@ class Rels extends WriterPart
|
|||
$objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
|
||||
|
||||
// Write drawing relationships?
|
||||
$d = 0;
|
||||
$drawingOriginalIds = [];
|
||||
$unparsedLoadedData = $pWorksheet->getParent()->getUnparsedLoadedData();
|
||||
if (isset($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()]['drawingOriginalIds'])) {
|
||||
|
@ -197,13 +196,19 @@ class Rels extends WriterPart
|
|||
}
|
||||
|
||||
if (($pWorksheet->getDrawingCollection()->count() > 0) || (count($charts) > 0) || $drawingOriginalIds) {
|
||||
$relPath = '../drawings/drawing' . $pWorksheetId . '.xml';
|
||||
$rId = ++$d;
|
||||
$rId = 1;
|
||||
|
||||
// Use original $relPath to get original $rId.
|
||||
// Take first. In future can be overwritten.
|
||||
// (! synchronize with \PhpOffice\PhpSpreadsheet\Writer\Xlsx\Worksheet::writeDrawings)
|
||||
reset($drawingOriginalIds);
|
||||
$relPath = key($drawingOriginalIds);
|
||||
if (isset($drawingOriginalIds[$relPath])) {
|
||||
$rId = (int) (substr($drawingOriginalIds[$relPath], 3));
|
||||
}
|
||||
|
||||
// Generate new $relPath to write drawing relationship
|
||||
$relPath = '../drawings/drawing' . $pWorksheetId . '.xml';
|
||||
$this->writeRelationship(
|
||||
$objWriter,
|
||||
$rId,
|
||||
|
|
|
@ -1215,6 +1215,7 @@ class Worksheet extends WriterPart
|
|||
if (isset($unparsedLoadedData['sheets'][$pSheet->getCodeName()]['drawingOriginalIds'])) {
|
||||
$drawingOriginalIds = $unparsedLoadedData['sheets'][$pSheet->getCodeName()]['drawingOriginalIds'];
|
||||
// take first. In future can be overriten
|
||||
// (! synchronize with \PhpOffice\PhpSpreadsheet\Writer\Xlsx\Rels::writeWorksheetRelationships)
|
||||
$rId = reset($drawingOriginalIds);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,5 +18,6 @@ class DefinedNameConfusedForCellTest extends TestCase
|
|||
$filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test');
|
||||
$writer->save($filename);
|
||||
self::assertTrue(true);
|
||||
unlink($filename);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Engine;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class RangeTest extends TestCase
|
||||
{
|
||||
protected $spreadSheet;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->spreadSheet = new Spreadsheet();
|
||||
$this->spreadSheet->getActiveSheet()
|
||||
->setCellValue('A1', 1)
|
||||
->setCellValue('B1', 2)
|
||||
->setCellValue('C1', 3)
|
||||
->setCellValue('A2', 4)
|
||||
->setCellValue('B2', 5)
|
||||
->setCellValue('C2', 6)
|
||||
->setCellValue('A3', 7)
|
||||
->setCellValue('B3', 8)
|
||||
->setCellValue('C3', 9);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerRangeEvaluation
|
||||
*
|
||||
* @param mixed $formula
|
||||
* @param int $expectedResult
|
||||
*/
|
||||
public function testRangeEvaluation($formula, $expectedResult): void
|
||||
{
|
||||
$workSheet = $this->spreadSheet->getActiveSheet();
|
||||
$workSheet->setCellValue('E1', $formula);
|
||||
|
||||
$actualRresult = $workSheet->getCell('E1')->getCalculatedValue();
|
||||
self::assertSame($expectedResult, $actualRresult);
|
||||
}
|
||||
|
||||
public function providerRangeEvaluation()
|
||||
{
|
||||
return[
|
||||
['=SUM(A1:B3,A1:C2)', 48],
|
||||
['=SUM(A1:B3 A1:C2)', 12],
|
||||
['=SUM(A1:A3,C1:C3)', 30],
|
||||
['=SUM(A1:A3 C1:C3)', Functions::null()],
|
||||
['=SUM(A1:B2,B2:C3)', 40],
|
||||
['=SUM(A1:B2 B2:C3)', 5],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -57,6 +57,7 @@ class DefaultValueBinderTest extends TestCase
|
|||
['#REF!'],
|
||||
[new DateTime()],
|
||||
[new DateTimeImmutable()],
|
||||
['123456\n'],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -200,6 +200,37 @@ EOF;
|
|||
self::assertEquals($expected, $sheet->getCell('B3')->getValue());
|
||||
}
|
||||
|
||||
public function testLineBreakEscape(): void
|
||||
{
|
||||
$reader = new Csv();
|
||||
$spreadsheet = $reader->load('tests/data/Reader/CSV/line_break_in_enclosure_with_escaped_quotes.csv');
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$expected = <<<EOF
|
||||
This is a "test csv file"
|
||||
with both "line breaks"
|
||||
and "escaped
|
||||
quotes" that breaks
|
||||
the delimiters
|
||||
EOF;
|
||||
self::assertEquals($expected, $sheet->getCell('B3')->getValue());
|
||||
}
|
||||
|
||||
public function testUtf32LineBreakEscape(): void
|
||||
{
|
||||
$reader = new Csv();
|
||||
$reader->setInputEncoding('UTF-32LE');
|
||||
$spreadsheet = $reader->load('tests/data/Reader/CSV/line_break_escaped_32le.csv');
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$expected = <<<EOF
|
||||
This is a "test csv file"
|
||||
with both "line breaks"
|
||||
and "escaped
|
||||
quotes" that breaks
|
||||
the delimiters
|
||||
EOF;
|
||||
self::assertEquals($expected, $sheet->getCell('B3')->getValue());
|
||||
}
|
||||
|
||||
public function testSeparatorLine(): void
|
||||
{
|
||||
$reader = new Csv();
|
||||
|
|
|
@ -11,14 +11,6 @@ use PHPUnit\Framework\TestCase;
|
|||
|
||||
class Xlsx2Test extends TestCase
|
||||
{
|
||||
protected function tearDown(): void
|
||||
{
|
||||
$outfile = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test');
|
||||
if (file_exists($outfile)) {
|
||||
unlink($outfile);
|
||||
}
|
||||
}
|
||||
|
||||
public function testLoadXlsxConditionalFormatting2(): void
|
||||
{
|
||||
// Make sure Conditionals are read correctly from existing file
|
||||
|
@ -63,6 +55,7 @@ class Xlsx2Test extends TestCase
|
|||
$writer = IOFactory::createWriter($spreadshee1, 'Xlsx');
|
||||
$writer->save($outfile);
|
||||
$spreadsheet = $reader->load($outfile);
|
||||
unlink($outfile);
|
||||
$worksheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
$conditionalStyle = $worksheet->getConditionalStyles('A2:A8');
|
||||
|
@ -110,6 +103,7 @@ class Xlsx2Test extends TestCase
|
|||
$writer->save($outfile);
|
||||
$reader = IOFactory::createReader('Xlsx');
|
||||
$spreadsheet = $reader->load($outfile);
|
||||
unlink($outfile);
|
||||
$worksheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
$conditionalStyle = $worksheet->getConditionalStyles('A1:A6');
|
||||
|
|
|
@ -222,6 +222,7 @@ class XlsxTest extends TestCase
|
|||
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($excel);
|
||||
$writer->save($resultFilename);
|
||||
$excel = $reader->load($resultFilename);
|
||||
unlink($resultFilename);
|
||||
// Fake assert. The only thing we need is to ensure the file is loaded without exception
|
||||
self::assertNotNull($excel);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,22 @@ class CodePageTest extends TestCase
|
|||
return require 'tests/data/Shared/CodePage.php';
|
||||
}
|
||||
|
||||
public function testCoverage(): void
|
||||
{
|
||||
$covered = [];
|
||||
$expected = CodePage::getEncodings();
|
||||
foreach ($expected as $key => $val) {
|
||||
$covered[$key] = 0;
|
||||
}
|
||||
$tests = $this->providerCodePage();
|
||||
foreach ($tests as $test) {
|
||||
$covered[$test[1]] = 1;
|
||||
}
|
||||
foreach ($covered as $key => $val) {
|
||||
self::assertEquals(1, $val, "Codepage $key not tested");
|
||||
}
|
||||
}
|
||||
|
||||
public function testNumberToNameWithInvalidCodePage(): void
|
||||
{
|
||||
$invalidCodePage = 12345;
|
||||
|
|
|
@ -3,10 +3,23 @@
|
|||
namespace PhpOffice\PhpSpreadsheetTests\Shared;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Shared\Date;
|
||||
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class DateTest extends TestCase
|
||||
{
|
||||
private $dttimezone;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->dttimezone = Date::getDefaultTimeZone();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
Date::setDefaultTimeZone($this->dttimezone);
|
||||
}
|
||||
|
||||
public function testSetExcelCalendar(): void
|
||||
{
|
||||
$calendarValues = [
|
||||
|
@ -168,4 +181,41 @@ class DateTest extends TestCase
|
|||
{
|
||||
return require 'tests/data/Shared/Date/ExcelToTimestamp1900Timezone.php';
|
||||
}
|
||||
|
||||
public function testVarious(): void
|
||||
{
|
||||
Date::setDefaultTimeZone('UTC');
|
||||
self::assertFalse(Date::stringToExcel('2019-02-29'));
|
||||
self::assertTrue((bool) Date::stringToExcel('2019-02-28'));
|
||||
self::assertTrue((bool) Date::stringToExcel('2019-02-28 11:18'));
|
||||
self::assertFalse(Date::stringToExcel('2019-02-28 11:71'));
|
||||
$date = Date::PHPToExcel('2020-01-01');
|
||||
self::assertEquals(43831.0, $date);
|
||||
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->setCellValue('B1', 'x');
|
||||
$val = $sheet->getCell('B1')->getValue();
|
||||
self::assertFalse(Date::timestampToExcel($val));
|
||||
$cell = $sheet->getCell('A1');
|
||||
self::assertNotNull($cell);
|
||||
$cell->setValue($date);
|
||||
$sheet->getStyle('A1')
|
||||
->getNumberFormat()
|
||||
->setFormatCode(NumberFormat::FORMAT_DATE_DATETIME);
|
||||
self::assertTrue(null !== $cell && Date::isDateTime($cell));
|
||||
$cella2 = $sheet->getCell('A2');
|
||||
self::assertNotNull($cella2);
|
||||
$cella2->setValue('=A1+2');
|
||||
$sheet->getStyle('A2')
|
||||
->getNumberFormat()
|
||||
->setFormatCode(NumberFormat::FORMAT_DATE_DATETIME);
|
||||
self::assertTrue(null !== $cella2 && Date::isDateTime($cella2));
|
||||
$cella3 = $sheet->getCell('A3');
|
||||
self::assertNotNull($cella3);
|
||||
$cella3->setValue('=A1+4');
|
||||
$sheet->getStyle('A3')
|
||||
->getNumberFormat()
|
||||
->setFormatCode('0.00E+00');
|
||||
self::assertFalse(null !== $cella3 && Date::isDateTime($cella3));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,29 @@
|
|||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Shared;
|
||||
|
||||
use DateTime;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\Date;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\TimeZone;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class TimeZoneTest extends TestCase
|
||||
{
|
||||
private $tztimezone;
|
||||
|
||||
private $dttimezone;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->tztimezone = TimeZone::getTimeZone();
|
||||
$this->dttimezone = Date::getDefaultTimeZone();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
TimeZone::setTimeZone($this->tztimezone);
|
||||
Date::setDefaultTimeZone($this->dttimezone);
|
||||
}
|
||||
|
||||
public function testSetTimezone(): void
|
||||
{
|
||||
$timezoneValues = [
|
||||
|
@ -20,13 +38,51 @@ class TimeZoneTest extends TestCase
|
|||
foreach ($timezoneValues as $timezoneValue) {
|
||||
$result = TimeZone::setTimezone($timezoneValue);
|
||||
self::assertTrue($result);
|
||||
$result = Date::setDefaultTimezone($timezoneValue);
|
||||
self::assertTrue($result);
|
||||
}
|
||||
}
|
||||
|
||||
public function testSetTimezoneBackwardCompatible(): void
|
||||
{
|
||||
$bcTimezone = 'Etc/GMT+10';
|
||||
$result = TimeZone::setTimezone($bcTimezone);
|
||||
self::assertTrue($result);
|
||||
$result = Date::setDefaultTimezone($bcTimezone);
|
||||
self::assertTrue($result);
|
||||
}
|
||||
|
||||
public function testSetTimezoneWithInvalidValue(): void
|
||||
{
|
||||
$unsupportedTimezone = 'Etc/GMT+10';
|
||||
$unsupportedTimezone = 'XEtc/GMT+10';
|
||||
$result = TimeZone::setTimezone($unsupportedTimezone);
|
||||
self::assertFalse($result);
|
||||
$result = Date::setDefaultTimezone($unsupportedTimezone);
|
||||
self::assertFalse($result);
|
||||
}
|
||||
|
||||
public function testTimeZoneAdjustmentsInvalidTz(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
|
||||
$dtobj = DateTime::createFromFormat('Y-m-d H:i:s', '2008-09-22 00:00:00');
|
||||
$tstmp = $dtobj->getTimestamp();
|
||||
$unsupportedTimeZone = 'XEtc/GMT+10';
|
||||
TimeZone::getTimeZoneAdjustment($unsupportedTimeZone, $tstmp);
|
||||
}
|
||||
|
||||
public function testTimeZoneAdjustments(): void
|
||||
{
|
||||
$dtobj = DateTime::createFromFormat('Y-m-d H:i:s', '2008-01-01 00:00:00');
|
||||
$tstmp = $dtobj->getTimestamp();
|
||||
$supportedTimeZone = 'UTC';
|
||||
$adj = TimeZone::getTimeZoneAdjustment($supportedTimeZone, $tstmp);
|
||||
self::assertEquals(0, $adj);
|
||||
$supportedTimeZone = 'America/Toronto';
|
||||
$adj = TimeZone::getTimeZoneAdjustment($supportedTimeZone, $tstmp);
|
||||
self::assertEquals(-18000, $adj);
|
||||
$supportedTimeZone = 'America/Chicago';
|
||||
TimeZone::setTimeZone($supportedTimeZone);
|
||||
$adj = TimeZone::getTimeZoneAdjustment(null, $tstmp);
|
||||
self::assertEquals(-21600, $adj);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,18 @@ use PhpOffice\PhpSpreadsheetTests\Functional;
|
|||
|
||||
class ImagesRootTest extends Functional\AbstractFunctional
|
||||
{
|
||||
private $curdir;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->curdir = getcwd();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
chdir($this->curdir);
|
||||
}
|
||||
|
||||
public function testImagesRoot(): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
|
@ -20,7 +32,6 @@ class ImagesRootTest extends Functional\AbstractFunctional
|
|||
$newdir = __DIR__ . '/../../../data/Reader/HTML';
|
||||
$stub = 'image.jpg';
|
||||
$imagePath = "./$stub";
|
||||
$curdir = getcwd();
|
||||
chdir($newdir);
|
||||
self::assertFileExists($imagePath);
|
||||
$drawing->setPath($imagePath);
|
||||
|
@ -34,7 +45,6 @@ class ImagesRootTest extends Functional\AbstractFunctional
|
|||
$writer = new Html($spreadsheet);
|
||||
$writer->setImagesRoot($root);
|
||||
$html = $writer->generateHTMLAll();
|
||||
chdir($curdir);
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadHTML($html);
|
||||
$body = $dom->getElementsByTagName('body')[0];
|
||||
|
|
|
@ -30,9 +30,8 @@ class InvalidFileNameTest extends Functional\AbstractFunctional
|
|||
$writer->save('');
|
||||
}
|
||||
|
||||
public function testEmptyTempdirNamePdf(): void
|
||||
public function testNotEmptyTempdirNamePdf(): void
|
||||
{
|
||||
$this->expectException(WriterException::class);
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$spreadsheet->getActiveSheet()->getCell('A1')->setValue('Cell 1');
|
||||
$writer = new Mpdf($spreadsheet);
|
||||
|
@ -41,6 +40,16 @@ class InvalidFileNameTest extends Functional\AbstractFunctional
|
|||
$writer->setPaperSize(PageSetup::PAPERSIZE_LEDGER);
|
||||
self::assertEquals($writer->getPaperSize(), PageSetup::PAPERSIZE_LEDGER);
|
||||
self::assertEquals(File::sysGetTempDir() . '/phpsppdf', $writer->getTempDir());
|
||||
$writer->setTempDir(File::sysGetTempDir());
|
||||
self::assertEquals(File::sysGetTempDir(), $writer->getTempDir());
|
||||
}
|
||||
|
||||
public function testEmptyTempdirNamePdf(): void
|
||||
{
|
||||
$this->expectException(WriterException::class);
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$spreadsheet->getActiveSheet()->getCell('A1')->setValue('Cell 1');
|
||||
$writer = new Mpdf($spreadsheet);
|
||||
$writer->setTempDir('');
|
||||
}
|
||||
|
||||
|
|
|
@ -9,14 +9,6 @@ use PHPUnit\Framework\TestCase;
|
|||
|
||||
class FormulaErrTest extends TestCase
|
||||
{
|
||||
protected function tearDown(): void
|
||||
{
|
||||
$filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test');
|
||||
if (file_exists($filename)) {
|
||||
unlink($filename);
|
||||
}
|
||||
}
|
||||
|
||||
public function testFormulaError(): void
|
||||
{
|
||||
$obj = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
|
||||
|
@ -31,6 +23,7 @@ class FormulaErrTest extends TestCase
|
|||
$writer->save($filename);
|
||||
$reader = IOFactory::createReader('Xls');
|
||||
$robj = $reader->load($filename);
|
||||
unlink($filename);
|
||||
$sheet0 = $robj->setActiveSheetIndex(0);
|
||||
$a1 = $sheet0->getCell('A1')->getCalculatedValue();
|
||||
self::assertEquals(2, $a1);
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
|
||||
use PhpOffice\PhpSpreadsheet\Settings;
|
||||
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
|
||||
|
||||
class DrawingsTest extends AbstractFunctional
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $prevValue;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->prevValue = Settings::getLibXmlLoaderOptions();
|
||||
|
||||
// Disable validating XML with the DTD
|
||||
Settings::setLibXmlLoaderOptions($this->prevValue & ~LIBXML_DTDVALID & ~LIBXML_DTDATTR & ~LIBXML_DTDLOAD);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
Settings::setLibXmlLoaderOptions($this->prevValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test save and load XLSX file with drawing on 2nd worksheet.
|
||||
*/
|
||||
public function testSaveLoadWithDrawingOn2ndWorksheet(): void
|
||||
{
|
||||
// Read spreadsheet from file
|
||||
$inputFilename = 'tests/data/Writer/XLSX/drawing_on_2nd_page.xlsx';
|
||||
$reader = new Xlsx();
|
||||
$spreadsheet = $reader->load($inputFilename);
|
||||
|
||||
// Save spreadsheet to file and read it back
|
||||
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
|
||||
|
||||
// Fake assert. The only thing we need is to ensure the file is loaded without exception
|
||||
self::assertNotNull($reloadedSpreadsheet);
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ class FloatsRetainedTest extends TestCase
|
|||
|
||||
$reader = new Reader();
|
||||
$sheet = $reader->load($outputFilename);
|
||||
unlink($outputFilename);
|
||||
|
||||
self::assertSame($value, $sheet->getActiveSheet()->getCell('A1')->getValue());
|
||||
}
|
||||
|
|
|
@ -73,4 +73,8 @@ return [
|
|||
'e',
|
||||
'#DIV/0!',
|
||||
],
|
||||
[
|
||||
's',
|
||||
'123456\n',
|
||||
],
|
||||
];
|
||||
|
|
Binary file not shown.
Can't render this file because it contains an unexpected character in line 2 and column 24.
|
|
@ -1,21 +1,21 @@
|
|||
Name,Copy,URL
|
||||
Test,"This is a \"test csv file\"
|
||||
with both \"line breaks\"
|
||||
and \"escaped
|
||||
quotes\" that breaks
|
||||
Test,"This is a ""test csv file""
|
||||
with both ""line breaks""
|
||||
and ""escaped
|
||||
quotes"" that breaks
|
||||
the delimiters",http://google.com
|
||||
Test,"This is a \"test csv file\"
|
||||
with both \"line breaks\"
|
||||
and \"escaped
|
||||
quotes\" that breaks
|
||||
Test,"This is a ""test csv file""
|
||||
with both ""line breaks""
|
||||
and ""escaped
|
||||
quotes"" that breaks
|
||||
the delimiters",http://google.com
|
||||
Test,"This is a \"test csv file\"
|
||||
with both \"line breaks\"
|
||||
and \"escaped
|
||||
quotes\" that breaks
|
||||
Test,"This is a ""test csv file""
|
||||
with both ""line breaks""
|
||||
and ""escaped
|
||||
quotes"" that breaks
|
||||
the delimiters",http://google.com
|
||||
Test,"This is a \"test csv file\"
|
||||
with both \"line breaks\"
|
||||
and \"escaped
|
||||
quotes\" that breaks
|
||||
Test,"This is a ""test csv file""
|
||||
with both ""line breaks""
|
||||
and ""escaped
|
||||
quotes"" that breaks
|
||||
the delimiters",http://google.com
|
||||
|
|
Can't render this file because it contains an unexpected character in line 2 and column 18.
|
|
@ -1,6 +1,11 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
// ANSI Latin I (BIFF4-BIFF7)
|
||||
[
|
||||
'CP1252',
|
||||
0,
|
||||
],
|
||||
// ASCII
|
||||
[
|
||||
'ASCII',
|
||||
|
@ -127,11 +132,6 @@ return [
|
|||
1251,
|
||||
],
|
||||
// ANSI Latin I (BIFF4-BIFF7)
|
||||
[
|
||||
'CP1252',
|
||||
0,
|
||||
],
|
||||
// ANSI Latin I (BIFF4-BIFF7)
|
||||
[
|
||||
'CP1252',
|
||||
1252,
|
||||
|
@ -176,6 +176,31 @@ return [
|
|||
'MAC',
|
||||
10000,
|
||||
],
|
||||
// Macintosh Japanese
|
||||
[
|
||||
'CP932',
|
||||
10001,
|
||||
],
|
||||
// Macintosh Chinese Traditional
|
||||
[
|
||||
'CP950',
|
||||
10002,
|
||||
],
|
||||
// Macintosh Korean
|
||||
[
|
||||
'CP1361',
|
||||
10003,
|
||||
],
|
||||
// Apple Arabic
|
||||
[
|
||||
'MACARABIC',
|
||||
10004,
|
||||
],
|
||||
// Apple Hebrew
|
||||
[
|
||||
'MACHEBREW',
|
||||
10005,
|
||||
],
|
||||
// Macintosh Greek
|
||||
[
|
||||
'MACGREEK',
|
||||
|
@ -186,6 +211,26 @@ return [
|
|||
'MACCYRILLIC',
|
||||
10007,
|
||||
],
|
||||
// Macintosh - Simplified Chinese (GB 2312)
|
||||
[
|
||||
'CP936',
|
||||
10008,
|
||||
],
|
||||
// Macintosh Romania
|
||||
[
|
||||
'MACROMANIA',
|
||||
10010,
|
||||
],
|
||||
// Macintosh Ukraine
|
||||
[
|
||||
'MACUKRAINE',
|
||||
10017,
|
||||
],
|
||||
// Macintosh Thai
|
||||
[
|
||||
'MACTHAI',
|
||||
10021,
|
||||
],
|
||||
// Macintosh Central Europe
|
||||
[
|
||||
'MACCENTRALEUROPE',
|
||||
|
@ -201,6 +246,16 @@ return [
|
|||
'MACTURKISH',
|
||||
10081,
|
||||
],
|
||||
// Macintosh Croatian
|
||||
[
|
||||
'MACCROATIAN',
|
||||
10082,
|
||||
],
|
||||
// UTF-16 (BIFF8) grandfathers erroneous libraries
|
||||
[
|
||||
'UTF-16LE',
|
||||
21010,
|
||||
],
|
||||
// Apple Roman
|
||||
[
|
||||
'MAC',
|
||||
|
|
|
@ -146,4 +146,8 @@ return [
|
|||
false,
|
||||
'#,##0.00 "dollars"',
|
||||
],
|
||||
[
|
||||
true,
|
||||
'"date " y-m-d',
|
||||
],
|
||||
];
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue