Changeset 3473263
- Timestamp:
- 03/03/2026 04:48:29 AM (4 weeks ago)
- Location:
- tablepress
- Files:
-
- 2 added
- 66 edited
- 1 copied
-
tags/3.2.8 (copied) (copied from tablepress/trunk)
-
tags/3.2.8/blocks/blocks-manifest.php (modified) (1 diff)
-
tags/3.2.8/blocks/table/block.json (modified) (1 diff)
-
tags/3.2.8/classes/class-export.php (modified) (1 diff)
-
tags/3.2.8/classes/class-tablepress.php (modified) (2 diffs)
-
tags/3.2.8/libraries/evalmath.class.php (modified) (1 diff)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/Calculation.php (modified) (19 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/CalculationParserOnly.php (added)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/FormulaParser.php (modified) (1 diff)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/FormulaToken.php (modified) (1 diff)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/FunctionArray.php (modified) (1 diff)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/Functions.php (modified) (2 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/MathTrig/Sum.php (modified) (1 diff)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/TextData/Concatenate.php (modified) (5 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Cell/Cell.php (modified) (7 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Cell/DefaultValueBinder.php (modified) (2 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Helper/Downloader.php (modified) (2 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Helper/Sample.php (modified) (1 diff)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Reader/BaseReader.php (modified) (3 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Reader/Html.php (modified) (6 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Reader/Ods.php (modified) (34 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Reader/Ods/PageSettings.php (modified) (1 diff)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Reader/Xlsx.php (modified) (4 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Reader/Xlsx/Namespaces.php (modified) (1 diff)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Spreadsheet.php (modified) (4 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Style/Alignment.php (modified) (1 diff)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Style/Font.php (modified) (1 diff)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Style/NumberFormat.php (modified) (8 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php (modified) (5 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Style/Style.php (modified) (4 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Worksheet/Drawing.php (modified) (3 diffs)
-
tags/3.2.8/libraries/vendor/PhpSpreadsheet/Worksheet/Worksheet.php (modified) (17 diffs)
-
tags/3.2.8/libraries/vendor/autoload-classmap.php (modified) (1 diff)
-
tags/3.2.8/readme.txt (modified) (3 diffs)
-
tags/3.2.8/tablepress.php (modified) (3 diffs)
-
trunk/blocks/blocks-manifest.php (modified) (1 diff)
-
trunk/blocks/table/block.json (modified) (1 diff)
-
trunk/classes/class-export.php (modified) (1 diff)
-
trunk/classes/class-tablepress.php (modified) (2 diffs)
-
trunk/libraries/evalmath.class.php (modified) (1 diff)
-
trunk/libraries/vendor/PhpSpreadsheet/Calculation/Calculation.php (modified) (19 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Calculation/CalculationParserOnly.php (added)
-
trunk/libraries/vendor/PhpSpreadsheet/Calculation/FormulaParser.php (modified) (1 diff)
-
trunk/libraries/vendor/PhpSpreadsheet/Calculation/FormulaToken.php (modified) (1 diff)
-
trunk/libraries/vendor/PhpSpreadsheet/Calculation/FunctionArray.php (modified) (1 diff)
-
trunk/libraries/vendor/PhpSpreadsheet/Calculation/Functions.php (modified) (2 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Calculation/MathTrig/Sum.php (modified) (1 diff)
-
trunk/libraries/vendor/PhpSpreadsheet/Calculation/TextData/Concatenate.php (modified) (5 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Cell/Cell.php (modified) (7 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Cell/DefaultValueBinder.php (modified) (2 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Helper/Downloader.php (modified) (2 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Helper/Sample.php (modified) (1 diff)
-
trunk/libraries/vendor/PhpSpreadsheet/Reader/BaseReader.php (modified) (3 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Reader/Html.php (modified) (6 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Reader/Ods.php (modified) (34 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Reader/Ods/PageSettings.php (modified) (1 diff)
-
trunk/libraries/vendor/PhpSpreadsheet/Reader/Xlsx.php (modified) (4 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Reader/Xlsx/Namespaces.php (modified) (1 diff)
-
trunk/libraries/vendor/PhpSpreadsheet/Spreadsheet.php (modified) (4 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Style/Alignment.php (modified) (1 diff)
-
trunk/libraries/vendor/PhpSpreadsheet/Style/Font.php (modified) (1 diff)
-
trunk/libraries/vendor/PhpSpreadsheet/Style/NumberFormat.php (modified) (8 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php (modified) (5 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Style/Style.php (modified) (4 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Worksheet/Drawing.php (modified) (3 diffs)
-
trunk/libraries/vendor/PhpSpreadsheet/Worksheet/Worksheet.php (modified) (17 diffs)
-
trunk/libraries/vendor/autoload-classmap.php (modified) (1 diff)
-
trunk/readme.txt (modified) (3 diffs)
-
trunk/tablepress.php (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
tablepress/tags/3.2.8/blocks/blocks-manifest.php
r3463039 r3473263 6 6 'apiVersion' => 3, 7 7 'name' => 'tablepress/table', 8 'version' => '3.2. 7',8 'version' => '3.2.8', 9 9 'title' => 'TablePress table', 10 10 'category' => 'media', -
tablepress/tags/3.2.8/blocks/table/block.json
r3463039 r3473263 3 3 "apiVersion": 3, 4 4 "name": "tablepress/table", 5 "version": "3.2. 7",5 "version": "3.2.8", 6 6 "title": "TablePress table", 7 7 "category": "media", -
tablepress/tags/3.2.8/classes/class-export.php
r3463039 r3473263 158 158 $active_content_triggers = array( '=', '+', '-', '@' ); 159 159 if ( in_array( $cell_content[0], $active_content_triggers, true ) ) { 160 // phpcs:disable Generic.Strings.UnnecessaryStringConcat.Found -- Avoid concatenation of function names to prevent false positives in code scanners. 160 161 $functions_to_escape = array( 161 162 'cmd|', 162 'FOR FILES|',163 'rund ll32',164 'DD E(',165 'IMPORT XML(',166 'IMPORT FEED(',167 'IMPORT HTML(',168 'IMPORT RANGE(',169 'IMPORT DATA(',163 'FOR' . 'FILES|', 164 'rund' . 'll32', 165 'DD' . 'E(', 166 'IMPORT' . 'XML(', 167 'IMPORT' . 'FEED(', 168 'IMPORT' . 'HTML(', 169 'IMPORT' . 'RANGE(', 170 'IMPORT' . 'DATA(', 170 171 'IMAGE(', 171 172 'HYPERLINK(', 172 173 'WEBSERVICE(', 173 174 ); 175 // phpcs:enable 174 176 175 177 $fn_stripos = function_exists( 'mb_stripos' ) ? 'mb_stripos' : 'stripos'; -
tablepress/tags/3.2.8/classes/class-tablepress.php
r3463039 r3473263 28 28 * @const string 29 29 */ 30 public const version = '3.2. 7'; // phpcs:ignore Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase30 public const version = '3.2.8'; // phpcs:ignore Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase 31 31 32 32 /** … … 38 38 * @const int 39 39 */ 40 public const db_version = 12 1; // phpcs:ignore Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase40 public const db_version = 122; // phpcs:ignore Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase 41 41 42 42 /** -
tablepress/tags/3.2.8/libraries/evalmath.class.php
r3381612 r3473263 400 400 401 401 // Do we now have a function/variable/number? 402 } elseif ( $ex && ! $expecting_operator ) { 402 } elseif ( $ex && ! $expecting_operator ) { // @phpstan-ignore booleanNot.alwaysTrue 403 403 $expecting_operator = true; 404 404 $value = $match[1]; -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/Calculation.php
r3463039 r3473263 3 3 namespace TablePress\PhpOffice\PhpSpreadsheet\Calculation; 4 4 5 use TablePress\Composer\Pcre\Preg; // many pregs in this program use u modifier, which has side-effects which make it unsuitable for this 5 6 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Engine\BranchPruner; 6 7 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Engine\CyclicReferenceStack; … … 37 38 // Function (allow for the old @ symbol that could be used to prefix a function, but we'll ignore it) 38 39 const CALCULATION_REGEXP_FUNCTION = '@?(?:_xlfn\.)?(?:_xlws\.)?((?:__xludf\.)?[\p{L}][\p{L}\p{N}\._]*)[\s]*\('; // TablePress: Add _ to allow the deprecated RAND_INT, RAND_FLOAT, NUMBER_FORMAT, and NUMBER_FORMAT_EU functions. 39 // Cell reference (cell or range of cells, with or without a sheet reference)40 // Cell reference, with or without a sheet reference) 40 41 const CALCULATION_REGEXP_CELLREF = '((([^\s,!&%^\/\*\+<>=:`-]*)|(\'(?:[^\']|\'[^!])+?\')|(\"(?:[^\"]|\"[^!])+?\"))!)?\$?\b([a-z]{1,3})\$?(\d{1,7})(?![\w.])'; 41 42 // Used only to detect spill operator # … … 91 92 private BranchPruner $branchPruner; 92 93 93 pr ivatebool $branchPruningEnabled = true;94 protected bool $branchPruningEnabled = true; 94 95 95 96 /** … … 424 425 if (is_string($value)) { 425 426 // Error values cannot be "wrapped" 426 if ( preg_match('/^' . self::CALCULATION_REGEXP_ERROR . '$/i', $value, $match)) {427 if (Preg::isMatch('/^' . self::CALCULATION_REGEXP_ERROR . '$/i', $value, $match)) { 427 428 // Return Excel errors "as is" 428 429 return $value; … … 507 508 $value = $cell->getValue(); 508 509 if (is_string($value) && $cell->getDataType() === DataType::TYPE_FORMULA) { 509 $value = preg_replace_callback(510 $value = Preg::replaceCallback( 510 511 self::CALCULATION_REGEXP_CELLREF_SPILL, 511 512 fn (array $matches) => 'ANCHORARRAY(' . substr($matches[0], 0, -1) . ')', … … 570 571 public function parseFormula(string $formula) 571 572 { 572 $formula = preg_replace_callback(573 $formula = Preg::replaceCallback( 573 574 self::CALCULATION_REGEXP_CELLREF_SPILL, 574 575 fn (array $matches) => 'ANCHORARRAY(' . substr($matches[0], 0, -1) . ')', 575 576 $formula 576 ) ?? $formula;577 ); 577 578 // Basic validation that this is indeed a formula 578 579 // We return an empty array if not … … 678 679 } 679 680 681 // https://www.reddit.com/r/excel/comments/chr41y/cmd_formula_stopped_working_since_last_update/ 680 682 if (preg_match('/^=\s*cmd\s*\|/miu', $formula) !== 0) { 681 return self::wrapResult($formula);683 return ExcelError::REF(); // returns #BLOCKED in newer versions 682 684 } 683 685 … … 1074 1076 ]; 1075 1077 1078 /** @param string[] $matches */ 1079 private static function unionForComma(array $matches): string 1080 { 1081 return $matches[1] . str_replace(',', '∪', $matches[2]); 1082 } 1083 1084 private const CELL_OR_CELLRANGE_OR_DEFINED_NAME 1085 = '(?:' 1086 . self::CALCULATION_REGEXP_CELLREF // cell address 1087 . '(?::' . self::CALCULATION_REGEXP_CELLREF . ')?' // optional range address, non-capturing 1088 . '|' . self::CALCULATION_REGEXP_DEFINEDNAME 1089 . ')' 1090 ; 1091 1092 public const UNIONABLE_COMMAS = '/((?:[,(]|^)\s*)' // comma or open paren or start of string, followed by optional whitespace 1093 . '([(]' // open paren 1094 . self::CELL_OR_CELLRANGE_OR_DEFINED_NAME // cell address 1095 . '(?:\s*,\s*' // optioonal whitespace, comma, optional whitespace, non-capturing 1096 . self::CELL_OR_CELLRANGE_OR_DEFINED_NAME // cell address 1097 . ')+' // one or more occurrences 1098 . '\s*[)])/i'; // optional whitespace, end paren 1099 1076 1100 /** 1077 1101 * @return array<int, mixed>|false … … 1081 1105 if (($formula = $this->convertMatrixReferences(trim($formula))) === false) { 1082 1106 return false; 1107 } 1108 1109 $oldFormula = $formula; 1110 $formula = Preg::replaceCallback(self::UNIONABLE_COMMAS, \Closure::fromCallable([self::class, 'unionForComma']), $formula); // @phpstan-ignore-line 1111 if ($oldFormula !== $formula) { 1112 $this->debugLog->writeDebugLog('Reformulated as %s', $formula); 1083 1113 } 1084 1114 $phpSpreadsheetFunctions = &self::getFunctionsAddress(); … … 1201 1231 } 1202 1232 } elseif (is_string($expectedArgumentCount) && $expectedArgumentCount !== '*') { 1203 if ( 1 !== preg_match('/(\d*)([-+,])(\d*)/', $expectedArgumentCount, $argMatch)) {1233 if (!Preg::isMatch('/(\d*)([-+,])(\d*)/', $expectedArgumentCount, $argMatch)) { 1204 1234 $argMatch = ['', '', '', '']; 1205 1235 } … … 1258 1288 // MS Excel allows this if the content is cell references; but doesn't allow actual values, 1259 1289 // but at this point, we can't differentiate (so allow both) 1260 return $this->raiseFormulaError('Formula Error: Unexpected ,'); 1261 /* The following code may be a better choice, but, with 1262 the other changes for this PR, I can no longer come up 1263 with a test case that gets here 1290 //return $this->raiseFormulaError('Formula Error: Unexpected ,'); 1291 1264 1292 $stack->push('Binary Operator', '∪'); 1265 1293 … … 1267 1295 $expectingOperator = false; 1268 1296 1269 continue; */1297 continue; 1270 1298 } 1271 1299 … … 1293 1321 1294 1322 if (preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/miu', $val, $matches)) { 1295 $val = (string) preg_replace('/\s/u', '', $val); 1323 // $val is known to be valid unicode from statement above, so Preg::replace is okay even with u modifier 1324 $val = Preg::replace('/\s/u', '', $val); 1296 1325 if (isset($phpSpreadsheetFunctions[strtoupper($matches[1])]) || isset(self::$controlFunctions[strtoupper($matches[1])])) { // it's a function 1297 1326 $valToUpper = strtoupper($val); … … 2011 2040 $this->executeNumericBinaryOperation($multiplier, $arg, '*', $stack); 2012 2041 } 2013 } elseif ( preg_match('/^' . self::CALCULATION_REGEXP_CELLREF . '$/i', StringHelper::convertToString($token ?? ''), $matches)) {2042 } elseif (Preg::isMatch('/^' . self::CALCULATION_REGEXP_CELLREF . '$/i', StringHelper::convertToString($token ?? ''), $matches)) { 2014 2043 $cellRef = null; 2015 2044 2016 2045 /* Phpstan says matches[8/9/10] is never set, 2017 2046 and code coverage report seems to confirm. 2018 Appease PhpStan for now; 2019 probably delete this block later. 2047 regex101.com confirms - only 7 capturing groups. 2048 My theory is that this code expected regexp to 2049 match cell *or* cellRange, but it does not 2050 match the latter. Retain the code for now in case 2051 we do want to add the range match later. 2052 Probably delete this block later. 2053 Until delete happens, turn code coverage off. 2020 2054 */ 2021 2055 if (isset($matches[self::$matchIndex8])) { 2056 // @codeCoverageIgnoreStart 2022 2057 if ($cell === null) { 2023 2058 // We can't access the range, so return a REF error … … 2025 2060 } else { 2026 2061 $cellRef = $matches[6] . $matches[7] . ':' . $matches[self::$matchIndex9] . $matches[self::$matchIndex10]; 2062 $matches[2] = (string) $matches[2]; 2027 2063 if ($matches[2] > '') { 2028 2064 $matches[2] = trim($matches[2], "\"'"); … … 2049 2085 } 2050 2086 } 2087 // @codeCoverageIgnoreEnd 2051 2088 } else { 2052 2089 if ($cell === null) { … … 2055 2092 } else { 2056 2093 $cellRef = $matches[6] . $matches[7]; 2094 $matches[2] = (string) $matches[2]; 2057 2095 if ($matches[2] > '') { 2058 2096 $matches[2] = trim($matches[2], "\"'"); … … 2096 2134 } 2097 2135 if (is_string($cellValue)) { 2098 $cellValue = preg_replace('/"/', '""', $cellValue);2136 $cellValue = Preg::replace('/"/', '""', $cellValue); 2099 2137 } 2100 2138 $this->debugLog->writeDebugLog('Scalar Result for cell %s is %s', $cellRef, $this->showTypeDetails($cellValue)); … … 2866 2904 $definedNameType = $namedRange->isFormula() ? 'Formula' : 'Range'; 2867 2905 if ($definedNameType === 'Range') { 2868 if (preg_match('/^(.*!)?(.*)$/', $definedNameValue, $matches) === 1) { 2869 $matches2 = trim($matches[2]); 2870 $matches2 = preg_replace('/ +/', ' ∩ ', $matches2) ?? $matches2; 2871 $matches2 = preg_replace('/,/', ' ∪ ', $matches2) ?? $matches2; 2906 if (Preg::isMatch('/^(.*!)?(.*)$/', $definedNameValue, $matches)) { 2907 $matches2 = Preg::replace( 2908 ['/ +/', '/,/'], 2909 [' ∩ ', ' ∪ '], 2910 trim($matches[2]) 2911 ); 2872 2912 $definedNameValue = $matches[1] . $matches2; 2873 2913 } -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/FormulaParser.php
r3420898 r3473263 22 22 * software or the use or other dealings in the software. 23 23 * 24 * The following links are no longer valid. 24 25 * https://ewbi.blogs.com/develops/2007/03/excel_formula_p.html 25 26 * https://ewbi.blogs.com/develops/2004/12/excel_formula_p.html 27 * 28 * @deprecated 5.5.0 No replacement. 26 29 */ 27 30 class FormulaParser -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/FormulaToken.php
r3218835 r3473263 22 22 * software or the use or other dealings in the software. 23 23 * 24 * The following links are no longer valid. 24 25 * https://ewbi.blogs.com/develops/2007/03/excel_formula_p.html 25 26 * https://ewbi.blogs.com/develops/2004/12/excel_formula_p.html 27 * 28 * @deprecated 5.5.0 No replacement. 26 29 */ 27 30 class FormulaToken -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/FunctionArray.php
r3463039 r3473263 406 406 'functionCall' => [TextData\Concatenate::class, 'actualCONCATENATE'], 407 407 'argumentCount' => '1+', 408 'passCellReference' => true, 408 409 ], 409 410 'CONFIDENCE' => [ -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/Functions.php
r3385566 r3473263 4 4 5 5 use TablePress\PhpOffice\PhpSpreadsheet\Cell\Cell; 6 use TablePress\PhpOffice\PhpSpreadsheet\Cell\Coordinate; 6 7 use TablePress\PhpOffice\PhpSpreadsheet\Shared\Date; 7 8 use TablePress\PhpOffice\PhpSpreadsheet\Shared\StringHelper; … … 382 383 return $coordinate; 383 384 } 385 386 /** @param mixed[] $array */ 387 public static function convertArrayToCellRange(array $array): string 388 { 389 $retVal = ''; 390 $lastRow = $lastColumn = $firstRow = $firstColumn = 0; 391 foreach ($array as $rowkey => $row) { 392 if (!is_array($row) || !is_int($rowkey) || $rowkey < 1) { 393 $firstRow = 0; 394 395 break; 396 } 397 if ($firstRow > $rowkey || $firstRow === 0) { 398 $firstRow = $rowkey; 399 } 400 if ($lastRow < $rowkey) { 401 $lastRow = $rowkey; 402 } 403 foreach ($row as $colkey => $cellValue) { 404 if (!preg_match('/^[A-Z]{1,3}$/', $colkey)) { 405 $firstRow = 0; 406 407 break 2; 408 } 409 $column = Coordinate::columnIndexFromString($colkey); 410 if ($firstColumn > $column || $firstColumn === 0) { 411 $firstColumn = $column; 412 } 413 if ($lastColumn < $column) { 414 $lastColumn = $column; 415 } 416 } 417 } 418 if ($firstRow > 0 && $firstColumn > 0 && ($firstRow !== $lastRow || $firstColumn !== $lastColumn)) { 419 $retVal = Coordinate::stringFromColumnIndex($firstColumn) 420 . $firstRow 421 . ':' 422 . Coordinate::stringFromColumnIndex($lastColumn) 423 . $lastRow; 424 } 425 426 return $retVal; 427 } 384 428 } -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/MathTrig/Sum.php
r3463039 r3473263 112 112 } 113 113 114 /** @var array<float|int> $wrkArray */ 114 115 return array_sum($wrkArray); 115 116 } -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Calculation/TextData/Concatenate.php
r3350024 r3473263 8 8 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue; 9 9 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError; 10 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Internal\ExcelArrayPseudoFunctions; 11 use TablePress\PhpOffice\PhpSpreadsheet\Cell\Cell; 10 12 use TablePress\PhpOffice\PhpSpreadsheet\Cell\DataType; 11 13 use TablePress\PhpOffice\PhpSpreadsheet\Shared\StringHelper; … … 18 20 * This implements the CONCAT function, *not* CONCATENATE. 19 21 * 20 * @param mixed [] $args22 * @param mixed $args data to be concatenated 21 23 */ 22 24 public static function CONCATENATE(...$args): string … … 48 50 * This implements the CONCATENATE function. 49 51 * 50 * @param mixed []$args data to be concatenated52 * @param mixed $args data to be concatenated 51 53 * 52 54 * @return array<string>|string … … 54 56 public static function actualCONCATENATE(...$args) 55 57 { 58 $useSingle = false; 59 $cell = null; 60 $count = count($args); 61 if ($args[$count - 1] instanceof Cell) { 62 /** @var Cell */ 63 $cell = array_pop($args); 64 $type = (($nullsafeVariable1 = $cell->getWorksheet()->getParent()) ? $nullsafeVariable1->getCalculationEngine()->getInstanceArrayReturnType() : null) ?? Calculation::getArrayReturnType(); 65 $useSingle = $type === Calculation::RETURN_ARRAY_AS_VALUE; 66 } 56 67 if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_GNUMERIC) { 57 68 return self::CONCATENATE(...$args); … … 59 70 $result = ''; 60 71 foreach ($args as $operand2) { 72 if ($useSingle && $cell instanceof Cell && is_array($operand2)) { 73 $temp = Functions::convertArrayToCellRange($operand2); 74 if ($temp !== '') { 75 $operand2 = ExcelArrayPseudoFunctions::single($temp, $cell); 76 } 77 } 78 /** @var null|array<mixed>|bool|float|int|string $operand2 */ 61 79 $result = self::concatenate2Args($result, $operand2); 62 80 if (ErrorValue::isError($result, true) === true) { -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Cell/Cell.php
r3463039 r3473263 227 227 } 228 228 // Cells?->Worksheet?->Spreadsheet 229 $binder ??= (($nullsafeVariable3 = ($nullsafeVariable1 0 = ($nullsafeVariable14 = $this->parent) ? $nullsafeVariable14->getParent() : null) ? $nullsafeVariable10->getParent() : null) ? $nullsafeVariable3->getValueBinder() : null) ?? self::getValueBinder();229 $binder ??= (($nullsafeVariable3 = ($nullsafeVariable13 = ($nullsafeVariable17 = $this->parent) ? $nullsafeVariable17->getParent() : null) ? $nullsafeVariable13->getParent() : null) ? $nullsafeVariable3->getValueBinder() : null) ?? self::getValueBinder(); 230 230 if (!$binder->bindValue($this, $value)) { 231 231 throw new SpreadsheetException('Value could not be bound to cell.'); … … 291 291 $value2 = StringHelper::convertToString($value, true); 292 292 // Cells?->Worksheet?->Spreadsheet 293 $binder = ($nullsafeVariable4 = ($nullsafeVariable 11 = ($nullsafeVariable15 = $this->parent) ? $nullsafeVariable15->getParent() : null) ? $nullsafeVariable11->getParent() : null) ? $nullsafeVariable4->getValueBinder() : null;293 $binder = ($nullsafeVariable4 = ($nullsafeVariable5 = ($nullsafeVariable14 = $this->parent) ? $nullsafeVariable14->getParent() : null) ? $nullsafeVariable5->getParent() : null) ? $nullsafeVariable4->getValueBinder() : null; 294 294 $preserveCr = false; 295 295 if ($binder !== null && method_exists($binder, 'getPreserveCr')) { … … 341 341 $this->updateInCollection(); 342 342 $cellCoordinate = $this->getCoordinate(); 343 self::updateIfCellIsTableHeader(($nullsafeVariable 5 = $this->getParent()) ? $nullsafeVariable5->getParent() : null, $this, $oldValue, $value);343 self::updateIfCellIsTableHeader(($nullsafeVariable6 = $this->getParent()) ? $nullsafeVariable6->getParent() : null, $this, $oldValue, $value); 344 344 $worksheet = $this->getWorksheet(); 345 345 $spreadsheet = $worksheet->getParent(); … … 358 358 } 359 359 360 return (($nullsafeVariable 6 = $this->getParent()) ? $nullsafeVariable6->get($cellCoordinate) : null) ?? $this;360 return (($nullsafeVariable7 = $this->getParent()) ? $nullsafeVariable7->get($cellCoordinate) : null) ?? $this; 361 361 } 362 362 public const CALCULATE_DATE_TIME_ASIS = 0; … … 437 437 try { 438 438 $currentCalendar = SharedDate::getExcelCalendar(); 439 SharedDate::setExcelCalendar(($nullsafeVariable 7 = $this->getWorksheet()->getParent()) ? $nullsafeVariable7->getExcelCalendar() : null);439 SharedDate::setExcelCalendar(($nullsafeVariable8 = $this->getWorksheet()->getParent()) ? $nullsafeVariable8->getExcelCalendar() : null); 440 440 $thisworksheet = $this->getWorksheet(); 441 441 $index = $thisworksheet->getParentOrThrow()->getActiveSheetIndex(); … … 1002 1002 public function isLocked(): bool 1003 1003 { 1004 $protected = ($nullsafeVariable 8 = ($nullsafeVariable12 = ($nullsafeVariable16 = $this->parent) ? $nullsafeVariable16->getParent() : null) ? $nullsafeVariable12->getProtection() : null) ? $nullsafeVariable8->getSheet() : null;1004 $protected = ($nullsafeVariable9 = ($nullsafeVariable10 = ($nullsafeVariable15 = $this->parent) ? $nullsafeVariable15->getParent() : null) ? $nullsafeVariable10->getProtection() : null) ? $nullsafeVariable9->getSheet() : null; 1005 1005 if ($protected !== true) { 1006 1006 return false; … … 1015 1015 return false; 1016 1016 } 1017 $protected = ($nullsafeVariable 9 = ($nullsafeVariable13 = ($nullsafeVariable17 = $this->parent) ? $nullsafeVariable17->getParent() : null) ? $nullsafeVariable13->getProtection() : null) ? $nullsafeVariable9->getSheet() : null;1017 $protected = ($nullsafeVariable11 = ($nullsafeVariable12 = ($nullsafeVariable16 = $this->parent) ? $nullsafeVariable16->getParent() : null) ? $nullsafeVariable12->getProtection() : null) ? $nullsafeVariable11->getSheet() : null; 1018 1018 if ($protected !== true) { 1019 1019 return false; -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Cell/DefaultValueBinder.php
r3463039 r3473263 5 5 use TablePress\Composer\Pcre\Preg; 6 6 use DateTimeInterface; 7 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Calculation ;7 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\CalculationParserOnly; 8 8 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Exception as CalculationException; 9 9 use TablePress\PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException; … … 88 88 } 89 89 if (strlen($value) > 1 && $value[0] === '=') { 90 $calculation = new Calculation(); 91 $calculation->disableBranchPruning(); 90 $calculation = CalculationParserOnly::getParserInstance(); 92 91 93 92 try { -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Helper/Downloader.php
r3283748 r3473263 3 3 namespace TablePress\PhpOffice\PhpSpreadsheet\Helper; 4 4 5 use DateTimeImmutable; 6 use DateTimeZone; 5 7 use TablePress\PhpOffice\PhpSpreadsheet\Exception; 6 8 … … 91 93 // If you're serving to IE over SSL, then the following may be needed 92 94 header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past 93 header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified 95 $dt = new DateTimeImmutable('now', new DateTimeZone('UTC')); 96 header('Last-Modified: ' . $dt->format('D, d M Y H:i:s') . ' GMT'); // always modified 94 97 header('Cache-Control: cache, must-revalidate'); // HTTP/1.1 95 98 header('Pragma: public'); // HTTP/1.0 -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Helper/Sample.php
r3463039 r3473263 132 132 $writer->save($path); 133 133 $this->logWrite($writer, $path, $callStartTime); 134 if ($this->isCli() === false) { 135 // @codeCoverageIgnoreStart 136 echo '<a href="https://plugins.trac.wordpress.org/download.php?type=" . pathinfo($path, PATHINFO_EXTENSION) . '&name=' . basename($path) . '">Download ' . basename($path) . '</a><br />'; 137 // @codeCoverageIgnoreEnd 138 } 134 $this->addDownloadLink($path); 139 135 } 140 136 141 137 $this->logEndingNotes(); 138 } 139 140 public function addDownloadLink(string $path): void 141 { 142 if ($this->isCli() === false) { 143 // @codeCoverageIgnoreStart 144 echo '<a href="https://plugins.trac.wordpress.org/download.php?type=" . pathinfo($path, PATHINFO_EXTENSION) . '&name=' . basename($path) . '">Download ' . basename($path) . '</a><br />'; 145 // @codeCoverageIgnoreEnd 146 } 142 147 } 143 148 -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Reader/BaseReader.php
r3463039 r3473263 3 3 namespace TablePress\PhpOffice\PhpSpreadsheet\Reader; 4 4 5 use Closure; 5 6 use TablePress\PhpOffice\PhpSpreadsheet\Cell\IValueBinder; 6 7 use TablePress\PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException; … … 81 82 protected ?IValueBinder $valueBinder = null; 82 83 84 /** @var null|Closure(string):bool function to return whether image path is okay */ 85 protected ?Closure $isWhitelisted = null; 86 83 87 public function __construct() 84 88 { … … 184 188 185 189 /** 186 * Allow external images. Use with caution. 187 * Improper specification of these within a spreadsheet 190 * USE WITH CAUTION (and in conjunction with setIsWhiteListed)! 191 * Allow external images; 192 * these can be specified within a spreadsheet 193 * in a way that can subject the caller to security exploits. 194 */ 195 public function setAllowExternalImages(bool $allowExternalImages): self 196 { 197 $this->allowExternalImages = $allowExternalImages; 198 199 return $this; 200 } 201 202 public function getAllowExternalImages(): bool 203 { 204 return $this->allowExternalImages; 205 } 206 207 /** 208 * USE WITH CAUTION! 209 * Supply a callback to determine whether a path should be whitelisted, 210 * used in conjunction with setAllowExternalImages; 211 * supplying a method which might return true 188 212 * can subject the caller to security exploits. 189 */ 190 public function setAllowExternalImages(bool $allowExternalImages): self 191 { 192 $this->allowExternalImages = $allowExternalImages; 193 194 return $this; 195 } 196 197 public function getAllowExternalImages(): bool 198 { 199 return $this->allowExternalImages; 213 * 214 * @param Closure(string):bool $isWhitelisted 215 */ 216 public function setIsWhitelisted(Closure $isWhitelisted): self 217 { 218 $this->isWhitelisted = $isWhitelisted; 219 220 return $this; 200 221 } 201 222 -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Reader/Html.php
r3463039 r3473263 291 291 * @param string[] $attributeArray 292 292 * 293 * @param-out string $cellContent In one case, it can be bool293 * @param-out string $cellContentx 294 294 * @param int|string $row 295 * @param mixed $cellContent 295 * @param mixed $cellContentx 296 296 */ 297 protected function flushCell(Worksheet $sheet, string $column, $row, &$cellContent, array $attributeArray): void 298 { 297 protected function flushCell(Worksheet $sheet, string $column, $row, &$cellContentx, array $attributeArray): void 298 { 299 $cellContent = $cellContentx; 299 300 if (is_string($cellContent)) { 300 301 // Simple String content … … 305 306 306 307 // Set cell value explicitly if there is data-type attribute 308 if (isset($attributeArray['data-checkbox'])) { 309 $sheet->getStyle($column . $row) 310 ->setCheckBox(true); 311 } 307 312 if (isset($attributeArray['data-type'])) { 308 313 $datatype = $attributeArray['data-type']; … … 317 322 if ($datatype === DataType::TYPE_BOOL) { 318 323 // This is the case where we can set cellContent to bool rather than string 319 $cellContent = self::convertBoolean($cellContent); //* @phpstan-ignore-line 320 if (!is_bool($cellContent)) { 321 $attributeArray['data-type'] = DataType::TYPE_STRING; 324 if ($cellContent === '☑') { 325 $cellContent = true; 326 $sheet->getStyle($column . $row) 327 ->setCheckBox(true); 328 } elseif ($cellContent === '☐') { 329 $cellContent = false; 330 $sheet->getStyle($column . $row) 331 ->setCheckBox(true); 332 } else { 333 $cellContent = self::convertBoolean($cellContent); 334 if (!is_bool($cellContent)) { 335 $attributeArray['data-type'] = DataType::TYPE_STRING; 336 } 322 337 } 323 338 } … … 327 342 328 343 try { 329 $sheet->setCellValueExplicit($column . $row, $cellContent, $attributeArray['data-type']); 344 if (isset($attributeArray['data-formula'])) { 345 $sheet->setCellValueExplicit($column . $row, $attributeArray['data-formula'], DataType::TYPE_FORMULA); 346 $sheet->getCell($column . $row) 347 ->setCalculatedValue( 348 $cellContent 349 ); 350 } else { 351 $sheet->setCellValueExplicit($column . $row, $cellContent, $attributeArray['data-type']); 352 } 330 353 } catch (SpreadsheetException $exception) { 331 354 $sheet->setCellValue($column . $row, $cellContent); … … 349 372 $this->dataArray[$row][$column] = 'RICH TEXT: ' . StringHelper::convertToString($cellContent); // @codeCoverageIgnore 350 373 } 351 $cellContent = (string)'';374 $cellContentx = ''; 352 375 } 353 376 … … 1218 1241 1219 1242 $drawing = new Drawing(); 1220 $drawing->setPath($src, false, null, $this->allowExternalImages );1243 $drawing->setPath($src, false, null, $this->allowExternalImages, $this->isWhitelisted); 1221 1244 if ($drawing->getPath() === '') { 1222 1245 return; -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Reader/Ods.php
r3463039 r3473263 3 3 namespace TablePress\PhpOffice\PhpSpreadsheet\Reader; 4 4 5 use Closure; 6 use TablePress\Composer\Pcre\Preg; 7 use DateTime; 8 use DateTimeZone; 5 9 use DOMAttr; 6 10 use DOMDocument; … … 8 12 use DOMNode; 9 13 use DOMText; 14 use TablePress\PhpOffice\PhpSpreadsheet\Cell\AddressRange; 10 15 use TablePress\PhpOffice\PhpSpreadsheet\Cell\Coordinate; 11 16 use TablePress\PhpOffice\PhpSpreadsheet\Cell\DataType; … … 22 27 use TablePress\PhpOffice\PhpSpreadsheet\Shared\StringHelper; 23 28 use TablePress\PhpOffice\PhpSpreadsheet\Spreadsheet; 29 use TablePress\PhpOffice\PhpSpreadsheet\Style\Alignment; 30 use TablePress\PhpOffice\PhpSpreadsheet\Style\Border; 31 use TablePress\PhpOffice\PhpSpreadsheet\Style\Borders; 32 use TablePress\PhpOffice\PhpSpreadsheet\Style\Fill; 24 33 use TablePress\PhpOffice\PhpSpreadsheet\Style\NumberFormat; 34 use TablePress\PhpOffice\PhpSpreadsheet\Style\Protection; 25 35 use TablePress\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; 26 36 use Throwable; … … 142 152 * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns). 143 153 * 144 * @return array<int, array{worksheetName: string, lastColumnLetter: string, lastColumnIndex: int, totalRows: int, totalColumns: int, sheetState: string}> 154 * @return array<int, array{ 155 * worksheetName: string, 156 * lastColumnLetter: string, 157 * lastColumnIndex: int, 158 * totalRows: int, 159 * totalColumns: int, 160 * sheetState: string 161 * }> 145 162 */ 146 163 public function listWorksheetInfo(string $filename): array … … 243 260 } 244 261 262 /** @var array<string, 263 * array{ 264 * font?:array{ 265 * autoColor?: true, 266 * bold?: true, 267 * color?: array{rgb: string}, 268 * italic?: true, 269 * name?: non-empty-string, 270 * size?: float|int, 271 * strikethrough?: true, 272 * underline?: 'double'|'single', 273 * }, 274 * fill?:array{ 275 * fillType?: string, 276 * startColor?: array{rgb: string}, 277 * }, 278 * alignment?:array{ 279 * horizontal?: string, 280 * readOrder?: int, 281 * shrinkToFit?: bool, 282 * textRotation?: int, 283 * vertical?: string, 284 * wrapText?: bool, 285 * }, 286 * protection?:array{ 287 * locked?: string, 288 * hidden?: string, 289 * }, 290 * borders?:array{ 291 * bottom?: array{borderStyle:string, color:array{rgb: string}}, 292 * left?: array{borderStyle:string, color:array{rgb: string}}, 293 * right?: array{borderStyle:string, color:array{rgb: string}}, 294 * top?: array{borderStyle:string, color:array{rgb: string}}, 295 * diagonal?: array{borderStyle:string, color:array{rgb: string}}, 296 * diagonalDirection?: int, 297 * }, 298 * }> 299 */ 300 private array $allStyles; 301 302 private int $highestDataIndex; 303 245 304 /** 246 305 * Loads PhpSpreadsheet from file into PhpSpreadsheet instance. … … 270 329 // Styles 271 330 331 $this->allStyles = []; 272 332 $dom = new DOMDocument('1.01', 'UTF-8'); 273 333 $dom->loadXML( … … 275 335 ->scan($zip->getFromName('styles.xml')) 276 336 ); 337 $officeNs = (string) $dom->lookupNamespaceUri('office'); 338 $styleNs = (string) $dom->lookupNamespaceUri('style'); 339 $fontNs = (string) $dom->lookupNamespaceUri('fo'); 340 341 $automaticStyle0 = $this->readDataOnly ? null : $dom->getElementsByTagNameNS($officeNs, 'styles')->item(0); 342 $automaticStyles = ($automaticStyle0 === null) ? [] : $automaticStyle0->getElementsByTagNameNS($styleNs, 'default-style'); 343 foreach ($automaticStyles as $automaticStyle) { 344 $styleFamily = $automaticStyle->getAttributeNS($styleNs, 'family'); 345 if ($styleFamily === 'table-cell') { 346 $fonts = []; 347 foreach ($automaticStyle->getElementsByTagNameNS($styleNs, 'text-properties') as $textProperty) { 348 $fonts = $this->getFontStyles($textProperty, $styleNs, $fontNs); 349 } 350 if (!empty($fonts)) { 351 $spreadsheet->getDefaultStyle() 352 ->getFont() 353 ->applyFromArray($fonts); 354 } 355 } 356 } 357 $automaticStyles = ($automaticStyle0 === null) ? [] : $automaticStyle0->getElementsByTagNameNS($styleNs, 'style'); 358 foreach ($automaticStyles as $automaticStyle) { 359 $styleName = $automaticStyle->getAttributeNS($styleNs, 'name'); 360 $styleFamily = $automaticStyle->getAttributeNS($styleNs, 'family'); 361 if ($styleFamily === 'table-cell') { 362 $fills = $fonts = []; 363 foreach ($automaticStyle->getElementsByTagNameNS($styleNs, 'text-properties') as $textProperty) { 364 $fonts = $this->getFontStyles($textProperty, $styleNs, $fontNs); 365 } 366 foreach ($automaticStyle->getElementsByTagNameNS($styleNs, 'table-cell-properties') as $tableCellProperty) { 367 $fills = $this->getFillStyles($tableCellProperty, $fontNs); 368 } 369 if ($styleName !== '') { 370 if (!empty($fonts)) { 371 $this->allStyles[$styleName]['font'] = $fonts; 372 if ($styleName === 'Default') { 373 $spreadsheet->getDefaultStyle() 374 ->getFont() 375 ->applyFromArray($fonts); 376 } 377 } 378 if (!empty($fills)) { 379 $this->allStyles[$styleName]['fill'] = $fills; 380 if ($styleName === 'Default') { 381 $spreadsheet->getDefaultStyle() 382 ->getFill() 383 ->applyFromArray($fills); 384 } 385 } 386 } 387 } 388 } 277 389 278 390 $pageSettings = new PageSettings($dom); … … 286 398 ); 287 399 288 $officeNs = (string) $dom->lookupNamespaceUri('office');289 400 $tableNs = (string) $dom->lookupNamespaceUri('table'); 290 401 $textNs = (string) $dom->lookupNamespaceUri('text'); 291 402 $xlinkNs = (string) $dom->lookupNamespaceUri('xlink'); 292 $styleNs = (string) $dom->lookupNamespaceUri('style');293 403 294 404 $pageSettings->readStyleCrossReferences($dom); … … 297 407 $definedNameReader = new DefinedNames($spreadsheet, $tableNs); 298 408 $columnWidths = []; 299 $automaticStyle0 = $ dom->getElementsByTagNameNS($officeNs, 'automatic-styles')->item(0);409 $automaticStyle0 = $this->readDataOnly ? null : $dom->getElementsByTagNameNS($officeNs, 'automatic-styles')->item(0); 300 410 $automaticStyles = ($automaticStyle0 === null) ? [] : $automaticStyle0->getElementsByTagNameNS($styleNs, 'style'); 301 411 foreach ($automaticStyles as $automaticStyle) { … … 310 420 } 311 421 } 422 if ($styleFamily === 'table-cell') { 423 $fonts = $fills = $alignment1 = $alignment2 = $protection = $borders = []; 424 foreach ($automaticStyle->getElementsByTagNameNS($styleNs, 'text-properties') as $textProperty) { 425 $fonts = $this->getFontStyles($textProperty, $styleNs, $fontNs); 426 } 427 foreach ($automaticStyle->getElementsByTagNameNS($styleNs, 'table-cell-properties') as $tableCellProperty) { 428 $fills = $this->getFillStyles($tableCellProperty, $fontNs); 429 $borders = $this->getBorderStyles($tableCellProperty, $fontNs, $styleNs); 430 $protection = $this->getProtectionStyles($tableCellProperty, $styleNs); 431 } 432 foreach ($automaticStyle->getElementsByTagNameNS($styleNs, 'table-cell-properties') as $tableCellProperty) { 433 $alignment1 = $this->getAlignment1Styles($tableCellProperty, $styleNs, $fontNs); 434 } 435 foreach ($automaticStyle->getElementsByTagNameNS($styleNs, 'paragraph-properties') as $paragraphProperty) { 436 $alignment2 = $this->getAlignment2Styles($paragraphProperty, $styleNs, $fontNs); 437 } 438 if ($styleName !== '') { 439 if (!empty($fonts)) { 440 $this->allStyles[$styleName]['font'] = $fonts; 441 } 442 if (!empty($fills)) { 443 $this->allStyles[$styleName]['fill'] = $fills; 444 } 445 $alignment = array_merge($alignment1, $alignment2); 446 if (!empty($alignment)) { 447 $this->allStyles[$styleName]['alignment'] = $alignment; 448 } 449 if (!empty($protection)) { 450 $this->allStyles[$styleName]['protection'] = $protection; 451 } 452 if (!empty($borders)) { 453 $this->allStyles[$styleName]['borders'] = $borders; 454 } 455 } 456 } 312 457 } 313 458 … … 346 491 // formula cells... during the load, all formulae should be correct, and we're simply 347 492 // bringing the worksheet name in line with the formula, not the reverse 348 $spreadsheet->getActiveSheet()->setTitle((string) $worksheetName, false, false); 493 $spreadsheet->getActiveSheet() 494 ->setTitle((string) $worksheetName, false, false); 349 495 } 350 496 … … 352 498 $rowID = 1; 353 499 $tableColumnIndex = 1; 500 $this->highestDataIndex = AddressRange::MAX_COLUMN_INT; 354 501 foreach ($worksheetDataSet->childNodes as $childNode) { 355 502 /** @var DOMElement $childNode */ … … 390 537 391 538 break; 392 case 'table-header-columns':393 case 'table-columns':394 $this->processTableHeaderColumns(395 $childNode,396 $tableNs,397 $columnWidths,398 $tableColumnIndex,399 $spreadsheet400 );401 402 break;403 case 'table-column-group':404 $this->processTableColumnGroup(405 $childNode,406 $tableNs,407 $columnWidths,408 $tableColumnIndex,409 $spreadsheet410 );411 412 break;413 case 'table-column':414 $this->processTableColumn(415 $childNode,416 $tableNs,417 $columnWidths,418 $tableColumnIndex,419 $spreadsheet420 );421 422 break;423 539 case 'table-row': 424 540 $this->processTableRow( … … 434 550 435 551 break; 552 case 'table-header-columns': 553 case 'table-columns': 554 $this->processTableColumnHeader( 555 $childNode, 556 $tableNs, 557 $columnWidths, 558 $tableColumnIndex, 559 $spreadsheet, 560 $this->readEmptyCells, 561 true 562 ); 563 564 break; 565 case 'table-column-group': 566 $this->processTableColumnGroup( 567 $childNode, 568 $tableNs, 569 $columnWidths, 570 $tableColumnIndex, 571 $spreadsheet, 572 $this->readEmptyCells, 573 true 574 ); 575 576 break; 577 case 'table-column': 578 $this->processTableColumn( 579 $childNode, 580 $tableNs, 581 $columnWidths, 582 $tableColumnIndex, 583 $spreadsheet, 584 $this->readEmptyCells, 585 true 586 ); 587 588 break; 436 589 } 437 590 } … … 449 602 $spreadsheet->createSheet(); 450 603 } 604 } 605 606 foreach ($spreadsheets as $workbookData) { 607 /** @var DOMElement $workbookData */ 608 $tables = $workbookData->getElementsByTagNameNS($tableNs, 'table'); 609 610 $worksheetID = 0; 611 foreach ($tables as $worksheetDataSet) { 612 /** @var DOMElement $worksheetDataSet */ 613 $worksheetName = $worksheetDataSet->getAttributeNS($tableNs, 'name'); 614 615 // Check loadSheetsOnly 616 if ( 617 $this->loadSheetsOnly !== null 618 && $worksheetName 619 && !in_array($worksheetName, $this->loadSheetsOnly) 620 ) { 621 continue; 622 } 623 624 // Create sheet 625 $spreadsheet->setActiveSheetIndex($worksheetID); 626 $highestDataColumn = $spreadsheet->getActiveSheet()->getHighestDataColumn(); 627 $this->highestDataIndex = Coordinate::columnIndexFromString($highestDataColumn); 628 629 // Go through every child of table element processing column widths 630 $rowID = 1; 631 $tableColumnIndex = 1; 632 foreach ($worksheetDataSet->childNodes as $childNode) { 633 /** @var DOMElement $childNode */ 634 if (empty($columnWidths) || $this->readEmptyCells) { 635 break; 636 } 637 638 // Filter elements which are not under the "table" ns 639 if ($childNode->namespaceURI != $tableNs) { 640 continue; 641 } 642 643 $key = self::extractNodeName($childNode->nodeName); 644 645 switch ($key) { 646 case 'table-header-columns': 647 case 'table-columns': 648 $this->processTableColumnHeader( 649 $childNode, 650 $tableNs, 651 $columnWidths, 652 $tableColumnIndex, 653 $spreadsheet, 654 true, 655 false 656 ); 657 658 break; 659 case 'table-column-group': 660 $this->processTableColumnGroup( 661 $childNode, 662 $tableNs, 663 $columnWidths, 664 $tableColumnIndex, 665 $spreadsheet, 666 true, 667 false 668 ); 669 670 break; 671 case 'table-column': 672 $this->processTableColumn( 673 $childNode, 674 $tableNs, 675 $columnWidths, 676 $tableColumnIndex, 677 $spreadsheet, 678 true, 679 false 680 ); 681 682 break; 683 } 684 } 685 ++$worksheetID; 686 } 451 687 452 688 $autoFilterReader->read($workbookData); 453 689 $definedNameReader->read($workbookData); 454 690 } 691 455 692 $spreadsheet->setActiveSheetIndex(0); 456 693 … … 567 804 $rowRepeats = 1; 568 805 } 806 $worksheet = $spreadsheet->getSheetByName($worksheetName); 569 807 570 808 $columnID = 'A'; … … 574 812 continue; // should just be whitespace 575 813 } 814 if ($cellData->hasAttributeNS($tableNs, 'number-columns-repeated')) { 815 $colRepeats = (int) $cellData->getAttributeNS($tableNs, 'number-columns-repeated'); 816 } else { 817 $colRepeats = 1; 818 } 819 $styleName = $cellData->getAttributeNS($tableNs, 'style-name'); 820 821 // When a cell has number-columns-repeated, check if ANY column in the 822 // repeated range passes the read filter. If not, skip the entire group. 823 // If some columns pass, we need to fall through to the processing block 824 // which will handle per-column filtering. 576 825 if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) { 577 if ($cellData->hasAttributeNS($tableNs, 'number-columns-repeated')) { 578 $colRepeats = (int) $cellData->getAttributeNS($tableNs, 'number-columns-repeated'); 579 } else { 580 $colRepeats = 1; 581 } 582 826 if ($colRepeats <= 1) { 827 StringHelper::stringIncrement($columnID); 828 829 continue; 830 } 831 832 // Check if any column within this repeated group passes the filter 833 $anyColumnPasses = false; 834 $tempCol = $columnID; 583 835 for ($i = 0; $i < $colRepeats; ++$i) { 584 StringHelper::stringIncrement($columnID); 585 } 586 587 continue; 836 if ($i > 0) { 837 StringHelper::stringIncrement($tempCol); 838 } 839 if ($this->getReadFilter()->readCell($tempCol, $rowID, $worksheetName)) { 840 $anyColumnPasses = true; 841 842 break; 843 } 844 } 845 846 if (!$anyColumnPasses) { 847 for ($i = 0; $i < $colRepeats; ++$i) { 848 StringHelper::stringIncrement($columnID); 849 } 850 851 continue; 852 } 853 // Fall through to process the cell, with per-column filter checks 854 } 855 if ($worksheet !== null && ($cellData->hasChildNodes() || ($cellData->nextSibling !== null)) && isset($this->allStyles[$styleName])) { 856 $spannedRange = "$columnID$rowID"; 857 // the following is sufficient for ods, 858 // and does no harm for xlsx/xls. 859 $worksheet->getStyle($spannedRange) 860 ->applyFromArray($this->allStyles[$styleName]); 861 // the rest of this block is needed for xlsx/xls, 862 // and does no harm for ods. 863 if (isset($this->allStyles[$styleName]['borders'])) { 864 $spannedRows = $cellData->getAttributeNS($tableNs, 'number-columns-spanned'); 865 $spannedColumns = $cellData->getAttributeNS($tableNs, 'number-rows-spanned'); 866 $spannedRows = max((int) $spannedRows, 1); 867 $spannedColumns = max((int) $spannedColumns, 1); 868 if ($spannedRows > 1 || $spannedColumns > 1) { 869 $endRow = $rowID + $spannedRows - 1; 870 $endCol = $columnID; 871 while ($spannedColumns > 1) { 872 StringHelper::stringIncrement($endCol); 873 --$spannedColumns; 874 } 875 $spannedRange .= ":$endCol$endRow"; 876 $worksheet->getStyle($spannedRange) 877 ->getBorders() 878 ->applyFromArray( 879 $this->allStyles[$styleName]['borders'] 880 ); 881 } 882 } 588 883 } 589 884 … … 658 953 659 954 if (count($paragraphs) > 0) { 955 $dataValue = null; 660 956 // Consolidate if there are multiple p records (maybe with spans as well) 661 957 $dataArray = []; … … 672 968 673 969 $type = $cellData->getAttributeNS($officeNs, 'value-type'); 970 $symbol = ''; 971 $leftHandCurrency = Preg::isMatch('/\$|£|¥/', $allCellDataText, $matches); 972 if ($leftHandCurrency) { 973 $type = str_replace('float', 'currency', $type); 974 $symbol = (string) $matches[0]; 975 } 976 $customFormatting = ''; 977 if ($this->formatCallback !== null) { 978 $temp = ($this->formatCallback)($type, $allCellDataText); 979 if ($temp !== '') { 980 $customFormatting = $temp; 981 } 982 } 674 983 675 984 switch ($type) { … … 692 1001 break; 693 1002 case 'percentage': 1003 if (!str_contains($allCellDataText, '.')) { 1004 $formatting = NumberFormat::FORMAT_PERCENTAGE; 1005 } elseif (substr($allCellDataText, -3, 1) === '.') { 1006 $formatting = NumberFormat::FORMAT_PERCENTAGE_0; 1007 } else { 1008 $formatting = NumberFormat::FORMAT_PERCENTAGE_00; 1009 } 694 1010 $type = DataType::TYPE_NUMERIC; 695 1011 $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value'); 696 697 // percentage should always be float698 //if (floor($dataValue) == $dataValue) {699 // $dataValue = (int) $dataValue;700 //}701 $formatting = NumberFormat::FORMAT_PERCENTAGE_00;702 1012 703 1013 break; … … 706 1016 $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value'); 707 1017 708 if (floor($dataValue) == $dataValue) { 709 $dataValue = (int) $dataValue; 710 } 711 $formatting = NumberFormat::FORMAT_CURRENCY_USD_INTEGER; 1018 $currency = $cellData->getAttributeNS($officeNs, 'currency'); 1019 if ($leftHandCurrency) { 1020 $typeValue = 'currency'; 1021 $formatting = str_contains($allCellDataText, '.') ? NumberFormat::FORMAT_CURRENCY_USD : NumberFormat::FORMAT_CURRENCY_USD_INTEGER; 1022 if ($symbol !== '$') { 1023 $formatting = str_replace('$', $symbol, $formatting); 1024 } 1025 } elseif (str_contains($allCellDataText, '€')) { 1026 $typeValue = 'currency'; 1027 $formatting = str_contains($allCellDataText, '.') ? NumberFormat::FORMAT_CURRENCY_EUR : NumberFormat::FORMAT_CURRENCY_EUR_INTEGER; 1028 } 712 1029 713 1030 break; … … 716 1033 $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value'); 717 1034 1035 if ($dataValue !== floor($dataValue)) { 1036 // do nothing 1037 } elseif (substr($allCellDataText, -2, 1) === '.') { 1038 $formatting = NumberFormat::FORMAT_NUMBER_0; 1039 } elseif (substr($allCellDataText, -3, 1) === '.') { 1040 $formatting = NumberFormat::FORMAT_NUMBER_00; 1041 } 718 1042 if (floor($dataValue) == $dataValue) { 719 1043 if ($dataValue == (int) $dataValue) { … … 728 1052 $dataValue = Date::convertIsoDate($value); 729 1053 730 if ($dataValue != floor($dataValue)) { 1054 if (Preg::isMatch('/^\d\d\d\d-\d\d-\d\d$/', $allCellDataText)) { 1055 $formatting = 'yyyy-mm-dd'; 1056 } elseif (Preg::isMatch('/^\d\d?-[a-zA-Z]+-\d\d\d\d$/', $allCellDataText)) { 1057 $formatting = 'd-mmm-yyyy'; 1058 } elseif ($dataValue != floor($dataValue)) { 731 1059 $formatting = NumberFormat::FORMAT_DATE_XLSX15 732 1060 . ' ' … … 741 1069 742 1070 $timeValue = $cellData->getAttributeNS($officeNs, 'time-value'); 743 744 $dataValue = Date::PHPToExcel( 745 strtotime( 746 '01-01-1970 ' . implode(':', sscanf($timeValue, 'PT%dH%dM%dS') ?? []) 747 ) 748 ); 749 $formatting = NumberFormat::FORMAT_DATE_TIME4; 1071 $minus = ''; 1072 if (str_starts_with($timeValue, '-')) { 1073 $minus = '-'; 1074 $timeValue = (string) substr($timeValue, 1); 1075 } 1076 $timeArray = sscanf($timeValue, 'PT%dH%dM%dS'); 1077 if (is_array($timeArray)) { 1078 /** @var array{int, int, int} $timeArray */ 1079 $days = intdiv($timeArray[0], 24); 1080 $hours = $timeArray[0] % 24; 1081 $dt = new DateTime("1899-12-30 $hours:{$timeArray[1]}:{$timeArray[2]}", new DateTimeZone('UTC')); 1082 $dt->modify("+$days days"); 1083 $dataValue = Date::PHPToExcel($dt); 1084 if ($minus === '-') { 1085 $dataValue *= -1; 1086 $formatting = '[hh]:mm:ss'; 1087 } else { 1088 $formatting = NumberFormat::FORMAT_DATE_TIME4; 1089 } 1090 } 750 1091 751 1092 break; 752 1093 default: 753 1094 $dataValue = null; 1095 } 1096 if ($customFormatting !== '') { 1097 $formatting = $customFormatting; 754 1098 } 755 1099 } else { … … 764 1108 } 765 1109 766 if ($cellData->hasAttributeNS($tableNs, 'number-columns-repeated')) { 767 $colRepeats = (int) $cellData->getAttributeNS($tableNs, 'number-columns-repeated'); 768 } else { 769 $colRepeats = 1; 770 } 771 772 if ($type !== null) { // @phpstan-ignore-line 773 for ($i = 0; $i < $colRepeats; ++$i) { 774 if ($i > 0) { 775 StringHelper::stringIncrement($columnID); 776 } 777 778 if ($type !== DataType::TYPE_NULL) { 779 for ($rowAdjust = 0; $rowAdjust < $rowRepeats; ++$rowAdjust) { 780 $rID = $rowID + $rowAdjust; 781 782 $cell = $spreadsheet->getActiveSheet() 783 ->getCell($columnID . $rID); 784 785 // Set value 786 if ($hasCalculatedValue) { 787 $cell->setValueExplicit($cellDataFormula, $type); 788 if ($cellDataType === 'array') { 789 $cell->setFormulaAttributes(['t' => 'array', 'ref' => $cellDataRef]); 790 } 791 } elseif ($type !== '' || $dataValue !== null) { 792 $cell->setValueExplicit($dataValue, $type); 1110 for ($i = 0; $i < $colRepeats; ++$i) { 1111 if ($i > 0) { 1112 StringHelper::stringIncrement($columnID); 1113 } 1114 1115 if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) { 1116 continue; 1117 } 1118 1119 if ($type !== DataType::TYPE_NULL) { 1120 for ($rowAdjust = 0; $rowAdjust < $rowRepeats; ++$rowAdjust) { 1121 $rID = $rowID + $rowAdjust; 1122 1123 $cell = $spreadsheet->getActiveSheet() 1124 ->getCell($columnID . $rID); 1125 1126 // Set value 1127 if ($hasCalculatedValue) { 1128 $cell->setValueExplicit($cellDataFormula, $type); 1129 if ($cellDataType === 'array') { 1130 $cell->setFormulaAttributes(['t' => 'array', 'ref' => $cellDataRef]); 793 1131 } 794 795 if ($hasCalculatedValue) { 796 $cell->setCalculatedValue($dataValue, $type === DataType::TYPE_NUMERIC); 1132 } elseif ($type !== '' || $dataValue !== null) { 1133 $cell->setValueExplicit($dataValue, $type); 1134 } 1135 1136 if ($hasCalculatedValue) { 1137 $cell->setCalculatedValue($dataValue, $type === DataType::TYPE_NUMERIC); 1138 } 1139 1140 // Set other properties 1141 if ($formatting !== null) { 1142 $spreadsheet->getActiveSheet() 1143 ->getStyle($columnID . $rID) 1144 ->getNumberFormat() 1145 ->setFormatCode($formatting); 1146 } else { 1147 $spreadsheet->getActiveSheet() 1148 ->getStyle($columnID . $rID) 1149 ->getNumberFormat() 1150 ->setFormatCode(NumberFormat::FORMAT_GENERAL); 1151 } 1152 1153 if ($hyperlink !== null) { 1154 if ($hyperlink[0] === '#') { 1155 $hyperlink = 'sheet://' . substr($hyperlink, 1); 797 1156 } 798 799 // Set other properties 800 if ($formatting !== null) { 801 $spreadsheet->getActiveSheet() 802 ->getStyle($columnID . $rID) 803 ->getNumberFormat() 804 ->setFormatCode($formatting); 805 } else { 806 $spreadsheet->getActiveSheet() 807 ->getStyle($columnID . $rID) 808 ->getNumberFormat() 809 ->setFormatCode(NumberFormat::FORMAT_GENERAL); 810 } 811 812 if ($hyperlink !== null) { 813 if ($hyperlink[0] === '#') { 814 $hyperlink = 'sheet://' . substr($hyperlink, 1); 815 } 816 $cell->getHyperlink() 817 ->setUrl($hyperlink); 818 } 1157 $cell->getHyperlink() 1158 ->setUrl($hyperlink); 819 1159 } 820 1160 } … … 844 1184 * @param string[] $columnWidths 845 1185 */ 846 private function processTable HeaderColumns(1186 private function processTableColumnHeader( 847 1187 DOMElement $childNode, 848 1188 string $tableNs, 849 1189 array $columnWidths, 850 1190 int &$tableColumnIndex, 851 Spreadsheet $spreadsheet 1191 Spreadsheet $spreadsheet, 1192 bool $processWidths = true, 1193 bool $processStyles = true 852 1194 ): void { 853 1195 foreach ($childNode->childNodes as $grandchildNode) { … … 861 1203 $columnWidths, 862 1204 $tableColumnIndex, 863 $spreadsheet 1205 $spreadsheet, 1206 $processWidths, 1207 $processStyles 864 1208 ); 865 1209 … … 877 1221 array $columnWidths, 878 1222 int &$tableColumnIndex, 879 Spreadsheet $spreadsheet 1223 Spreadsheet $spreadsheet, 1224 bool $processWidths = true, 1225 bool $processStyles = true 880 1226 ): void { 881 1227 foreach ($childNode->childNodes as $grandchildNode) { … … 889 1235 $columnWidths, 890 1236 $tableColumnIndex, 891 $spreadsheet 1237 $spreadsheet, 1238 $processWidths, 1239 $processStyles 892 1240 ); 893 1241 … … 895 1243 case 'table-header-columns': 896 1244 case 'table-columns': 897 $this->processTable HeaderColumns(1245 $this->processTableColumnHeader( 898 1246 $grandchildNode, 899 1247 $tableNs, 900 1248 $columnWidths, 901 1249 $tableColumnIndex, 902 $spreadsheet 1250 $spreadsheet, 1251 $processWidths, 1252 $processStyles 903 1253 ); 904 1254 … … 910 1260 $columnWidths, 911 1261 $tableColumnIndex, 912 $spreadsheet 1262 $spreadsheet, 1263 $processWidths, 1264 $processStyles 913 1265 ); 914 1266 … … 926 1278 array $columnWidths, 927 1279 int &$tableColumnIndex, 928 Spreadsheet $spreadsheet 1280 Spreadsheet $spreadsheet, 1281 bool $processWidths = true, 1282 bool $processStyles = true 929 1283 ): void { 930 1284 if ($childNode->hasAttributeNS($tableNs, 'number-columns-repeated')) { … … 934 1288 } 935 1289 $tableStyleName = $childNode->getAttributeNS($tableNs, 'style-name'); 936 if (isset($columnWidths[$tableStyleName])) { 937 $columnWidth = new HelperDimension($columnWidths[$tableStyleName]); 938 $tableColumnString = Coordinate::stringFromColumnIndex($tableColumnIndex); 939 for ($rowRepeats2 = $rowRepeats; $rowRepeats2 > 0; --$rowRepeats2) { 940 /** @var string $tableColumnString */ 941 $spreadsheet->getActiveSheet() 942 ->getColumnDimension($tableColumnString) 943 ->setWidth($columnWidth->toUnit('cm'), 'cm'); 944 StringHelper::stringIncrement($tableColumnString); 1290 if ($processWidths) { 1291 if (isset($columnWidths[$tableStyleName])) { 1292 $columnWidth = new HelperDimension($columnWidths[$tableStyleName]); 1293 $tableColumnIndex2 = $tableColumnIndex; 1294 $tableColumnString = Coordinate::stringFromColumnIndex($tableColumnIndex2); 1295 for ($rowRepeats2 = $rowRepeats; $rowRepeats2 > 0 && $tableColumnIndex2 <= AddressRange::MAX_COLUMN_INT; --$rowRepeats2) { 1296 if (!$this->readEmptyCells && $tableColumnIndex2 > $this->highestDataIndex) { 1297 break; 1298 } 1299 $spreadsheet->getActiveSheet() 1300 ->getColumnDimension($tableColumnString) 1301 ->setWidth($columnWidth->toUnit('cm'), 'cm'); 1302 StringHelper::stringIncrement( 1303 $tableColumnString 1304 ); 1305 ++$tableColumnIndex2; 1306 } 1307 } 1308 } 1309 if ($processStyles) { 1310 $defaultStyleName = $childNode->getAttributeNS($tableNs, 'default-cell-style-name'); 1311 if ($defaultStyleName !== 'Default' && isset($this->allStyles[$defaultStyleName])) { 1312 $tableColumnIndex2 = $tableColumnIndex; 1313 $tableColumnString = Coordinate::stringFromColumnIndex($tableColumnIndex2); 1314 for ($rowRepeats2 = $rowRepeats; $rowRepeats2 > 0 && $tableColumnIndex2 <= AddressRange::MAX_COLUMN_INT; --$rowRepeats2) { 1315 $spreadsheet->getActiveSheet() 1316 ->getStyle($tableColumnString) 1317 ->applyFromArray( 1318 $this->allStyles[$defaultStyleName] 1319 ); 1320 StringHelper::stringIncrement( 1321 $tableColumnString 1322 ); 1323 ++$tableColumnIndex2; 1324 } 945 1325 } 946 1326 } … … 1100 1480 } 1101 1481 } 1482 1483 /** @var null|Closure(string, string):string */ 1484 private ?Closure $formatCallback = null; 1485 1486 /** @param Closure(string, string):string $formatCallback */ 1487 public function setFormatCallback(Closure $formatCallback): void 1488 { 1489 $this->formatCallback = $formatCallback; 1490 } 1491 1492 /** @return array{ 1493 * autoColor?: true, 1494 * bold?: true, 1495 * color?: array{rgb: string}, 1496 * italic?: true, 1497 * name?: non-empty-string, 1498 * size?: float|int, 1499 * strikethrough?: true, 1500 * underline?: 'double'|'single', 1501 * } 1502 */ 1503 protected function getFontStyles(DOMElement $textProperty, string $styleNs, string $fontNs): array 1504 { 1505 $fonts = []; 1506 $temp = $textProperty->getAttributeNs($styleNs, 'font-name') ?: $textProperty->getAttributeNs($fontNs, 'font-family'); 1507 if ($temp !== '') { 1508 $fonts['name'] = $temp; 1509 } 1510 $temp = $textProperty->getAttributeNs($fontNs, 'font-size'); 1511 if ($temp !== '' && str_ends_with($temp, 'pt')) { 1512 $fonts['size'] = (float) substr($temp, 0, -2); 1513 } 1514 $temp = $textProperty->getAttributeNs($fontNs, 'font-style'); 1515 if ($temp === 'italic') { 1516 $fonts['italic'] = true; 1517 } 1518 $temp = $textProperty->getAttributeNs($fontNs, 'font-weight'); 1519 if ($temp === 'bold') { 1520 $fonts['bold'] = true; 1521 } 1522 $temp = $textProperty->getAttributeNs($fontNs, 'color'); 1523 if (Preg::isMatch('/^#[a-f0-9]{6}$/i', $temp)) { 1524 $fonts['color'] = ['rgb' => (string) substr($temp, 1)]; 1525 } 1526 $temp = $textProperty->getAttributeNs($styleNs, 'use-window-font-color'); 1527 if ($temp === 'true') { 1528 $fonts['autoColor'] = true; 1529 } 1530 $temp = $textProperty->getAttributeNs($styleNs, 'text-underline-type'); 1531 if ($temp === '') { 1532 $temp = $textProperty->getAttributeNs($styleNs, 'text-underline-style'); 1533 if ($temp !== '' && $temp !== 'none') { 1534 $temp = 'single'; 1535 } 1536 } 1537 if ($temp === 'single' || $temp === 'double') { 1538 $fonts['underline'] = $temp; 1539 } 1540 $temp = $textProperty->getAttributeNs($styleNs, 'text-line-through-type'); 1541 if ($temp !== '' && $temp !== 'none') { 1542 $fonts['strikethrough'] = true; 1543 } 1544 1545 return $fonts; 1546 } 1547 1548 /** @return array{ 1549 * fillType?: string, 1550 * startColor?: array{rgb: string}, 1551 * } 1552 */ 1553 protected function getFillStyles(DOMElement $tableCellProperties, string $fontNs): array 1554 { 1555 $fills = []; 1556 $temp = $tableCellProperties->getAttributeNs($fontNs, 'background-color'); 1557 if (Preg::isMatch('/^#[a-f0-9]{6}$/i', $temp)) { 1558 $fills['fillType'] = Fill::FILL_SOLID; 1559 $fills['startColor'] = ['rgb' => (string) substr($temp, 1)]; 1560 } elseif ($temp === 'transparent') { 1561 $fills['fillType'] = Fill::FILL_NONE; 1562 } 1563 1564 return $fills; 1565 } 1566 1567 private const MAP_VERTICAL = [ 1568 'top' => Alignment::VERTICAL_TOP, 1569 'middle' => Alignment::VERTICAL_CENTER, 1570 'automatic' => Alignment::VERTICAL_JUSTIFY, 1571 'bottom' => Alignment::VERTICAL_BOTTOM, 1572 ]; 1573 private const MAP_HORIZONTAL = [ 1574 'center' => Alignment::HORIZONTAL_CENTER, 1575 'end' => Alignment::HORIZONTAL_RIGHT, 1576 'justify' => Alignment::HORIZONTAL_FILL, 1577 'start' => Alignment::HORIZONTAL_LEFT, 1578 ]; 1579 1580 /** @return array{ 1581 * shrinkToFit?: bool, 1582 * textRotation?: int, 1583 * vertical?: string, 1584 * wrapText?: bool, 1585 * } 1586 */ 1587 protected function getAlignment1Styles(DOMElement $tableCellProperties, string $styleNs, string $fontNs): array 1588 { 1589 $alignment1 = []; 1590 $temp = $tableCellProperties->getAttributeNs($styleNs, 'rotation-angle'); 1591 if (is_numeric($temp)) { 1592 $temp2 = (int) $temp; 1593 if ($temp2 > 90) { 1594 $temp2 -= 360; 1595 } 1596 if ($temp2 >= -90 && $temp2 <= 90) { 1597 $alignment1['textRotation'] = (int) $temp2; 1598 } 1599 } 1600 $temp = $tableCellProperties->getAttributeNs($styleNs, 'vertical-align'); 1601 $temp2 = self::MAP_VERTICAL[$temp] ?? ''; 1602 if ($temp2 !== '') { 1603 $alignment1['vertical'] = $temp2; 1604 } 1605 $temp = $tableCellProperties->getAttributeNs($fontNs, 'wrap-option'); 1606 if ($temp === 'wrap') { 1607 $alignment1['wrapText'] = true; 1608 } elseif ($temp === 'no-wrap') { 1609 $alignment1['wrapText'] = false; 1610 } 1611 $temp = $tableCellProperties->getAttributeNs($styleNs, 'shrink-to-fit'); 1612 if ($temp === 'true' || $temp === 'false') { 1613 $alignment1['shrinkToFit'] = $temp === 'true'; 1614 } 1615 1616 return $alignment1; 1617 } 1618 1619 /** @return array{ 1620 * horizontal?: string, 1621 * readOrder?: int, 1622 * } 1623 */ 1624 protected function getAlignment2Styles(DOMElement $paragraphProperties, string $styleNs, string $fontNs): array 1625 { 1626 $alignment2 = []; 1627 $temp = $paragraphProperties->getAttributeNs($fontNs, 'text-align'); 1628 $temp2 = self::MAP_HORIZONTAL[$temp] ?? ''; 1629 if ($temp2 !== '') { 1630 $alignment2['horizontal'] = $temp2; 1631 } 1632 $temp = $paragraphProperties->getAttributeNs($fontNs, 'margin-left') ?: $paragraphProperties->getAttributeNs($fontNs, 'margin-right'); 1633 if (Preg::isMatch('/^\d+([.]\d+)?(cm|in|mm|pt)$/', $temp)) { 1634 $dimension = new HelperDimension($temp); 1635 $alignment2['indent'] = (int) round($dimension->toUnit('px') / Alignment::INDENT_UNITS_TO_PIXELS); 1636 } 1637 1638 $temp = $paragraphProperties->getAttributeNs($styleNs, 'writing-mode'); 1639 if ($temp === 'rl-tb') { 1640 $alignment2['readOrder'] = Alignment::READORDER_RTL; 1641 } elseif ($temp === 'lr-tb') { 1642 $alignment2['readOrder'] = Alignment::READORDER_LTR; 1643 } 1644 1645 return $alignment2; 1646 } 1647 1648 /** @return array{ 1649 * locked?: string, 1650 * hidden?: string, 1651 * } 1652 */ 1653 protected function getProtectionStyles(DOMElement $tableCellProperties, string $styleNs): array 1654 { 1655 $protection = []; 1656 $temp = $tableCellProperties->getAttributeNs($styleNs, 'cell-protect'); 1657 switch ($temp) { 1658 case 'protected formula-hidden': 1659 $protection['locked'] = Protection::PROTECTION_PROTECTED; 1660 $protection['hidden'] = Protection::PROTECTION_PROTECTED; 1661 1662 break; 1663 case 'formula-hidden': 1664 $protection['locked'] = Protection::PROTECTION_UNPROTECTED; 1665 $protection['hidden'] = Protection::PROTECTION_PROTECTED; 1666 1667 break; 1668 case 'protected': 1669 $protection['locked'] = Protection::PROTECTION_PROTECTED; 1670 $protection['hidden'] = Protection::PROTECTION_UNPROTECTED; 1671 1672 break; 1673 case 'none': 1674 $protection['locked'] = Protection::PROTECTION_UNPROTECTED; 1675 $protection['hidden'] = Protection::PROTECTION_UNPROTECTED; 1676 1677 break; 1678 } 1679 1680 return $protection; 1681 } 1682 1683 private const MAP_BORDER_STYLE = [ // default BORDER_THIN 1684 'none' => Border::BORDER_NONE, 1685 'hidden' => Border::BORDER_NONE, 1686 'dotted' => Border::BORDER_DOTTED, 1687 'dash-dot' => Border::BORDER_DASHDOT, 1688 'dash-dot-dot' => Border::BORDER_DASHDOTDOT, 1689 'dashed' => Border::BORDER_DASHED, 1690 'double' => Border::BORDER_DOUBLE, 1691 ]; 1692 1693 private const MAP_BORDER_MEDIUM = [ 1694 Border::BORDER_THIN => Border::BORDER_MEDIUM, 1695 Border::BORDER_DASHDOT => Border::BORDER_MEDIUMDASHDOT, 1696 Border::BORDER_DASHDOTDOT => Border::BORDER_MEDIUMDASHDOTDOT, 1697 Border::BORDER_DASHED => Border::BORDER_MEDIUMDASHED, 1698 ]; 1699 1700 private const MAP_BORDER_THICK = [ 1701 Border::BORDER_THIN => Border::BORDER_THICK, 1702 Border::BORDER_DASHDOT => Border::BORDER_MEDIUMDASHDOT, 1703 Border::BORDER_DASHDOTDOT => Border::BORDER_MEDIUMDASHDOTDOT, 1704 Border::BORDER_DASHED => Border::BORDER_MEDIUMDASHED, 1705 ]; 1706 1707 /** @return array{ 1708 * bottom?: array{borderStyle:string, color:array{rgb: string}}, 1709 * top?: array{borderStyle:string, color:array{rgb: string}}, 1710 * left?: array{borderStyle:string, color:array{rgb: string}}, 1711 * right?: array{borderStyle:string, color:array{rgb: string}}, 1712 * diagonal?: array{borderStyle:string, color:array{rgb: string}}, 1713 * diagonalDirection?: int, 1714 * } 1715 */ 1716 protected function getBorderStyles(DOMElement $tableCellProperties, string $fontNs, string $styleNs): array 1717 { 1718 $borders = []; 1719 $temp = $tableCellProperties->getAttributeNs($fontNs, 'border'); 1720 $diagonalIndex = Borders::DIAGONAL_NONE; 1721 foreach (['bottom', 'left', 'right', 'top', 'diagonal-tl-br', 'diagonal-bl-tr'] as $direction) { 1722 if (str_starts_with($direction, 'diagonal')) { 1723 $directionIndex = 'diagonal'; 1724 $temp = $tableCellProperties->getAttributeNs($styleNs, $direction); 1725 } else { 1726 $directionIndex = $direction; 1727 $temp = $tableCellProperties->getAttributeNs($fontNs, "border-$direction"); 1728 } 1729 if (Preg::isMatch('/^(\d+(?:[.]\d+)?)pt\s+([-\w]+)\s+#([0-9a-fA-F]{6})$/', $temp, $matches)) { 1730 $style = self::MAP_BORDER_STYLE[$matches[2]] ?? Border::BORDER_THIN; 1731 $width = (float) $matches[1]; 1732 if ($width >= 2.5) { 1733 $style = self::MAP_BORDER_THICK[$style] ?? $style; 1734 } elseif ($width >= 1.75) { 1735 $style = self::MAP_BORDER_MEDIUM[$style] ?? $style; 1736 } 1737 $color = $matches[3]; 1738 $borders[$directionIndex] = ['borderStyle' => $style, 'color' => ['rgb' => $matches[3]]]; 1739 if ($direction === 'diagonal-tl-br') { 1740 $diagonalIndex = Borders::DIAGONAL_DOWN; 1741 } elseif ($direction === 'diagonal-bl-tr') { 1742 $diagonalIndex = ($diagonalIndex === Borders::DIAGONAL_NONE) ? Borders::DIAGONAL_UP : Borders::DIAGONAL_BOTH; 1743 } 1744 } 1745 } 1746 if ($diagonalIndex !== Borders::DIAGONAL_NONE) { 1747 $borders['diagonalDirection'] = $diagonalIndex; 1748 } 1749 1750 return $borders; // @phpstan-ignore-line 1751 } 1102 1752 } -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Reader/Ods/PageSettings.php
r3463039 r3473263 69 69 $marginBottom = ($nullsafeVariable8 = $pageLayoutProperties) ? $nullsafeVariable8->getAttributeNS($this->stylesFo, 'margin-bottom') : null; 70 70 $header = $styleSet->getElementsByTagNameNS($this->stylesNs, 'header-style')->item(0); 71 $headerProperties = ($nullsafeVariable9 = ($nullsafeVariable1 3 = $header) ? $nullsafeVariable13->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties') : null) ? $nullsafeVariable9->item(0) : null;72 $marginHeader = ($nullsafeVariable1 0 = $headerProperties) ? $nullsafeVariable10->getAttributeNS($this->stylesFo, 'min-height') : null;71 $headerProperties = ($nullsafeVariable9 = ($nullsafeVariable10 = $header) ? $nullsafeVariable10->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties') : null) ? $nullsafeVariable9->item(0) : null; 72 $marginHeader = ($nullsafeVariable11 = $headerProperties) ? $nullsafeVariable11->getAttributeNS($this->stylesFo, 'min-height') : null; 73 73 $footer = $styleSet->getElementsByTagNameNS($this->stylesNs, 'footer-style')->item(0); 74 $footerProperties = ($nullsafeVariable1 1 = ($nullsafeVariable14 = $footer) ? $nullsafeVariable14->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties') : null) ? $nullsafeVariable11->item(0) : null;75 $marginFooter = ($nullsafeVariable1 2 = $footerProperties) ? $nullsafeVariable12->getAttributeNS($this->stylesFo, 'min-height') : null;74 $footerProperties = ($nullsafeVariable12 = ($nullsafeVariable13 = $footer) ? $nullsafeVariable13->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties') : null) ? $nullsafeVariable12->item(0) : null; 75 $marginFooter = ($nullsafeVariable14 = $footerProperties) ? $nullsafeVariable14->getAttributeNS($this->stylesFo, 'min-height') : null; 76 76 77 77 $this->pageLayoutStyles[$styleName] = (object) [ -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Reader/Xlsx.php
r3463039 r3473263 699 699 $this->styleReader 700 700 ->readStyle($objStyle, $style); 701 if (isset($xfTag->extLst)) { 702 foreach ($xfTag->extLst->ext as $extTag) { 703 $attributes = $extTag->attributes(); 704 if (isset($attributes['uri'])) { 705 if ((string) $attributes['uri'] === Namespaces::STYLE_CHECKBOX_URI) { 706 $objStyle->setCheckBox(true); 707 } 708 } 709 } 710 } 701 711 foreach ($this->styleReader->getFontCharsets() as $fontName => $charset) { 702 712 $excel->addFontCharset($fontName, $charset); … … 1599 1609 if (isset($images[$linkImageKey])) { 1600 1610 $url = str_replace('xl/drawings/', '', $images[$linkImageKey]); 1601 $objDrawing->setPath($url, false, null, $this->allowExternalImages );1611 $objDrawing->setPath($url, false, null, $this->allowExternalImages, $this->isWhitelisted); 1602 1612 } 1603 1613 if ($objDrawing->getPath() === '') { … … 1703 1713 if (isset($images[$linkImageKey])) { 1704 1714 $url = str_replace('xl/drawings/', '', $images[$linkImageKey]); 1705 $objDrawing->setPath($url, false, null, $this->allowExternalImages );1715 $objDrawing->setPath($url, false, null, $this->allowExternalImages, $this->isWhitelisted); 1706 1716 } 1707 1717 if ($objDrawing->getPath() === '') { … … 2233 2243 if (str_contains($item[1], 'px')) { 2234 2244 $item[1] = str_replace('px', '', $item[1]); 2235 } 2236 if (str_contains($item[1], 'pt')) { 2245 } elseif (str_contains($item[1], 'pt')) { 2237 2246 $item[1] = str_replace('pt', '', $item[1]); 2238 $item[1] = (string) Font::fontSizeToPixels((int) $item[1]); 2239 } 2240 if (str_contains($item[1], 'in')) { 2247 $item[1] = Font::fontSizeToPixels((float) $item[1]); 2248 } elseif (str_contains($item[1], 'in')) { 2241 2249 $item[1] = str_replace('in', '', $item[1]); 2242 $item[1] = (string) Font::inchSizeToPixels((int) $item[1]); 2243 } 2244 if (str_contains($item[1], 'cm')) { 2250 $item[1] = (int) Font::inchSizeToPixels((float) $item[1]); 2251 } elseif (str_contains($item[1], 'cm')) { 2245 2252 $item[1] = str_replace('cm', '', $item[1]); 2246 $item[1] = (string) Font::centimeterSizeToPixels((int) $item[1]); 2253 $item[1] = (int) Font::centimeterSizeToPixels((float) $item[1]); 2254 } elseif (str_contains($item[1], 'mm')) { 2255 $item[1] = str_replace('mm', '', $item[1]); 2256 $item[1] = (int) Font::centimeterSizeToPixels((float) $item[1] / 10); 2247 2257 } 2248 2258 -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Reader/Xlsx/Namespaces.php
r3463039 r3473263 130 130 131 131 const RELATIONSHIPS_RICH_VALUE_REL = 'http://schemas.microsoft.com/office/2022/10/relationships/richValueRel'; 132 133 const FEATURE_PROPERTY_BAG = 'http://schemas.microsoft.com/office/spreadsheetml/2022/featurepropertybag'; 134 const RELATIONSHIPS_FEATURE_PROPERTY_BAG = 'http://schemas.microsoft.com/office/2022/11/relationships/FeaturePropertyBag'; 135 const STYLE_CHECKBOX_URI = '{C7286773-470A-42A8-94C5-96B5CB345126}'; 132 136 } -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Spreadsheet.php
r3463039 r3473263 3 3 namespace TablePress\PhpOffice\PhpSpreadsheet; 4 4 5 use TablePress\Composer\Pcre\Preg; 5 6 use JsonSerializable; 6 7 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Calculation; … … 1065 1066 if ($worksheet !== null) { 1066 1067 $wsTitle = StringHelper::strToUpper($worksheet->getTitle()); 1067 $definedName = (string) preg_replace('/^.*!/', '', $definedName);1068 $definedName = Preg::replace('/^.*!/', '', $definedName); 1068 1069 foreach ($this->definedNames as $dn) { 1069 1070 $sheet = $dn->getScope() ?? $dn->getWorksheet(); … … 1870 1871 } 1871 1872 1873 /** 1874 * Change all 2-digit-year date styles to use 4-digit year; 1875 * change all dd-mm-yyyy and mm-dd-yyyy styles to yyyy-mm-dd; 1876 * dd-mmm-yyyy is unambiguous and left unchanged. 1877 */ 1878 public function disambiguateDateStyles(): void 1879 { 1880 foreach ($this->cellXfCollection as $style) { 1881 $numberFormat = $style->getNumberFormat(); 1882 $oldFormat = (string) $numberFormat->getFormatCode(); 1883 $newFormat = Preg::replace('/\byy\b/i', 'yyyy', $oldFormat); 1884 $newFormat = Preg::replace( 1885 '~\bdd?(-|/|"-"|"/")' 1886 . 'mm?(-|/|"-"|"/")' 1887 . 'yyyy~', 1888 'yyyy-mm-dd', 1889 $newFormat 1890 ); 1891 $newFormat = Preg::replace( 1892 '~\bmm?(-|/|"-"|"/")' 1893 . 'dd?(-|/|"-"|"/")' 1894 . 'yyyy~', 1895 'yyyy-mm-dd', 1896 $newFormat 1897 ); 1898 if ($newFormat !== $oldFormat) { 1899 $numberFormat->setFormatCode($newFormat); 1900 } 1901 } 1902 } 1903 1872 1904 public function returnArrayAsArray(): void 1873 1905 { … … 1904 1936 return $this->domainWhiteList; 1905 1937 } 1938 1939 private bool $usesCheckBoxStyle = false; 1940 1941 public function getUsesCheckBoxStyle(): bool 1942 { 1943 return $this->usesCheckBoxStyle; 1944 } 1945 1946 public function setUsesCheckBoxStyle(): bool 1947 { 1948 $this->usesCheckBoxStyle = false; 1949 foreach ($this->getCellXfCollection() as $cellXf) { 1950 if ($cellXf->getCheckBox()) { 1951 $this->usesCheckBoxStyle = true; 1952 1953 break; 1954 } 1955 } 1956 1957 return $this->usesCheckBoxStyle; 1958 } 1906 1959 } -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Style/Alignment.php
r3420898 r3473263 366 366 } 367 367 } else { 368 throw new PhpSpreadsheetException( 'Text rotation should be a value between -90 and 90.');368 throw new PhpSpreadsheetException("Text rotation $angleInDegrees should be a value between -90 and 90."); 369 369 } 370 370 -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Style/Font.php
r3350024 r3473263 178 178 * </code> 179 179 * 180 * @param array{name?: string, latin?: string, eastAsian?: string, complexScript?: string, bold?: bool, italic?: bool, superscript?: bool, subscript?: bool, underline?: bool|string, strikethrough?: bool, color?: string[], size?: ?int, chartColor?: ChartColor, scheme?: string, cap?: string, autoColor?: bool} $styleArray Array containing style information 180 * @param array{ 181 * autoColor?: bool, 182 * bold?: bool, 183 * cap?: string, 184 * chartColor?: ChartColor, 185 * color?: string[], 186 * complexScript?: string, 187 * eastAsian?: string, 188 * italic?: bool, 189 * latin?: string, 190 * name?: string, 191 * scheme?: string, 192 * size?: null|float|int, 193 * strikethrough?: bool, 194 * superscript?: bool, 195 * subscript?: bool, 196 * underline?: bool|string, 197 * } $styleArray Array containing style information 181 198 * 182 199 * @return $this -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Style/NumberFormat.php
r3385566 r3473263 24 24 const FORMAT_DATE_YYYYMMDD = 'yyyy-mm-dd'; 25 25 const FORMAT_DATE_DDMMYYYY = 'dd/mm/yyyy'; 26 const FORMAT_DATE_DMYSLASH = 'd /m/yy';26 const FORMAT_DATE_DMYSLASH = 'd"/"m"/"yy'; 27 27 const FORMAT_DATE_DMYMINUS = 'd-m-yy'; 28 28 const FORMAT_DATE_DMMINUS = 'd-m'; … … 31 31 const FORMAT_DATE_XLSX14_ACTUAL = 'm/d/yyyy'; 32 32 const FORMAT_DATE_XLSX15 = 'd-mmm-yy'; 33 const FORMAT_DATE_XLSX15_YYYY = 'd-mmm-yyyy'; 33 34 const FORMAT_DATE_XLSX16 = 'd-mmm'; 34 35 const FORMAT_DATE_XLSX17 = 'mmm-yy'; … … 36 37 const FORMAT_DATE_XLSX22_ACTUAL = 'm/d/yyyy h:mm'; 37 38 const FORMAT_DATE_DATETIME = 'd/m/yy h:mm'; 39 const FORMAT_DATE_DATETIME_BETTER = 'yyyy-mm-dd hh:mm'; 38 40 const FORMAT_DATE_TIME1 = 'h:mm AM/PM'; 39 41 const FORMAT_DATE_TIME2 = 'h:mm:ss AM/PM'; … … 44 46 const FORMAT_DATE_TIME7 = 'i:s.S'; 45 47 const FORMAT_DATE_TIME8 = 'h:mm:ss;@'; 46 const FORMAT_DATE_YYYYMMDDSLASH = 'yyyy/mm/dd;@'; 48 const FORMAT_DATE_TIME_INTERVAL_HMS = '[hh]:mm:ss'; 49 const FORMAT_DATE_YYYYMMDDSLASH = 'yyyy"/"mm"/"dd;@'; 47 50 const FORMAT_DATE_LONG_DATE = 'dddd, mmmm d, yyyy'; 48 51 … … 62 65 self::FORMAT_DATE_XLSX22_ACTUAL, 63 66 self::FORMAT_DATE_DATETIME, 67 self::FORMAT_DATE_DATETIME_BETTER, 64 68 self::FORMAT_DATE_TIME1, 65 69 self::FORMAT_DATE_TIME2, … … 70 74 self::FORMAT_DATE_TIME7, 71 75 self::FORMAT_DATE_TIME8, 76 self::FORMAT_DATE_TIME_INTERVAL_HMS, 72 77 self::FORMAT_DATE_YYYYMMDDSLASH, 73 78 self::FORMAT_DATE_LONG_DATE, … … 76 81 self::FORMAT_DATE_XLSX22, 77 82 self::FORMAT_DATE_DATETIME, 83 self::FORMAT_DATE_DATETIME_BETTER, 78 84 self::FORMAT_DATE_TIME1, 79 85 self::FORMAT_DATE_TIME2, … … 84 90 self::FORMAT_DATE_TIME7, 85 91 self::FORMAT_DATE_TIME8, 92 self::FORMAT_DATE_TIME_INTERVAL_HMS, 86 93 ]; 87 94 88 const FORMAT_CURRENCY_USD_INTEGER = '$#,##0_-'; 89 const FORMAT_CURRENCY_USD = '$#,##0.00_-'; 95 private const FORMAT_CURRENCY_AMOUNT_INTEGER = '#,##0_-'; 96 private const FORMAT_CURRENCY_AMOUNT_FLOAT = '#,##0.00_-'; 97 const FORMAT_CURRENCY_USD_INTEGER = '$' . self::FORMAT_CURRENCY_AMOUNT_INTEGER; 98 const FORMAT_CURRENCY_USD = '$' . self::FORMAT_CURRENCY_AMOUNT_FLOAT; 99 const FORMAT_CURRENCY_GBP_INTEGER = '£' . self::FORMAT_CURRENCY_AMOUNT_INTEGER; 100 const FORMAT_CURRENCY_GBP = '£' . self::FORMAT_CURRENCY_AMOUNT_FLOAT; 101 const FORMAT_CURRENCY_YEN_YUAN_INTEGER = '¥' . self::FORMAT_CURRENCY_AMOUNT_INTEGER; 102 const FORMAT_CURRENCY_YEN_YUAN = '¥' . self::FORMAT_CURRENCY_AMOUNT_FLOAT; 90 103 const FORMAT_CURRENCY_EUR_INTEGER = '#,##0_-[$€]'; 91 104 const FORMAT_CURRENCY_EUR = '#,##0.00_-[$€]'; -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php
r3420898 r3473263 3 3 namespace TablePress\PhpOffice\PhpSpreadsheet\Style\NumberFormat; 4 4 5 use TablePress\Composer\Pcre\Preg; 5 6 use TablePress\PhpOffice\PhpSpreadsheet\Shared\Date; 6 7 use TablePress\PhpOffice\PhpSpreadsheet\Shared\StringHelper; … … 122 123 public static function format($value, string $format): string 123 124 { 125 if ($value < 0 && Preg::isMatch('/^\[?[hms]/i', $format)) { 126 return '-' . self::format(-$value, $format); 127 } 124 128 // strip off first part containing e.g. [$-F800] or [$USD-409] 125 129 // general syntax: [$<Currency string>-<language info>] 126 130 // language info is in hexadecimal 127 131 // strip off chinese part like [DBNum1][$-804] 128 $format = (string) preg_replace('/^(\[DBNum\d\])*(\[\$[^\]]*\])/i', '', $format);132 $format = Preg::replace('/^(\[DBNum\d\])*(\[\$[^\]]*\])/i', '', $format); 129 133 130 134 // OpenOffice.org uses upper-case number formats, e.g. 'YYYY', convert to lower-case; 131 135 // but we don't want to change any quoted strings 132 /** @var callable $callable */ 133 $callable = [self::class, 'setLowercaseCallback']; 134 $format = (string) preg_replace_callback('/(?:^|")([^"]*)(?:$|")/', $callable, $format); 136 $format = Preg::replaceCallback('/(?:^|")([^"]*)(?:$|")/', \Closure::fromCallable([self::class, 'setLowerCaseCallback']), $format); 135 137 136 138 // Only process the non-quoted blocks for date format characters … … 160 162 161 163 // escape any quoted characters so that DateTime format() will render them correctly 162 /** @var callable $callback */ 163 $callback = [self::class, 'escapeQuotesCallback']; 164 $format = (string) preg_replace_callback('/"(.*)"/U', $callback, $format); 164 $format = Preg::replaceCallback('/"(.*)"/U', \Closure::fromCallable([self::class, 'escapeQuotesCallback']), $format); 165 165 166 166 try { … … 172 172 // Excel 2003 XML formats, m will not have been changed to i above. 173 173 // Change it now. 174 $format = (string) \preg_replace('/\\\:m/', ':i', $format);174 $format = Preg::replace('/\\\:m/', ':i', $format); 175 175 $microseconds = (int) $dateObj->format('u'); 176 176 if (str_contains($format, ':s.000')) { … … 208 208 } 209 209 210 /** @param string[]$matches */210 /** @param array<?string> $matches */ 211 211 private static function setLowercaseCallback(array $matches): string 212 212 { 213 /** @var string[] $matches */ 213 214 return mb_strtolower($matches[0]); 214 215 } 215 216 216 /** @param string[]$matches */217 /** @param array<?string> $matches */ 217 218 private static function escapeQuotesCallback(array $matches): string 218 219 { 220 /** @var string[] $matches */ 219 221 return '\\' . implode('\\', mb_str_split($matches[1], 1, 'UTF-8')); 220 222 } -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Style/Style.php
r3385566 r3473263 52 52 */ 53 53 protected bool $quotePrefix = false; 54 55 protected bool $checkBox = false; 54 56 55 57 /** … … 485 487 * numberFormat?: string[], 486 488 * protection?: array{locked?: string, hidden?: string}, 489 * checkBox?: bool, 487 490 * quotePrefix?: bool} $styleArray */ 491 if (isset($styleArray['checkBox'])) { 492 $this->checkBox = (bool) $styleArray['checkBox']; 493 } 488 494 if (isset($styleArray['fill'])) { 489 495 $this->getFill() … … 701 707 } 702 708 709 public function getCheckBox(): bool 710 { 711 if ($this->isSupervisor) { 712 return $this->getSharedComponent()->getCheckBox(); 713 } 714 715 return $this->checkBox; 716 } 717 718 /** 719 * @return static 720 */ 721 public function setCheckBox(bool $checkBox) 722 { 723 if ($this->isSupervisor) { 724 $styleArray = ['checkBox' => $checkBox]; 725 $this->getActiveSheet() 726 ->getStyle($this->getSelectedCells()) 727 ->applyFromArray($styleArray); 728 } else { 729 $this->checkBox = $checkBox; 730 } 731 732 return $this; 733 } 734 703 735 /** 704 736 * Get hash code. … … 716 748 . $this->protection->getHashCode() 717 749 . ($this->quotePrefix ? 't' : 'f') 750 . ($this->checkBox ? 't' : 'f') 718 751 . __CLASS__ 719 752 ); -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Worksheet/Drawing.php
r3420898 r3473263 90 90 * @param bool $verifyFile Verify file 91 91 * @param ?ZipArchive $zip Zip archive instance 92 * @param null|callable(string):bool $isWhitelisted 92 93 * 93 94 * @return $this 94 95 */ 95 public function setPath(string $path, bool $verifyFile = true, ?ZipArchive $zip = null, bool $allowExternal = true )96 public function setPath(string $path, bool $verifyFile = true, ?ZipArchive $zip = null, bool $allowExternal = true, ?callable $isWhitelisted = null) 96 97 { 97 98 $this->isUrl = false; … … 103 104 104 105 $this->path = ''; 106 if ($zip instanceof ZipArchive) { 107 $zipPath = explode('#', $path)[1]; 108 $locate = @$zip->locateName($zipPath); 109 if ($locate !== false) { 110 if ($this->isImage($path)) { 111 $this->path = $path; 112 $this->setSizesAndType($path); 113 } 114 } 105 115 // Check if a URL has been passed. https://stackoverflow.com/a/2058596/1252979 106 if (filter_var($path, FILTER_VALIDATE_URL) || (preg_match('/^([\w\s\x00-\x1f]+):/u', $path) && !preg_match('/^([\w]+):/u', $path))) {116 } elseif (filter_var($path, FILTER_VALIDATE_URL) || (preg_match('/^([\w\s\x00-\x1f]+):/u', $path) && !preg_match('/^([\w]+):/u', $path))) { 107 117 if (!preg_match('/^(http|https|file|ftp|s3):/', $path)) { 108 118 throw new PhpSpreadsheetException('Invalid protocol for linked drawing'); 109 119 } 110 120 if (!$allowExternal) { 121 return $this; 122 } 123 if ($isWhitelisted !== null && !$isWhitelisted($path)) { 111 124 return $this; 112 125 } … … 145 158 } 146 159 } 147 } elseif ($zip instanceof ZipArchive) {148 $zipPath = explode('#', $path)[1];149 $locate = @$zip->locateName($zipPath);150 if ($locate !== false) {151 if ($this->isImage($path)) {152 $this->path = $path;153 $this->setSizesAndType($path);154 }155 }156 160 } else { 157 161 $exists = @file_exists($path); -
tablepress/tags/3.2.8/libraries/vendor/PhpSpreadsheet/Worksheet/Worksheet.php
r3463039 r3473263 2981 2981 * @param bool $formatData Whether to format data according to cell's style. 2982 2982 * @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value 2983 * @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead. 2983 2984 * 2984 2985 * @throws Exception … … 2986 2987 * @return mixed 2987 2988 */ 2988 protected function cellToArray(Cell $cell, bool $calculateFormulas, bool $formatData, $nullValue, bool $lessFloatPrecision = false )2989 protected function cellToArray(Cell $cell, bool $calculateFormulas, bool $formatData, $nullValue, bool $lessFloatPrecision = false, $oldCalculatedValue = false) 2989 2990 { 2990 2991 $returnValue = $nullValue; … … 2993 2994 if ($cell->getValue() instanceof RichText) { 2994 2995 $returnValue = $cell->getValue()->getPlainText(); 2996 } elseif ($calculateFormulas) { 2997 $returnValue = $cell->getCalculatedValue(); 2998 } elseif ($oldCalculatedValue && ($cell->getDataType() === DataType::TYPE_FORMULA)) { 2999 $returnValue = $cell->getOldCalculatedValue() ?? $cell->getValue(); 2995 3000 } else { 2996 $returnValue = ($calculateFormulas) ? $cell->getCalculatedValue() :$cell->getValue();3001 $returnValue = $cell->getValue(); 2997 3002 } 2998 3003 … … 3020 3025 * @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value. 3021 3026 * @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value 3027 * @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead. 3022 3028 * 3023 3029 * @return mixed[][] … … 3031 3037 bool $ignoreHidden = false, 3032 3038 bool $reduceArrays = false, 3033 bool $lessFloatPrecision = false 3039 bool $lessFloatPrecision = false, 3040 bool $oldCalculatedValue = false 3034 3041 ): array { 3035 3042 $returnValue = []; 3036 3043 3037 3044 // Loop through rows 3038 foreach ($this->rangeToArrayYieldRows($range, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision ) as $rowRef => $rowArray) {3045 foreach ($this->rangeToArrayYieldRows($range, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision, $oldCalculatedValue) as $rowRef => $rowArray) { 3039 3046 /** @var int $rowRef */ 3040 3047 $returnValue[$rowRef] = $rowArray; … … 3057 3064 * @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value. 3058 3065 * @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value 3066 * @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead. 3059 3067 * 3060 3068 * @return mixed[][] … … 3068 3076 bool $ignoreHidden = false, 3069 3077 bool $reduceArrays = false, 3070 bool $lessFloatPrecision = false 3078 bool $lessFloatPrecision = false, 3079 bool $oldCalculatedValue = false 3071 3080 ): array { 3072 3081 $returnValue = []; … … 3075 3084 foreach ($parts as $part) { 3076 3085 // Loop through rows 3077 foreach ($this->rangeToArrayYieldRows($part, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision ) as $rowRef => $rowArray) {3086 foreach ($this->rangeToArrayYieldRows($part, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision, $oldCalculatedValue) as $rowRef => $rowArray) { 3078 3087 /** @var int $rowRef */ 3079 3088 $returnValue[$rowRef] = $rowArray; … … 3097 3106 * @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value. 3098 3107 * @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value 3108 * @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead. 3099 3109 * 3100 3110 * @return Generator<array<mixed>> … … 3108 3118 bool $ignoreHidden = false, 3109 3119 bool $reduceArrays = false, 3110 bool $lessFloatPrecision = false 3120 bool $lessFloatPrecision = false, 3121 bool $oldCalculatedValue = false 3111 3122 ) { 3112 3123 $range = Validations::validateCellOrCellRange($range); … … 3174 3185 $cell = $this->cellCollection->get("{$col}{$thisRow}"); 3175 3186 if ($cell !== null) { 3176 $value = $this->cellToArray($cell, $calculateFormulas, $formatData, $nullValue, $lessFloatPrecision );3187 $value = $this->cellToArray($cell, $calculateFormulas, $formatData, $nullValue, $lessFloatPrecision, $oldCalculatedValue); 3177 3188 if ($reduceArrays) { 3178 3189 while (is_array($value)) { … … 3277 3288 * @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value. 3278 3289 * @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value 3290 * @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead. 3279 3291 * 3280 3292 * @return mixed[][] … … 3288 3300 bool $ignoreHidden = false, 3289 3301 bool $reduceArrays = false, 3290 bool $lessFloatPrecision = false 3302 bool $lessFloatPrecision = false, 3303 bool $oldCalculatedValue = false 3291 3304 ): array { 3292 3305 $retVal = []; … … 3297 3310 $workSheet = $namedRange->getWorksheet(); 3298 3311 if ($workSheet !== null) { 3299 $retVal = $workSheet->rangeToArray($cellRange, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision );3312 $retVal = $workSheet->rangeToArray($cellRange, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision, $oldCalculatedValue); 3300 3313 } 3301 3314 } … … 3316 3329 * @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value. 3317 3330 * @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value 3331 * @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead. 3318 3332 * 3319 3333 * @return mixed[][] … … 3326 3340 bool $ignoreHidden = false, 3327 3341 bool $reduceArrays = false, 3328 bool $lessFloatPrecision = false 3342 bool $lessFloatPrecision = false, 3343 bool $oldCalculatedValue = false 3329 3344 ): array { 3330 3345 // Garbage collect... … … 3337 3352 3338 3353 // Return 3339 return $this->rangeToArray("A1:{$maxCol}{$maxRow}", $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision );3354 return $this->rangeToArray("A1:{$maxCol}{$maxRow}", $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision, $oldCalculatedValue); 3340 3355 } 3341 3356 -
tablepress/tags/3.2.8/libraries/vendor/autoload-classmap.php
r3463039 r3473263 263 263 'TablePress\PhpOffice\PhpSpreadsheet\Calculation\Database\DCount' => $strauss_src . '/PhpSpreadsheet/Calculation/Database/DCount.php', 264 264 'TablePress\PhpOffice\PhpSpreadsheet\Calculation\Database\DSum' => $strauss_src . '/PhpSpreadsheet/Calculation/Database/DSum.php', 265 'TablePress\PhpOffice\PhpSpreadsheet\Calculation\CalculationParserOnly' => $strauss_src . '/PhpSpreadsheet/Calculation/CalculationParserOnly.php', 265 266 'TablePress\PhpOffice\PhpSpreadsheet\Calculation\FunctionArray' => $strauss_src . '/PhpSpreadsheet/Calculation/FunctionArray.php', 266 267 'TablePress\PhpOffice\PhpSpreadsheet\Calculation\Information\Info' => $strauss_src . '/PhpSpreadsheet/Calculation/Information/Info.php', -
tablepress/tags/3.2.8/readme.txt
r3463039 r3473263 6 6 Requires PHP: 7.4 7 7 Tested up to: 6.9 8 Stable tag: 3.2. 78 Stable tag: 3.2.8 9 9 License: GPLv2 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 108 108 109 109 Changes in recent versions are shown below. For earlier changes, please see the [changelog history](https://tablepress.org/info/#changelog). 110 111 = Version 3.2.8 (March 3, 2026) = 112 113 * Bugfix: Whitespace handling for the “Filter Term Separator” setting in the “Column Filter Dropdowns” feature module now works properly again. (TablePress Pro and Max only.) 114 * Enhancement: The “Column Filter Dropdowns” feature module integration when using “Server-side Processing” is now more reliable. (TablePress Max only.) 115 * Cleaned up and simplified code, for easier future maintenance, to follow WordPress Coding Standards, and to offer helpful inline documentation. 116 * Several external code libraries and build tools have been updated to benefit from enhancements and bug fixes. 117 * Improved support for PHP 8.5. 110 118 111 119 = Version 3.2.7 (February 17, 2026) = … … 212 220 == Upgrade Notice == 213 221 214 = 3.2. 7=222 = 3.2.8 = 215 223 This update is an enhancement, stability, maintenance, and compatibility release. Updating is highly recommended! 216 224 -
tablepress/tags/3.2.8/tablepress.php
r3463039 r3473263 5 5 * @package TablePress 6 6 * @author Tobias Bäthge 7 * @version 3.2. 77 * @version 3.2.8 8 8 * 9 9 * … … 11 11 * Plugin URI: https://tablepress.org/ 12 12 * Description: Embed beautiful and interactive tables into your WordPress website’s posts and pages, without having to write code! 13 * Version: 3.2. 713 * Version: 3.2.8 14 14 * Requires at least: 6.2 15 15 * Requires PHP: 7.4 … … 70 70 'has_addons' => false, 71 71 'has_paid_plans' => true, 72 'is_org_compliant' => true, 72 73 'menu' => array( 73 74 'slug' => 'tablepress', -
tablepress/trunk/blocks/blocks-manifest.php
r3463039 r3473263 6 6 'apiVersion' => 3, 7 7 'name' => 'tablepress/table', 8 'version' => '3.2. 7',8 'version' => '3.2.8', 9 9 'title' => 'TablePress table', 10 10 'category' => 'media', -
tablepress/trunk/blocks/table/block.json
r3463039 r3473263 3 3 "apiVersion": 3, 4 4 "name": "tablepress/table", 5 "version": "3.2. 7",5 "version": "3.2.8", 6 6 "title": "TablePress table", 7 7 "category": "media", -
tablepress/trunk/classes/class-export.php
r3463039 r3473263 158 158 $active_content_triggers = array( '=', '+', '-', '@' ); 159 159 if ( in_array( $cell_content[0], $active_content_triggers, true ) ) { 160 // phpcs:disable Generic.Strings.UnnecessaryStringConcat.Found -- Avoid concatenation of function names to prevent false positives in code scanners. 160 161 $functions_to_escape = array( 161 162 'cmd|', 162 'FOR FILES|',163 'rund ll32',164 'DD E(',165 'IMPORT XML(',166 'IMPORT FEED(',167 'IMPORT HTML(',168 'IMPORT RANGE(',169 'IMPORT DATA(',163 'FOR' . 'FILES|', 164 'rund' . 'll32', 165 'DD' . 'E(', 166 'IMPORT' . 'XML(', 167 'IMPORT' . 'FEED(', 168 'IMPORT' . 'HTML(', 169 'IMPORT' . 'RANGE(', 170 'IMPORT' . 'DATA(', 170 171 'IMAGE(', 171 172 'HYPERLINK(', 172 173 'WEBSERVICE(', 173 174 ); 175 // phpcs:enable 174 176 175 177 $fn_stripos = function_exists( 'mb_stripos' ) ? 'mb_stripos' : 'stripos'; -
tablepress/trunk/classes/class-tablepress.php
r3463039 r3473263 28 28 * @const string 29 29 */ 30 public const version = '3.2. 7'; // phpcs:ignore Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase30 public const version = '3.2.8'; // phpcs:ignore Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase 31 31 32 32 /** … … 38 38 * @const int 39 39 */ 40 public const db_version = 12 1; // phpcs:ignore Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase40 public const db_version = 122; // phpcs:ignore Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase 41 41 42 42 /** -
tablepress/trunk/libraries/evalmath.class.php
r3381612 r3473263 400 400 401 401 // Do we now have a function/variable/number? 402 } elseif ( $ex && ! $expecting_operator ) { 402 } elseif ( $ex && ! $expecting_operator ) { // @phpstan-ignore booleanNot.alwaysTrue 403 403 $expecting_operator = true; 404 404 $value = $match[1]; -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Calculation/Calculation.php
r3463039 r3473263 3 3 namespace TablePress\PhpOffice\PhpSpreadsheet\Calculation; 4 4 5 use TablePress\Composer\Pcre\Preg; // many pregs in this program use u modifier, which has side-effects which make it unsuitable for this 5 6 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Engine\BranchPruner; 6 7 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Engine\CyclicReferenceStack; … … 37 38 // Function (allow for the old @ symbol that could be used to prefix a function, but we'll ignore it) 38 39 const CALCULATION_REGEXP_FUNCTION = '@?(?:_xlfn\.)?(?:_xlws\.)?((?:__xludf\.)?[\p{L}][\p{L}\p{N}\._]*)[\s]*\('; // TablePress: Add _ to allow the deprecated RAND_INT, RAND_FLOAT, NUMBER_FORMAT, and NUMBER_FORMAT_EU functions. 39 // Cell reference (cell or range of cells, with or without a sheet reference)40 // Cell reference, with or without a sheet reference) 40 41 const CALCULATION_REGEXP_CELLREF = '((([^\s,!&%^\/\*\+<>=:`-]*)|(\'(?:[^\']|\'[^!])+?\')|(\"(?:[^\"]|\"[^!])+?\"))!)?\$?\b([a-z]{1,3})\$?(\d{1,7})(?![\w.])'; 41 42 // Used only to detect spill operator # … … 91 92 private BranchPruner $branchPruner; 92 93 93 pr ivatebool $branchPruningEnabled = true;94 protected bool $branchPruningEnabled = true; 94 95 95 96 /** … … 424 425 if (is_string($value)) { 425 426 // Error values cannot be "wrapped" 426 if ( preg_match('/^' . self::CALCULATION_REGEXP_ERROR . '$/i', $value, $match)) {427 if (Preg::isMatch('/^' . self::CALCULATION_REGEXP_ERROR . '$/i', $value, $match)) { 427 428 // Return Excel errors "as is" 428 429 return $value; … … 507 508 $value = $cell->getValue(); 508 509 if (is_string($value) && $cell->getDataType() === DataType::TYPE_FORMULA) { 509 $value = preg_replace_callback(510 $value = Preg::replaceCallback( 510 511 self::CALCULATION_REGEXP_CELLREF_SPILL, 511 512 fn (array $matches) => 'ANCHORARRAY(' . substr($matches[0], 0, -1) . ')', … … 570 571 public function parseFormula(string $formula) 571 572 { 572 $formula = preg_replace_callback(573 $formula = Preg::replaceCallback( 573 574 self::CALCULATION_REGEXP_CELLREF_SPILL, 574 575 fn (array $matches) => 'ANCHORARRAY(' . substr($matches[0], 0, -1) . ')', 575 576 $formula 576 ) ?? $formula;577 ); 577 578 // Basic validation that this is indeed a formula 578 579 // We return an empty array if not … … 678 679 } 679 680 681 // https://www.reddit.com/r/excel/comments/chr41y/cmd_formula_stopped_working_since_last_update/ 680 682 if (preg_match('/^=\s*cmd\s*\|/miu', $formula) !== 0) { 681 return self::wrapResult($formula);683 return ExcelError::REF(); // returns #BLOCKED in newer versions 682 684 } 683 685 … … 1074 1076 ]; 1075 1077 1078 /** @param string[] $matches */ 1079 private static function unionForComma(array $matches): string 1080 { 1081 return $matches[1] . str_replace(',', '∪', $matches[2]); 1082 } 1083 1084 private const CELL_OR_CELLRANGE_OR_DEFINED_NAME 1085 = '(?:' 1086 . self::CALCULATION_REGEXP_CELLREF // cell address 1087 . '(?::' . self::CALCULATION_REGEXP_CELLREF . ')?' // optional range address, non-capturing 1088 . '|' . self::CALCULATION_REGEXP_DEFINEDNAME 1089 . ')' 1090 ; 1091 1092 public const UNIONABLE_COMMAS = '/((?:[,(]|^)\s*)' // comma or open paren or start of string, followed by optional whitespace 1093 . '([(]' // open paren 1094 . self::CELL_OR_CELLRANGE_OR_DEFINED_NAME // cell address 1095 . '(?:\s*,\s*' // optioonal whitespace, comma, optional whitespace, non-capturing 1096 . self::CELL_OR_CELLRANGE_OR_DEFINED_NAME // cell address 1097 . ')+' // one or more occurrences 1098 . '\s*[)])/i'; // optional whitespace, end paren 1099 1076 1100 /** 1077 1101 * @return array<int, mixed>|false … … 1081 1105 if (($formula = $this->convertMatrixReferences(trim($formula))) === false) { 1082 1106 return false; 1107 } 1108 1109 $oldFormula = $formula; 1110 $formula = Preg::replaceCallback(self::UNIONABLE_COMMAS, \Closure::fromCallable([self::class, 'unionForComma']), $formula); // @phpstan-ignore-line 1111 if ($oldFormula !== $formula) { 1112 $this->debugLog->writeDebugLog('Reformulated as %s', $formula); 1083 1113 } 1084 1114 $phpSpreadsheetFunctions = &self::getFunctionsAddress(); … … 1201 1231 } 1202 1232 } elseif (is_string($expectedArgumentCount) && $expectedArgumentCount !== '*') { 1203 if ( 1 !== preg_match('/(\d*)([-+,])(\d*)/', $expectedArgumentCount, $argMatch)) {1233 if (!Preg::isMatch('/(\d*)([-+,])(\d*)/', $expectedArgumentCount, $argMatch)) { 1204 1234 $argMatch = ['', '', '', '']; 1205 1235 } … … 1258 1288 // MS Excel allows this if the content is cell references; but doesn't allow actual values, 1259 1289 // but at this point, we can't differentiate (so allow both) 1260 return $this->raiseFormulaError('Formula Error: Unexpected ,'); 1261 /* The following code may be a better choice, but, with 1262 the other changes for this PR, I can no longer come up 1263 with a test case that gets here 1290 //return $this->raiseFormulaError('Formula Error: Unexpected ,'); 1291 1264 1292 $stack->push('Binary Operator', '∪'); 1265 1293 … … 1267 1295 $expectingOperator = false; 1268 1296 1269 continue; */1297 continue; 1270 1298 } 1271 1299 … … 1293 1321 1294 1322 if (preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/miu', $val, $matches)) { 1295 $val = (string) preg_replace('/\s/u', '', $val); 1323 // $val is known to be valid unicode from statement above, so Preg::replace is okay even with u modifier 1324 $val = Preg::replace('/\s/u', '', $val); 1296 1325 if (isset($phpSpreadsheetFunctions[strtoupper($matches[1])]) || isset(self::$controlFunctions[strtoupper($matches[1])])) { // it's a function 1297 1326 $valToUpper = strtoupper($val); … … 2011 2040 $this->executeNumericBinaryOperation($multiplier, $arg, '*', $stack); 2012 2041 } 2013 } elseif ( preg_match('/^' . self::CALCULATION_REGEXP_CELLREF . '$/i', StringHelper::convertToString($token ?? ''), $matches)) {2042 } elseif (Preg::isMatch('/^' . self::CALCULATION_REGEXP_CELLREF . '$/i', StringHelper::convertToString($token ?? ''), $matches)) { 2014 2043 $cellRef = null; 2015 2044 2016 2045 /* Phpstan says matches[8/9/10] is never set, 2017 2046 and code coverage report seems to confirm. 2018 Appease PhpStan for now; 2019 probably delete this block later. 2047 regex101.com confirms - only 7 capturing groups. 2048 My theory is that this code expected regexp to 2049 match cell *or* cellRange, but it does not 2050 match the latter. Retain the code for now in case 2051 we do want to add the range match later. 2052 Probably delete this block later. 2053 Until delete happens, turn code coverage off. 2020 2054 */ 2021 2055 if (isset($matches[self::$matchIndex8])) { 2056 // @codeCoverageIgnoreStart 2022 2057 if ($cell === null) { 2023 2058 // We can't access the range, so return a REF error … … 2025 2060 } else { 2026 2061 $cellRef = $matches[6] . $matches[7] . ':' . $matches[self::$matchIndex9] . $matches[self::$matchIndex10]; 2062 $matches[2] = (string) $matches[2]; 2027 2063 if ($matches[2] > '') { 2028 2064 $matches[2] = trim($matches[2], "\"'"); … … 2049 2085 } 2050 2086 } 2087 // @codeCoverageIgnoreEnd 2051 2088 } else { 2052 2089 if ($cell === null) { … … 2055 2092 } else { 2056 2093 $cellRef = $matches[6] . $matches[7]; 2094 $matches[2] = (string) $matches[2]; 2057 2095 if ($matches[2] > '') { 2058 2096 $matches[2] = trim($matches[2], "\"'"); … … 2096 2134 } 2097 2135 if (is_string($cellValue)) { 2098 $cellValue = preg_replace('/"/', '""', $cellValue);2136 $cellValue = Preg::replace('/"/', '""', $cellValue); 2099 2137 } 2100 2138 $this->debugLog->writeDebugLog('Scalar Result for cell %s is %s', $cellRef, $this->showTypeDetails($cellValue)); … … 2866 2904 $definedNameType = $namedRange->isFormula() ? 'Formula' : 'Range'; 2867 2905 if ($definedNameType === 'Range') { 2868 if (preg_match('/^(.*!)?(.*)$/', $definedNameValue, $matches) === 1) { 2869 $matches2 = trim($matches[2]); 2870 $matches2 = preg_replace('/ +/', ' ∩ ', $matches2) ?? $matches2; 2871 $matches2 = preg_replace('/,/', ' ∪ ', $matches2) ?? $matches2; 2906 if (Preg::isMatch('/^(.*!)?(.*)$/', $definedNameValue, $matches)) { 2907 $matches2 = Preg::replace( 2908 ['/ +/', '/,/'], 2909 [' ∩ ', ' ∪ '], 2910 trim($matches[2]) 2911 ); 2872 2912 $definedNameValue = $matches[1] . $matches2; 2873 2913 } -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Calculation/FormulaParser.php
r3420898 r3473263 22 22 * software or the use or other dealings in the software. 23 23 * 24 * The following links are no longer valid. 24 25 * https://ewbi.blogs.com/develops/2007/03/excel_formula_p.html 25 26 * https://ewbi.blogs.com/develops/2004/12/excel_formula_p.html 27 * 28 * @deprecated 5.5.0 No replacement. 26 29 */ 27 30 class FormulaParser -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Calculation/FormulaToken.php
r3218835 r3473263 22 22 * software or the use or other dealings in the software. 23 23 * 24 * The following links are no longer valid. 24 25 * https://ewbi.blogs.com/develops/2007/03/excel_formula_p.html 25 26 * https://ewbi.blogs.com/develops/2004/12/excel_formula_p.html 27 * 28 * @deprecated 5.5.0 No replacement. 26 29 */ 27 30 class FormulaToken -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Calculation/FunctionArray.php
r3463039 r3473263 406 406 'functionCall' => [TextData\Concatenate::class, 'actualCONCATENATE'], 407 407 'argumentCount' => '1+', 408 'passCellReference' => true, 408 409 ], 409 410 'CONFIDENCE' => [ -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Calculation/Functions.php
r3385566 r3473263 4 4 5 5 use TablePress\PhpOffice\PhpSpreadsheet\Cell\Cell; 6 use TablePress\PhpOffice\PhpSpreadsheet\Cell\Coordinate; 6 7 use TablePress\PhpOffice\PhpSpreadsheet\Shared\Date; 7 8 use TablePress\PhpOffice\PhpSpreadsheet\Shared\StringHelper; … … 382 383 return $coordinate; 383 384 } 385 386 /** @param mixed[] $array */ 387 public static function convertArrayToCellRange(array $array): string 388 { 389 $retVal = ''; 390 $lastRow = $lastColumn = $firstRow = $firstColumn = 0; 391 foreach ($array as $rowkey => $row) { 392 if (!is_array($row) || !is_int($rowkey) || $rowkey < 1) { 393 $firstRow = 0; 394 395 break; 396 } 397 if ($firstRow > $rowkey || $firstRow === 0) { 398 $firstRow = $rowkey; 399 } 400 if ($lastRow < $rowkey) { 401 $lastRow = $rowkey; 402 } 403 foreach ($row as $colkey => $cellValue) { 404 if (!preg_match('/^[A-Z]{1,3}$/', $colkey)) { 405 $firstRow = 0; 406 407 break 2; 408 } 409 $column = Coordinate::columnIndexFromString($colkey); 410 if ($firstColumn > $column || $firstColumn === 0) { 411 $firstColumn = $column; 412 } 413 if ($lastColumn < $column) { 414 $lastColumn = $column; 415 } 416 } 417 } 418 if ($firstRow > 0 && $firstColumn > 0 && ($firstRow !== $lastRow || $firstColumn !== $lastColumn)) { 419 $retVal = Coordinate::stringFromColumnIndex($firstColumn) 420 . $firstRow 421 . ':' 422 . Coordinate::stringFromColumnIndex($lastColumn) 423 . $lastRow; 424 } 425 426 return $retVal; 427 } 384 428 } -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Calculation/MathTrig/Sum.php
r3463039 r3473263 112 112 } 113 113 114 /** @var array<float|int> $wrkArray */ 114 115 return array_sum($wrkArray); 115 116 } -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Calculation/TextData/Concatenate.php
r3350024 r3473263 8 8 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue; 9 9 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError; 10 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Internal\ExcelArrayPseudoFunctions; 11 use TablePress\PhpOffice\PhpSpreadsheet\Cell\Cell; 10 12 use TablePress\PhpOffice\PhpSpreadsheet\Cell\DataType; 11 13 use TablePress\PhpOffice\PhpSpreadsheet\Shared\StringHelper; … … 18 20 * This implements the CONCAT function, *not* CONCATENATE. 19 21 * 20 * @param mixed [] $args22 * @param mixed $args data to be concatenated 21 23 */ 22 24 public static function CONCATENATE(...$args): string … … 48 50 * This implements the CONCATENATE function. 49 51 * 50 * @param mixed []$args data to be concatenated52 * @param mixed $args data to be concatenated 51 53 * 52 54 * @return array<string>|string … … 54 56 public static function actualCONCATENATE(...$args) 55 57 { 58 $useSingle = false; 59 $cell = null; 60 $count = count($args); 61 if ($args[$count - 1] instanceof Cell) { 62 /** @var Cell */ 63 $cell = array_pop($args); 64 $type = (($nullsafeVariable1 = $cell->getWorksheet()->getParent()) ? $nullsafeVariable1->getCalculationEngine()->getInstanceArrayReturnType() : null) ?? Calculation::getArrayReturnType(); 65 $useSingle = $type === Calculation::RETURN_ARRAY_AS_VALUE; 66 } 56 67 if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_GNUMERIC) { 57 68 return self::CONCATENATE(...$args); … … 59 70 $result = ''; 60 71 foreach ($args as $operand2) { 72 if ($useSingle && $cell instanceof Cell && is_array($operand2)) { 73 $temp = Functions::convertArrayToCellRange($operand2); 74 if ($temp !== '') { 75 $operand2 = ExcelArrayPseudoFunctions::single($temp, $cell); 76 } 77 } 78 /** @var null|array<mixed>|bool|float|int|string $operand2 */ 61 79 $result = self::concatenate2Args($result, $operand2); 62 80 if (ErrorValue::isError($result, true) === true) { -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Cell/Cell.php
r3463039 r3473263 227 227 } 228 228 // Cells?->Worksheet?->Spreadsheet 229 $binder ??= (($nullsafeVariable3 = ($nullsafeVariable1 0 = ($nullsafeVariable14 = $this->parent) ? $nullsafeVariable14->getParent() : null) ? $nullsafeVariable10->getParent() : null) ? $nullsafeVariable3->getValueBinder() : null) ?? self::getValueBinder();229 $binder ??= (($nullsafeVariable3 = ($nullsafeVariable13 = ($nullsafeVariable17 = $this->parent) ? $nullsafeVariable17->getParent() : null) ? $nullsafeVariable13->getParent() : null) ? $nullsafeVariable3->getValueBinder() : null) ?? self::getValueBinder(); 230 230 if (!$binder->bindValue($this, $value)) { 231 231 throw new SpreadsheetException('Value could not be bound to cell.'); … … 291 291 $value2 = StringHelper::convertToString($value, true); 292 292 // Cells?->Worksheet?->Spreadsheet 293 $binder = ($nullsafeVariable4 = ($nullsafeVariable 11 = ($nullsafeVariable15 = $this->parent) ? $nullsafeVariable15->getParent() : null) ? $nullsafeVariable11->getParent() : null) ? $nullsafeVariable4->getValueBinder() : null;293 $binder = ($nullsafeVariable4 = ($nullsafeVariable5 = ($nullsafeVariable14 = $this->parent) ? $nullsafeVariable14->getParent() : null) ? $nullsafeVariable5->getParent() : null) ? $nullsafeVariable4->getValueBinder() : null; 294 294 $preserveCr = false; 295 295 if ($binder !== null && method_exists($binder, 'getPreserveCr')) { … … 341 341 $this->updateInCollection(); 342 342 $cellCoordinate = $this->getCoordinate(); 343 self::updateIfCellIsTableHeader(($nullsafeVariable 5 = $this->getParent()) ? $nullsafeVariable5->getParent() : null, $this, $oldValue, $value);343 self::updateIfCellIsTableHeader(($nullsafeVariable6 = $this->getParent()) ? $nullsafeVariable6->getParent() : null, $this, $oldValue, $value); 344 344 $worksheet = $this->getWorksheet(); 345 345 $spreadsheet = $worksheet->getParent(); … … 358 358 } 359 359 360 return (($nullsafeVariable 6 = $this->getParent()) ? $nullsafeVariable6->get($cellCoordinate) : null) ?? $this;360 return (($nullsafeVariable7 = $this->getParent()) ? $nullsafeVariable7->get($cellCoordinate) : null) ?? $this; 361 361 } 362 362 public const CALCULATE_DATE_TIME_ASIS = 0; … … 437 437 try { 438 438 $currentCalendar = SharedDate::getExcelCalendar(); 439 SharedDate::setExcelCalendar(($nullsafeVariable 7 = $this->getWorksheet()->getParent()) ? $nullsafeVariable7->getExcelCalendar() : null);439 SharedDate::setExcelCalendar(($nullsafeVariable8 = $this->getWorksheet()->getParent()) ? $nullsafeVariable8->getExcelCalendar() : null); 440 440 $thisworksheet = $this->getWorksheet(); 441 441 $index = $thisworksheet->getParentOrThrow()->getActiveSheetIndex(); … … 1002 1002 public function isLocked(): bool 1003 1003 { 1004 $protected = ($nullsafeVariable 8 = ($nullsafeVariable12 = ($nullsafeVariable16 = $this->parent) ? $nullsafeVariable16->getParent() : null) ? $nullsafeVariable12->getProtection() : null) ? $nullsafeVariable8->getSheet() : null;1004 $protected = ($nullsafeVariable9 = ($nullsafeVariable10 = ($nullsafeVariable15 = $this->parent) ? $nullsafeVariable15->getParent() : null) ? $nullsafeVariable10->getProtection() : null) ? $nullsafeVariable9->getSheet() : null; 1005 1005 if ($protected !== true) { 1006 1006 return false; … … 1015 1015 return false; 1016 1016 } 1017 $protected = ($nullsafeVariable 9 = ($nullsafeVariable13 = ($nullsafeVariable17 = $this->parent) ? $nullsafeVariable17->getParent() : null) ? $nullsafeVariable13->getProtection() : null) ? $nullsafeVariable9->getSheet() : null;1017 $protected = ($nullsafeVariable11 = ($nullsafeVariable12 = ($nullsafeVariable16 = $this->parent) ? $nullsafeVariable16->getParent() : null) ? $nullsafeVariable12->getProtection() : null) ? $nullsafeVariable11->getSheet() : null; 1018 1018 if ($protected !== true) { 1019 1019 return false; -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Cell/DefaultValueBinder.php
r3463039 r3473263 5 5 use TablePress\Composer\Pcre\Preg; 6 6 use DateTimeInterface; 7 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Calculation ;7 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\CalculationParserOnly; 8 8 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Exception as CalculationException; 9 9 use TablePress\PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException; … … 88 88 } 89 89 if (strlen($value) > 1 && $value[0] === '=') { 90 $calculation = new Calculation(); 91 $calculation->disableBranchPruning(); 90 $calculation = CalculationParserOnly::getParserInstance(); 92 91 93 92 try { -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Helper/Downloader.php
r3283748 r3473263 3 3 namespace TablePress\PhpOffice\PhpSpreadsheet\Helper; 4 4 5 use DateTimeImmutable; 6 use DateTimeZone; 5 7 use TablePress\PhpOffice\PhpSpreadsheet\Exception; 6 8 … … 91 93 // If you're serving to IE over SSL, then the following may be needed 92 94 header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past 93 header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified 95 $dt = new DateTimeImmutable('now', new DateTimeZone('UTC')); 96 header('Last-Modified: ' . $dt->format('D, d M Y H:i:s') . ' GMT'); // always modified 94 97 header('Cache-Control: cache, must-revalidate'); // HTTP/1.1 95 98 header('Pragma: public'); // HTTP/1.0 -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Helper/Sample.php
r3463039 r3473263 132 132 $writer->save($path); 133 133 $this->logWrite($writer, $path, $callStartTime); 134 if ($this->isCli() === false) { 135 // @codeCoverageIgnoreStart 136 echo '<a href="https://plugins.trac.wordpress.org/download.php?type=" . pathinfo($path, PATHINFO_EXTENSION) . '&name=' . basename($path) . '">Download ' . basename($path) . '</a><br />'; 137 // @codeCoverageIgnoreEnd 138 } 134 $this->addDownloadLink($path); 139 135 } 140 136 141 137 $this->logEndingNotes(); 138 } 139 140 public function addDownloadLink(string $path): void 141 { 142 if ($this->isCli() === false) { 143 // @codeCoverageIgnoreStart 144 echo '<a href="https://plugins.trac.wordpress.org/download.php?type=" . pathinfo($path, PATHINFO_EXTENSION) . '&name=' . basename($path) . '">Download ' . basename($path) . '</a><br />'; 145 // @codeCoverageIgnoreEnd 146 } 142 147 } 143 148 -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Reader/BaseReader.php
r3463039 r3473263 3 3 namespace TablePress\PhpOffice\PhpSpreadsheet\Reader; 4 4 5 use Closure; 5 6 use TablePress\PhpOffice\PhpSpreadsheet\Cell\IValueBinder; 6 7 use TablePress\PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException; … … 81 82 protected ?IValueBinder $valueBinder = null; 82 83 84 /** @var null|Closure(string):bool function to return whether image path is okay */ 85 protected ?Closure $isWhitelisted = null; 86 83 87 public function __construct() 84 88 { … … 184 188 185 189 /** 186 * Allow external images. Use with caution. 187 * Improper specification of these within a spreadsheet 190 * USE WITH CAUTION (and in conjunction with setIsWhiteListed)! 191 * Allow external images; 192 * these can be specified within a spreadsheet 193 * in a way that can subject the caller to security exploits. 194 */ 195 public function setAllowExternalImages(bool $allowExternalImages): self 196 { 197 $this->allowExternalImages = $allowExternalImages; 198 199 return $this; 200 } 201 202 public function getAllowExternalImages(): bool 203 { 204 return $this->allowExternalImages; 205 } 206 207 /** 208 * USE WITH CAUTION! 209 * Supply a callback to determine whether a path should be whitelisted, 210 * used in conjunction with setAllowExternalImages; 211 * supplying a method which might return true 188 212 * can subject the caller to security exploits. 189 */ 190 public function setAllowExternalImages(bool $allowExternalImages): self 191 { 192 $this->allowExternalImages = $allowExternalImages; 193 194 return $this; 195 } 196 197 public function getAllowExternalImages(): bool 198 { 199 return $this->allowExternalImages; 213 * 214 * @param Closure(string):bool $isWhitelisted 215 */ 216 public function setIsWhitelisted(Closure $isWhitelisted): self 217 { 218 $this->isWhitelisted = $isWhitelisted; 219 220 return $this; 200 221 } 201 222 -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Reader/Html.php
r3463039 r3473263 291 291 * @param string[] $attributeArray 292 292 * 293 * @param-out string $cellContent In one case, it can be bool293 * @param-out string $cellContentx 294 294 * @param int|string $row 295 * @param mixed $cellContent 295 * @param mixed $cellContentx 296 296 */ 297 protected function flushCell(Worksheet $sheet, string $column, $row, &$cellContent, array $attributeArray): void 298 { 297 protected function flushCell(Worksheet $sheet, string $column, $row, &$cellContentx, array $attributeArray): void 298 { 299 $cellContent = $cellContentx; 299 300 if (is_string($cellContent)) { 300 301 // Simple String content … … 305 306 306 307 // Set cell value explicitly if there is data-type attribute 308 if (isset($attributeArray['data-checkbox'])) { 309 $sheet->getStyle($column . $row) 310 ->setCheckBox(true); 311 } 307 312 if (isset($attributeArray['data-type'])) { 308 313 $datatype = $attributeArray['data-type']; … … 317 322 if ($datatype === DataType::TYPE_BOOL) { 318 323 // This is the case where we can set cellContent to bool rather than string 319 $cellContent = self::convertBoolean($cellContent); //* @phpstan-ignore-line 320 if (!is_bool($cellContent)) { 321 $attributeArray['data-type'] = DataType::TYPE_STRING; 324 if ($cellContent === '☑') { 325 $cellContent = true; 326 $sheet->getStyle($column . $row) 327 ->setCheckBox(true); 328 } elseif ($cellContent === '☐') { 329 $cellContent = false; 330 $sheet->getStyle($column . $row) 331 ->setCheckBox(true); 332 } else { 333 $cellContent = self::convertBoolean($cellContent); 334 if (!is_bool($cellContent)) { 335 $attributeArray['data-type'] = DataType::TYPE_STRING; 336 } 322 337 } 323 338 } … … 327 342 328 343 try { 329 $sheet->setCellValueExplicit($column . $row, $cellContent, $attributeArray['data-type']); 344 if (isset($attributeArray['data-formula'])) { 345 $sheet->setCellValueExplicit($column . $row, $attributeArray['data-formula'], DataType::TYPE_FORMULA); 346 $sheet->getCell($column . $row) 347 ->setCalculatedValue( 348 $cellContent 349 ); 350 } else { 351 $sheet->setCellValueExplicit($column . $row, $cellContent, $attributeArray['data-type']); 352 } 330 353 } catch (SpreadsheetException $exception) { 331 354 $sheet->setCellValue($column . $row, $cellContent); … … 349 372 $this->dataArray[$row][$column] = 'RICH TEXT: ' . StringHelper::convertToString($cellContent); // @codeCoverageIgnore 350 373 } 351 $cellContent = (string)'';374 $cellContentx = ''; 352 375 } 353 376 … … 1218 1241 1219 1242 $drawing = new Drawing(); 1220 $drawing->setPath($src, false, null, $this->allowExternalImages );1243 $drawing->setPath($src, false, null, $this->allowExternalImages, $this->isWhitelisted); 1221 1244 if ($drawing->getPath() === '') { 1222 1245 return; -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Reader/Ods.php
r3463039 r3473263 3 3 namespace TablePress\PhpOffice\PhpSpreadsheet\Reader; 4 4 5 use Closure; 6 use TablePress\Composer\Pcre\Preg; 7 use DateTime; 8 use DateTimeZone; 5 9 use DOMAttr; 6 10 use DOMDocument; … … 8 12 use DOMNode; 9 13 use DOMText; 14 use TablePress\PhpOffice\PhpSpreadsheet\Cell\AddressRange; 10 15 use TablePress\PhpOffice\PhpSpreadsheet\Cell\Coordinate; 11 16 use TablePress\PhpOffice\PhpSpreadsheet\Cell\DataType; … … 22 27 use TablePress\PhpOffice\PhpSpreadsheet\Shared\StringHelper; 23 28 use TablePress\PhpOffice\PhpSpreadsheet\Spreadsheet; 29 use TablePress\PhpOffice\PhpSpreadsheet\Style\Alignment; 30 use TablePress\PhpOffice\PhpSpreadsheet\Style\Border; 31 use TablePress\PhpOffice\PhpSpreadsheet\Style\Borders; 32 use TablePress\PhpOffice\PhpSpreadsheet\Style\Fill; 24 33 use TablePress\PhpOffice\PhpSpreadsheet\Style\NumberFormat; 34 use TablePress\PhpOffice\PhpSpreadsheet\Style\Protection; 25 35 use TablePress\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; 26 36 use Throwable; … … 142 152 * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns). 143 153 * 144 * @return array<int, array{worksheetName: string, lastColumnLetter: string, lastColumnIndex: int, totalRows: int, totalColumns: int, sheetState: string}> 154 * @return array<int, array{ 155 * worksheetName: string, 156 * lastColumnLetter: string, 157 * lastColumnIndex: int, 158 * totalRows: int, 159 * totalColumns: int, 160 * sheetState: string 161 * }> 145 162 */ 146 163 public function listWorksheetInfo(string $filename): array … … 243 260 } 244 261 262 /** @var array<string, 263 * array{ 264 * font?:array{ 265 * autoColor?: true, 266 * bold?: true, 267 * color?: array{rgb: string}, 268 * italic?: true, 269 * name?: non-empty-string, 270 * size?: float|int, 271 * strikethrough?: true, 272 * underline?: 'double'|'single', 273 * }, 274 * fill?:array{ 275 * fillType?: string, 276 * startColor?: array{rgb: string}, 277 * }, 278 * alignment?:array{ 279 * horizontal?: string, 280 * readOrder?: int, 281 * shrinkToFit?: bool, 282 * textRotation?: int, 283 * vertical?: string, 284 * wrapText?: bool, 285 * }, 286 * protection?:array{ 287 * locked?: string, 288 * hidden?: string, 289 * }, 290 * borders?:array{ 291 * bottom?: array{borderStyle:string, color:array{rgb: string}}, 292 * left?: array{borderStyle:string, color:array{rgb: string}}, 293 * right?: array{borderStyle:string, color:array{rgb: string}}, 294 * top?: array{borderStyle:string, color:array{rgb: string}}, 295 * diagonal?: array{borderStyle:string, color:array{rgb: string}}, 296 * diagonalDirection?: int, 297 * }, 298 * }> 299 */ 300 private array $allStyles; 301 302 private int $highestDataIndex; 303 245 304 /** 246 305 * Loads PhpSpreadsheet from file into PhpSpreadsheet instance. … … 270 329 // Styles 271 330 331 $this->allStyles = []; 272 332 $dom = new DOMDocument('1.01', 'UTF-8'); 273 333 $dom->loadXML( … … 275 335 ->scan($zip->getFromName('styles.xml')) 276 336 ); 337 $officeNs = (string) $dom->lookupNamespaceUri('office'); 338 $styleNs = (string) $dom->lookupNamespaceUri('style'); 339 $fontNs = (string) $dom->lookupNamespaceUri('fo'); 340 341 $automaticStyle0 = $this->readDataOnly ? null : $dom->getElementsByTagNameNS($officeNs, 'styles')->item(0); 342 $automaticStyles = ($automaticStyle0 === null) ? [] : $automaticStyle0->getElementsByTagNameNS($styleNs, 'default-style'); 343 foreach ($automaticStyles as $automaticStyle) { 344 $styleFamily = $automaticStyle->getAttributeNS($styleNs, 'family'); 345 if ($styleFamily === 'table-cell') { 346 $fonts = []; 347 foreach ($automaticStyle->getElementsByTagNameNS($styleNs, 'text-properties') as $textProperty) { 348 $fonts = $this->getFontStyles($textProperty, $styleNs, $fontNs); 349 } 350 if (!empty($fonts)) { 351 $spreadsheet->getDefaultStyle() 352 ->getFont() 353 ->applyFromArray($fonts); 354 } 355 } 356 } 357 $automaticStyles = ($automaticStyle0 === null) ? [] : $automaticStyle0->getElementsByTagNameNS($styleNs, 'style'); 358 foreach ($automaticStyles as $automaticStyle) { 359 $styleName = $automaticStyle->getAttributeNS($styleNs, 'name'); 360 $styleFamily = $automaticStyle->getAttributeNS($styleNs, 'family'); 361 if ($styleFamily === 'table-cell') { 362 $fills = $fonts = []; 363 foreach ($automaticStyle->getElementsByTagNameNS($styleNs, 'text-properties') as $textProperty) { 364 $fonts = $this->getFontStyles($textProperty, $styleNs, $fontNs); 365 } 366 foreach ($automaticStyle->getElementsByTagNameNS($styleNs, 'table-cell-properties') as $tableCellProperty) { 367 $fills = $this->getFillStyles($tableCellProperty, $fontNs); 368 } 369 if ($styleName !== '') { 370 if (!empty($fonts)) { 371 $this->allStyles[$styleName]['font'] = $fonts; 372 if ($styleName === 'Default') { 373 $spreadsheet->getDefaultStyle() 374 ->getFont() 375 ->applyFromArray($fonts); 376 } 377 } 378 if (!empty($fills)) { 379 $this->allStyles[$styleName]['fill'] = $fills; 380 if ($styleName === 'Default') { 381 $spreadsheet->getDefaultStyle() 382 ->getFill() 383 ->applyFromArray($fills); 384 } 385 } 386 } 387 } 388 } 277 389 278 390 $pageSettings = new PageSettings($dom); … … 286 398 ); 287 399 288 $officeNs = (string) $dom->lookupNamespaceUri('office');289 400 $tableNs = (string) $dom->lookupNamespaceUri('table'); 290 401 $textNs = (string) $dom->lookupNamespaceUri('text'); 291 402 $xlinkNs = (string) $dom->lookupNamespaceUri('xlink'); 292 $styleNs = (string) $dom->lookupNamespaceUri('style');293 403 294 404 $pageSettings->readStyleCrossReferences($dom); … … 297 407 $definedNameReader = new DefinedNames($spreadsheet, $tableNs); 298 408 $columnWidths = []; 299 $automaticStyle0 = $ dom->getElementsByTagNameNS($officeNs, 'automatic-styles')->item(0);409 $automaticStyle0 = $this->readDataOnly ? null : $dom->getElementsByTagNameNS($officeNs, 'automatic-styles')->item(0); 300 410 $automaticStyles = ($automaticStyle0 === null) ? [] : $automaticStyle0->getElementsByTagNameNS($styleNs, 'style'); 301 411 foreach ($automaticStyles as $automaticStyle) { … … 310 420 } 311 421 } 422 if ($styleFamily === 'table-cell') { 423 $fonts = $fills = $alignment1 = $alignment2 = $protection = $borders = []; 424 foreach ($automaticStyle->getElementsByTagNameNS($styleNs, 'text-properties') as $textProperty) { 425 $fonts = $this->getFontStyles($textProperty, $styleNs, $fontNs); 426 } 427 foreach ($automaticStyle->getElementsByTagNameNS($styleNs, 'table-cell-properties') as $tableCellProperty) { 428 $fills = $this->getFillStyles($tableCellProperty, $fontNs); 429 $borders = $this->getBorderStyles($tableCellProperty, $fontNs, $styleNs); 430 $protection = $this->getProtectionStyles($tableCellProperty, $styleNs); 431 } 432 foreach ($automaticStyle->getElementsByTagNameNS($styleNs, 'table-cell-properties') as $tableCellProperty) { 433 $alignment1 = $this->getAlignment1Styles($tableCellProperty, $styleNs, $fontNs); 434 } 435 foreach ($automaticStyle->getElementsByTagNameNS($styleNs, 'paragraph-properties') as $paragraphProperty) { 436 $alignment2 = $this->getAlignment2Styles($paragraphProperty, $styleNs, $fontNs); 437 } 438 if ($styleName !== '') { 439 if (!empty($fonts)) { 440 $this->allStyles[$styleName]['font'] = $fonts; 441 } 442 if (!empty($fills)) { 443 $this->allStyles[$styleName]['fill'] = $fills; 444 } 445 $alignment = array_merge($alignment1, $alignment2); 446 if (!empty($alignment)) { 447 $this->allStyles[$styleName]['alignment'] = $alignment; 448 } 449 if (!empty($protection)) { 450 $this->allStyles[$styleName]['protection'] = $protection; 451 } 452 if (!empty($borders)) { 453 $this->allStyles[$styleName]['borders'] = $borders; 454 } 455 } 456 } 312 457 } 313 458 … … 346 491 // formula cells... during the load, all formulae should be correct, and we're simply 347 492 // bringing the worksheet name in line with the formula, not the reverse 348 $spreadsheet->getActiveSheet()->setTitle((string) $worksheetName, false, false); 493 $spreadsheet->getActiveSheet() 494 ->setTitle((string) $worksheetName, false, false); 349 495 } 350 496 … … 352 498 $rowID = 1; 353 499 $tableColumnIndex = 1; 500 $this->highestDataIndex = AddressRange::MAX_COLUMN_INT; 354 501 foreach ($worksheetDataSet->childNodes as $childNode) { 355 502 /** @var DOMElement $childNode */ … … 390 537 391 538 break; 392 case 'table-header-columns':393 case 'table-columns':394 $this->processTableHeaderColumns(395 $childNode,396 $tableNs,397 $columnWidths,398 $tableColumnIndex,399 $spreadsheet400 );401 402 break;403 case 'table-column-group':404 $this->processTableColumnGroup(405 $childNode,406 $tableNs,407 $columnWidths,408 $tableColumnIndex,409 $spreadsheet410 );411 412 break;413 case 'table-column':414 $this->processTableColumn(415 $childNode,416 $tableNs,417 $columnWidths,418 $tableColumnIndex,419 $spreadsheet420 );421 422 break;423 539 case 'table-row': 424 540 $this->processTableRow( … … 434 550 435 551 break; 552 case 'table-header-columns': 553 case 'table-columns': 554 $this->processTableColumnHeader( 555 $childNode, 556 $tableNs, 557 $columnWidths, 558 $tableColumnIndex, 559 $spreadsheet, 560 $this->readEmptyCells, 561 true 562 ); 563 564 break; 565 case 'table-column-group': 566 $this->processTableColumnGroup( 567 $childNode, 568 $tableNs, 569 $columnWidths, 570 $tableColumnIndex, 571 $spreadsheet, 572 $this->readEmptyCells, 573 true 574 ); 575 576 break; 577 case 'table-column': 578 $this->processTableColumn( 579 $childNode, 580 $tableNs, 581 $columnWidths, 582 $tableColumnIndex, 583 $spreadsheet, 584 $this->readEmptyCells, 585 true 586 ); 587 588 break; 436 589 } 437 590 } … … 449 602 $spreadsheet->createSheet(); 450 603 } 604 } 605 606 foreach ($spreadsheets as $workbookData) { 607 /** @var DOMElement $workbookData */ 608 $tables = $workbookData->getElementsByTagNameNS($tableNs, 'table'); 609 610 $worksheetID = 0; 611 foreach ($tables as $worksheetDataSet) { 612 /** @var DOMElement $worksheetDataSet */ 613 $worksheetName = $worksheetDataSet->getAttributeNS($tableNs, 'name'); 614 615 // Check loadSheetsOnly 616 if ( 617 $this->loadSheetsOnly !== null 618 && $worksheetName 619 && !in_array($worksheetName, $this->loadSheetsOnly) 620 ) { 621 continue; 622 } 623 624 // Create sheet 625 $spreadsheet->setActiveSheetIndex($worksheetID); 626 $highestDataColumn = $spreadsheet->getActiveSheet()->getHighestDataColumn(); 627 $this->highestDataIndex = Coordinate::columnIndexFromString($highestDataColumn); 628 629 // Go through every child of table element processing column widths 630 $rowID = 1; 631 $tableColumnIndex = 1; 632 foreach ($worksheetDataSet->childNodes as $childNode) { 633 /** @var DOMElement $childNode */ 634 if (empty($columnWidths) || $this->readEmptyCells) { 635 break; 636 } 637 638 // Filter elements which are not under the "table" ns 639 if ($childNode->namespaceURI != $tableNs) { 640 continue; 641 } 642 643 $key = self::extractNodeName($childNode->nodeName); 644 645 switch ($key) { 646 case 'table-header-columns': 647 case 'table-columns': 648 $this->processTableColumnHeader( 649 $childNode, 650 $tableNs, 651 $columnWidths, 652 $tableColumnIndex, 653 $spreadsheet, 654 true, 655 false 656 ); 657 658 break; 659 case 'table-column-group': 660 $this->processTableColumnGroup( 661 $childNode, 662 $tableNs, 663 $columnWidths, 664 $tableColumnIndex, 665 $spreadsheet, 666 true, 667 false 668 ); 669 670 break; 671 case 'table-column': 672 $this->processTableColumn( 673 $childNode, 674 $tableNs, 675 $columnWidths, 676 $tableColumnIndex, 677 $spreadsheet, 678 true, 679 false 680 ); 681 682 break; 683 } 684 } 685 ++$worksheetID; 686 } 451 687 452 688 $autoFilterReader->read($workbookData); 453 689 $definedNameReader->read($workbookData); 454 690 } 691 455 692 $spreadsheet->setActiveSheetIndex(0); 456 693 … … 567 804 $rowRepeats = 1; 568 805 } 806 $worksheet = $spreadsheet->getSheetByName($worksheetName); 569 807 570 808 $columnID = 'A'; … … 574 812 continue; // should just be whitespace 575 813 } 814 if ($cellData->hasAttributeNS($tableNs, 'number-columns-repeated')) { 815 $colRepeats = (int) $cellData->getAttributeNS($tableNs, 'number-columns-repeated'); 816 } else { 817 $colRepeats = 1; 818 } 819 $styleName = $cellData->getAttributeNS($tableNs, 'style-name'); 820 821 // When a cell has number-columns-repeated, check if ANY column in the 822 // repeated range passes the read filter. If not, skip the entire group. 823 // If some columns pass, we need to fall through to the processing block 824 // which will handle per-column filtering. 576 825 if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) { 577 if ($cellData->hasAttributeNS($tableNs, 'number-columns-repeated')) { 578 $colRepeats = (int) $cellData->getAttributeNS($tableNs, 'number-columns-repeated'); 579 } else { 580 $colRepeats = 1; 581 } 582 826 if ($colRepeats <= 1) { 827 StringHelper::stringIncrement($columnID); 828 829 continue; 830 } 831 832 // Check if any column within this repeated group passes the filter 833 $anyColumnPasses = false; 834 $tempCol = $columnID; 583 835 for ($i = 0; $i < $colRepeats; ++$i) { 584 StringHelper::stringIncrement($columnID); 585 } 586 587 continue; 836 if ($i > 0) { 837 StringHelper::stringIncrement($tempCol); 838 } 839 if ($this->getReadFilter()->readCell($tempCol, $rowID, $worksheetName)) { 840 $anyColumnPasses = true; 841 842 break; 843 } 844 } 845 846 if (!$anyColumnPasses) { 847 for ($i = 0; $i < $colRepeats; ++$i) { 848 StringHelper::stringIncrement($columnID); 849 } 850 851 continue; 852 } 853 // Fall through to process the cell, with per-column filter checks 854 } 855 if ($worksheet !== null && ($cellData->hasChildNodes() || ($cellData->nextSibling !== null)) && isset($this->allStyles[$styleName])) { 856 $spannedRange = "$columnID$rowID"; 857 // the following is sufficient for ods, 858 // and does no harm for xlsx/xls. 859 $worksheet->getStyle($spannedRange) 860 ->applyFromArray($this->allStyles[$styleName]); 861 // the rest of this block is needed for xlsx/xls, 862 // and does no harm for ods. 863 if (isset($this->allStyles[$styleName]['borders'])) { 864 $spannedRows = $cellData->getAttributeNS($tableNs, 'number-columns-spanned'); 865 $spannedColumns = $cellData->getAttributeNS($tableNs, 'number-rows-spanned'); 866 $spannedRows = max((int) $spannedRows, 1); 867 $spannedColumns = max((int) $spannedColumns, 1); 868 if ($spannedRows > 1 || $spannedColumns > 1) { 869 $endRow = $rowID + $spannedRows - 1; 870 $endCol = $columnID; 871 while ($spannedColumns > 1) { 872 StringHelper::stringIncrement($endCol); 873 --$spannedColumns; 874 } 875 $spannedRange .= ":$endCol$endRow"; 876 $worksheet->getStyle($spannedRange) 877 ->getBorders() 878 ->applyFromArray( 879 $this->allStyles[$styleName]['borders'] 880 ); 881 } 882 } 588 883 } 589 884 … … 658 953 659 954 if (count($paragraphs) > 0) { 955 $dataValue = null; 660 956 // Consolidate if there are multiple p records (maybe with spans as well) 661 957 $dataArray = []; … … 672 968 673 969 $type = $cellData->getAttributeNS($officeNs, 'value-type'); 970 $symbol = ''; 971 $leftHandCurrency = Preg::isMatch('/\$|£|¥/', $allCellDataText, $matches); 972 if ($leftHandCurrency) { 973 $type = str_replace('float', 'currency', $type); 974 $symbol = (string) $matches[0]; 975 } 976 $customFormatting = ''; 977 if ($this->formatCallback !== null) { 978 $temp = ($this->formatCallback)($type, $allCellDataText); 979 if ($temp !== '') { 980 $customFormatting = $temp; 981 } 982 } 674 983 675 984 switch ($type) { … … 692 1001 break; 693 1002 case 'percentage': 1003 if (!str_contains($allCellDataText, '.')) { 1004 $formatting = NumberFormat::FORMAT_PERCENTAGE; 1005 } elseif (substr($allCellDataText, -3, 1) === '.') { 1006 $formatting = NumberFormat::FORMAT_PERCENTAGE_0; 1007 } else { 1008 $formatting = NumberFormat::FORMAT_PERCENTAGE_00; 1009 } 694 1010 $type = DataType::TYPE_NUMERIC; 695 1011 $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value'); 696 697 // percentage should always be float698 //if (floor($dataValue) == $dataValue) {699 // $dataValue = (int) $dataValue;700 //}701 $formatting = NumberFormat::FORMAT_PERCENTAGE_00;702 1012 703 1013 break; … … 706 1016 $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value'); 707 1017 708 if (floor($dataValue) == $dataValue) { 709 $dataValue = (int) $dataValue; 710 } 711 $formatting = NumberFormat::FORMAT_CURRENCY_USD_INTEGER; 1018 $currency = $cellData->getAttributeNS($officeNs, 'currency'); 1019 if ($leftHandCurrency) { 1020 $typeValue = 'currency'; 1021 $formatting = str_contains($allCellDataText, '.') ? NumberFormat::FORMAT_CURRENCY_USD : NumberFormat::FORMAT_CURRENCY_USD_INTEGER; 1022 if ($symbol !== '$') { 1023 $formatting = str_replace('$', $symbol, $formatting); 1024 } 1025 } elseif (str_contains($allCellDataText, '€')) { 1026 $typeValue = 'currency'; 1027 $formatting = str_contains($allCellDataText, '.') ? NumberFormat::FORMAT_CURRENCY_EUR : NumberFormat::FORMAT_CURRENCY_EUR_INTEGER; 1028 } 712 1029 713 1030 break; … … 716 1033 $dataValue = (float) $cellData->getAttributeNS($officeNs, 'value'); 717 1034 1035 if ($dataValue !== floor($dataValue)) { 1036 // do nothing 1037 } elseif (substr($allCellDataText, -2, 1) === '.') { 1038 $formatting = NumberFormat::FORMAT_NUMBER_0; 1039 } elseif (substr($allCellDataText, -3, 1) === '.') { 1040 $formatting = NumberFormat::FORMAT_NUMBER_00; 1041 } 718 1042 if (floor($dataValue) == $dataValue) { 719 1043 if ($dataValue == (int) $dataValue) { … … 728 1052 $dataValue = Date::convertIsoDate($value); 729 1053 730 if ($dataValue != floor($dataValue)) { 1054 if (Preg::isMatch('/^\d\d\d\d-\d\d-\d\d$/', $allCellDataText)) { 1055 $formatting = 'yyyy-mm-dd'; 1056 } elseif (Preg::isMatch('/^\d\d?-[a-zA-Z]+-\d\d\d\d$/', $allCellDataText)) { 1057 $formatting = 'd-mmm-yyyy'; 1058 } elseif ($dataValue != floor($dataValue)) { 731 1059 $formatting = NumberFormat::FORMAT_DATE_XLSX15 732 1060 . ' ' … … 741 1069 742 1070 $timeValue = $cellData->getAttributeNS($officeNs, 'time-value'); 743 744 $dataValue = Date::PHPToExcel( 745 strtotime( 746 '01-01-1970 ' . implode(':', sscanf($timeValue, 'PT%dH%dM%dS') ?? []) 747 ) 748 ); 749 $formatting = NumberFormat::FORMAT_DATE_TIME4; 1071 $minus = ''; 1072 if (str_starts_with($timeValue, '-')) { 1073 $minus = '-'; 1074 $timeValue = (string) substr($timeValue, 1); 1075 } 1076 $timeArray = sscanf($timeValue, 'PT%dH%dM%dS'); 1077 if (is_array($timeArray)) { 1078 /** @var array{int, int, int} $timeArray */ 1079 $days = intdiv($timeArray[0], 24); 1080 $hours = $timeArray[0] % 24; 1081 $dt = new DateTime("1899-12-30 $hours:{$timeArray[1]}:{$timeArray[2]}", new DateTimeZone('UTC')); 1082 $dt->modify("+$days days"); 1083 $dataValue = Date::PHPToExcel($dt); 1084 if ($minus === '-') { 1085 $dataValue *= -1; 1086 $formatting = '[hh]:mm:ss'; 1087 } else { 1088 $formatting = NumberFormat::FORMAT_DATE_TIME4; 1089 } 1090 } 750 1091 751 1092 break; 752 1093 default: 753 1094 $dataValue = null; 1095 } 1096 if ($customFormatting !== '') { 1097 $formatting = $customFormatting; 754 1098 } 755 1099 } else { … … 764 1108 } 765 1109 766 if ($cellData->hasAttributeNS($tableNs, 'number-columns-repeated')) { 767 $colRepeats = (int) $cellData->getAttributeNS($tableNs, 'number-columns-repeated'); 768 } else { 769 $colRepeats = 1; 770 } 771 772 if ($type !== null) { // @phpstan-ignore-line 773 for ($i = 0; $i < $colRepeats; ++$i) { 774 if ($i > 0) { 775 StringHelper::stringIncrement($columnID); 776 } 777 778 if ($type !== DataType::TYPE_NULL) { 779 for ($rowAdjust = 0; $rowAdjust < $rowRepeats; ++$rowAdjust) { 780 $rID = $rowID + $rowAdjust; 781 782 $cell = $spreadsheet->getActiveSheet() 783 ->getCell($columnID . $rID); 784 785 // Set value 786 if ($hasCalculatedValue) { 787 $cell->setValueExplicit($cellDataFormula, $type); 788 if ($cellDataType === 'array') { 789 $cell->setFormulaAttributes(['t' => 'array', 'ref' => $cellDataRef]); 790 } 791 } elseif ($type !== '' || $dataValue !== null) { 792 $cell->setValueExplicit($dataValue, $type); 1110 for ($i = 0; $i < $colRepeats; ++$i) { 1111 if ($i > 0) { 1112 StringHelper::stringIncrement($columnID); 1113 } 1114 1115 if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) { 1116 continue; 1117 } 1118 1119 if ($type !== DataType::TYPE_NULL) { 1120 for ($rowAdjust = 0; $rowAdjust < $rowRepeats; ++$rowAdjust) { 1121 $rID = $rowID + $rowAdjust; 1122 1123 $cell = $spreadsheet->getActiveSheet() 1124 ->getCell($columnID . $rID); 1125 1126 // Set value 1127 if ($hasCalculatedValue) { 1128 $cell->setValueExplicit($cellDataFormula, $type); 1129 if ($cellDataType === 'array') { 1130 $cell->setFormulaAttributes(['t' => 'array', 'ref' => $cellDataRef]); 793 1131 } 794 795 if ($hasCalculatedValue) { 796 $cell->setCalculatedValue($dataValue, $type === DataType::TYPE_NUMERIC); 1132 } elseif ($type !== '' || $dataValue !== null) { 1133 $cell->setValueExplicit($dataValue, $type); 1134 } 1135 1136 if ($hasCalculatedValue) { 1137 $cell->setCalculatedValue($dataValue, $type === DataType::TYPE_NUMERIC); 1138 } 1139 1140 // Set other properties 1141 if ($formatting !== null) { 1142 $spreadsheet->getActiveSheet() 1143 ->getStyle($columnID . $rID) 1144 ->getNumberFormat() 1145 ->setFormatCode($formatting); 1146 } else { 1147 $spreadsheet->getActiveSheet() 1148 ->getStyle($columnID . $rID) 1149 ->getNumberFormat() 1150 ->setFormatCode(NumberFormat::FORMAT_GENERAL); 1151 } 1152 1153 if ($hyperlink !== null) { 1154 if ($hyperlink[0] === '#') { 1155 $hyperlink = 'sheet://' . substr($hyperlink, 1); 797 1156 } 798 799 // Set other properties 800 if ($formatting !== null) { 801 $spreadsheet->getActiveSheet() 802 ->getStyle($columnID . $rID) 803 ->getNumberFormat() 804 ->setFormatCode($formatting); 805 } else { 806 $spreadsheet->getActiveSheet() 807 ->getStyle($columnID . $rID) 808 ->getNumberFormat() 809 ->setFormatCode(NumberFormat::FORMAT_GENERAL); 810 } 811 812 if ($hyperlink !== null) { 813 if ($hyperlink[0] === '#') { 814 $hyperlink = 'sheet://' . substr($hyperlink, 1); 815 } 816 $cell->getHyperlink() 817 ->setUrl($hyperlink); 818 } 1157 $cell->getHyperlink() 1158 ->setUrl($hyperlink); 819 1159 } 820 1160 } … … 844 1184 * @param string[] $columnWidths 845 1185 */ 846 private function processTable HeaderColumns(1186 private function processTableColumnHeader( 847 1187 DOMElement $childNode, 848 1188 string $tableNs, 849 1189 array $columnWidths, 850 1190 int &$tableColumnIndex, 851 Spreadsheet $spreadsheet 1191 Spreadsheet $spreadsheet, 1192 bool $processWidths = true, 1193 bool $processStyles = true 852 1194 ): void { 853 1195 foreach ($childNode->childNodes as $grandchildNode) { … … 861 1203 $columnWidths, 862 1204 $tableColumnIndex, 863 $spreadsheet 1205 $spreadsheet, 1206 $processWidths, 1207 $processStyles 864 1208 ); 865 1209 … … 877 1221 array $columnWidths, 878 1222 int &$tableColumnIndex, 879 Spreadsheet $spreadsheet 1223 Spreadsheet $spreadsheet, 1224 bool $processWidths = true, 1225 bool $processStyles = true 880 1226 ): void { 881 1227 foreach ($childNode->childNodes as $grandchildNode) { … … 889 1235 $columnWidths, 890 1236 $tableColumnIndex, 891 $spreadsheet 1237 $spreadsheet, 1238 $processWidths, 1239 $processStyles 892 1240 ); 893 1241 … … 895 1243 case 'table-header-columns': 896 1244 case 'table-columns': 897 $this->processTable HeaderColumns(1245 $this->processTableColumnHeader( 898 1246 $grandchildNode, 899 1247 $tableNs, 900 1248 $columnWidths, 901 1249 $tableColumnIndex, 902 $spreadsheet 1250 $spreadsheet, 1251 $processWidths, 1252 $processStyles 903 1253 ); 904 1254 … … 910 1260 $columnWidths, 911 1261 $tableColumnIndex, 912 $spreadsheet 1262 $spreadsheet, 1263 $processWidths, 1264 $processStyles 913 1265 ); 914 1266 … … 926 1278 array $columnWidths, 927 1279 int &$tableColumnIndex, 928 Spreadsheet $spreadsheet 1280 Spreadsheet $spreadsheet, 1281 bool $processWidths = true, 1282 bool $processStyles = true 929 1283 ): void { 930 1284 if ($childNode->hasAttributeNS($tableNs, 'number-columns-repeated')) { … … 934 1288 } 935 1289 $tableStyleName = $childNode->getAttributeNS($tableNs, 'style-name'); 936 if (isset($columnWidths[$tableStyleName])) { 937 $columnWidth = new HelperDimension($columnWidths[$tableStyleName]); 938 $tableColumnString = Coordinate::stringFromColumnIndex($tableColumnIndex); 939 for ($rowRepeats2 = $rowRepeats; $rowRepeats2 > 0; --$rowRepeats2) { 940 /** @var string $tableColumnString */ 941 $spreadsheet->getActiveSheet() 942 ->getColumnDimension($tableColumnString) 943 ->setWidth($columnWidth->toUnit('cm'), 'cm'); 944 StringHelper::stringIncrement($tableColumnString); 1290 if ($processWidths) { 1291 if (isset($columnWidths[$tableStyleName])) { 1292 $columnWidth = new HelperDimension($columnWidths[$tableStyleName]); 1293 $tableColumnIndex2 = $tableColumnIndex; 1294 $tableColumnString = Coordinate::stringFromColumnIndex($tableColumnIndex2); 1295 for ($rowRepeats2 = $rowRepeats; $rowRepeats2 > 0 && $tableColumnIndex2 <= AddressRange::MAX_COLUMN_INT; --$rowRepeats2) { 1296 if (!$this->readEmptyCells && $tableColumnIndex2 > $this->highestDataIndex) { 1297 break; 1298 } 1299 $spreadsheet->getActiveSheet() 1300 ->getColumnDimension($tableColumnString) 1301 ->setWidth($columnWidth->toUnit('cm'), 'cm'); 1302 StringHelper::stringIncrement( 1303 $tableColumnString 1304 ); 1305 ++$tableColumnIndex2; 1306 } 1307 } 1308 } 1309 if ($processStyles) { 1310 $defaultStyleName = $childNode->getAttributeNS($tableNs, 'default-cell-style-name'); 1311 if ($defaultStyleName !== 'Default' && isset($this->allStyles[$defaultStyleName])) { 1312 $tableColumnIndex2 = $tableColumnIndex; 1313 $tableColumnString = Coordinate::stringFromColumnIndex($tableColumnIndex2); 1314 for ($rowRepeats2 = $rowRepeats; $rowRepeats2 > 0 && $tableColumnIndex2 <= AddressRange::MAX_COLUMN_INT; --$rowRepeats2) { 1315 $spreadsheet->getActiveSheet() 1316 ->getStyle($tableColumnString) 1317 ->applyFromArray( 1318 $this->allStyles[$defaultStyleName] 1319 ); 1320 StringHelper::stringIncrement( 1321 $tableColumnString 1322 ); 1323 ++$tableColumnIndex2; 1324 } 945 1325 } 946 1326 } … … 1100 1480 } 1101 1481 } 1482 1483 /** @var null|Closure(string, string):string */ 1484 private ?Closure $formatCallback = null; 1485 1486 /** @param Closure(string, string):string $formatCallback */ 1487 public function setFormatCallback(Closure $formatCallback): void 1488 { 1489 $this->formatCallback = $formatCallback; 1490 } 1491 1492 /** @return array{ 1493 * autoColor?: true, 1494 * bold?: true, 1495 * color?: array{rgb: string}, 1496 * italic?: true, 1497 * name?: non-empty-string, 1498 * size?: float|int, 1499 * strikethrough?: true, 1500 * underline?: 'double'|'single', 1501 * } 1502 */ 1503 protected function getFontStyles(DOMElement $textProperty, string $styleNs, string $fontNs): array 1504 { 1505 $fonts = []; 1506 $temp = $textProperty->getAttributeNs($styleNs, 'font-name') ?: $textProperty->getAttributeNs($fontNs, 'font-family'); 1507 if ($temp !== '') { 1508 $fonts['name'] = $temp; 1509 } 1510 $temp = $textProperty->getAttributeNs($fontNs, 'font-size'); 1511 if ($temp !== '' && str_ends_with($temp, 'pt')) { 1512 $fonts['size'] = (float) substr($temp, 0, -2); 1513 } 1514 $temp = $textProperty->getAttributeNs($fontNs, 'font-style'); 1515 if ($temp === 'italic') { 1516 $fonts['italic'] = true; 1517 } 1518 $temp = $textProperty->getAttributeNs($fontNs, 'font-weight'); 1519 if ($temp === 'bold') { 1520 $fonts['bold'] = true; 1521 } 1522 $temp = $textProperty->getAttributeNs($fontNs, 'color'); 1523 if (Preg::isMatch('/^#[a-f0-9]{6}$/i', $temp)) { 1524 $fonts['color'] = ['rgb' => (string) substr($temp, 1)]; 1525 } 1526 $temp = $textProperty->getAttributeNs($styleNs, 'use-window-font-color'); 1527 if ($temp === 'true') { 1528 $fonts['autoColor'] = true; 1529 } 1530 $temp = $textProperty->getAttributeNs($styleNs, 'text-underline-type'); 1531 if ($temp === '') { 1532 $temp = $textProperty->getAttributeNs($styleNs, 'text-underline-style'); 1533 if ($temp !== '' && $temp !== 'none') { 1534 $temp = 'single'; 1535 } 1536 } 1537 if ($temp === 'single' || $temp === 'double') { 1538 $fonts['underline'] = $temp; 1539 } 1540 $temp = $textProperty->getAttributeNs($styleNs, 'text-line-through-type'); 1541 if ($temp !== '' && $temp !== 'none') { 1542 $fonts['strikethrough'] = true; 1543 } 1544 1545 return $fonts; 1546 } 1547 1548 /** @return array{ 1549 * fillType?: string, 1550 * startColor?: array{rgb: string}, 1551 * } 1552 */ 1553 protected function getFillStyles(DOMElement $tableCellProperties, string $fontNs): array 1554 { 1555 $fills = []; 1556 $temp = $tableCellProperties->getAttributeNs($fontNs, 'background-color'); 1557 if (Preg::isMatch('/^#[a-f0-9]{6}$/i', $temp)) { 1558 $fills['fillType'] = Fill::FILL_SOLID; 1559 $fills['startColor'] = ['rgb' => (string) substr($temp, 1)]; 1560 } elseif ($temp === 'transparent') { 1561 $fills['fillType'] = Fill::FILL_NONE; 1562 } 1563 1564 return $fills; 1565 } 1566 1567 private const MAP_VERTICAL = [ 1568 'top' => Alignment::VERTICAL_TOP, 1569 'middle' => Alignment::VERTICAL_CENTER, 1570 'automatic' => Alignment::VERTICAL_JUSTIFY, 1571 'bottom' => Alignment::VERTICAL_BOTTOM, 1572 ]; 1573 private const MAP_HORIZONTAL = [ 1574 'center' => Alignment::HORIZONTAL_CENTER, 1575 'end' => Alignment::HORIZONTAL_RIGHT, 1576 'justify' => Alignment::HORIZONTAL_FILL, 1577 'start' => Alignment::HORIZONTAL_LEFT, 1578 ]; 1579 1580 /** @return array{ 1581 * shrinkToFit?: bool, 1582 * textRotation?: int, 1583 * vertical?: string, 1584 * wrapText?: bool, 1585 * } 1586 */ 1587 protected function getAlignment1Styles(DOMElement $tableCellProperties, string $styleNs, string $fontNs): array 1588 { 1589 $alignment1 = []; 1590 $temp = $tableCellProperties->getAttributeNs($styleNs, 'rotation-angle'); 1591 if (is_numeric($temp)) { 1592 $temp2 = (int) $temp; 1593 if ($temp2 > 90) { 1594 $temp2 -= 360; 1595 } 1596 if ($temp2 >= -90 && $temp2 <= 90) { 1597 $alignment1['textRotation'] = (int) $temp2; 1598 } 1599 } 1600 $temp = $tableCellProperties->getAttributeNs($styleNs, 'vertical-align'); 1601 $temp2 = self::MAP_VERTICAL[$temp] ?? ''; 1602 if ($temp2 !== '') { 1603 $alignment1['vertical'] = $temp2; 1604 } 1605 $temp = $tableCellProperties->getAttributeNs($fontNs, 'wrap-option'); 1606 if ($temp === 'wrap') { 1607 $alignment1['wrapText'] = true; 1608 } elseif ($temp === 'no-wrap') { 1609 $alignment1['wrapText'] = false; 1610 } 1611 $temp = $tableCellProperties->getAttributeNs($styleNs, 'shrink-to-fit'); 1612 if ($temp === 'true' || $temp === 'false') { 1613 $alignment1['shrinkToFit'] = $temp === 'true'; 1614 } 1615 1616 return $alignment1; 1617 } 1618 1619 /** @return array{ 1620 * horizontal?: string, 1621 * readOrder?: int, 1622 * } 1623 */ 1624 protected function getAlignment2Styles(DOMElement $paragraphProperties, string $styleNs, string $fontNs): array 1625 { 1626 $alignment2 = []; 1627 $temp = $paragraphProperties->getAttributeNs($fontNs, 'text-align'); 1628 $temp2 = self::MAP_HORIZONTAL[$temp] ?? ''; 1629 if ($temp2 !== '') { 1630 $alignment2['horizontal'] = $temp2; 1631 } 1632 $temp = $paragraphProperties->getAttributeNs($fontNs, 'margin-left') ?: $paragraphProperties->getAttributeNs($fontNs, 'margin-right'); 1633 if (Preg::isMatch('/^\d+([.]\d+)?(cm|in|mm|pt)$/', $temp)) { 1634 $dimension = new HelperDimension($temp); 1635 $alignment2['indent'] = (int) round($dimension->toUnit('px') / Alignment::INDENT_UNITS_TO_PIXELS); 1636 } 1637 1638 $temp = $paragraphProperties->getAttributeNs($styleNs, 'writing-mode'); 1639 if ($temp === 'rl-tb') { 1640 $alignment2['readOrder'] = Alignment::READORDER_RTL; 1641 } elseif ($temp === 'lr-tb') { 1642 $alignment2['readOrder'] = Alignment::READORDER_LTR; 1643 } 1644 1645 return $alignment2; 1646 } 1647 1648 /** @return array{ 1649 * locked?: string, 1650 * hidden?: string, 1651 * } 1652 */ 1653 protected function getProtectionStyles(DOMElement $tableCellProperties, string $styleNs): array 1654 { 1655 $protection = []; 1656 $temp = $tableCellProperties->getAttributeNs($styleNs, 'cell-protect'); 1657 switch ($temp) { 1658 case 'protected formula-hidden': 1659 $protection['locked'] = Protection::PROTECTION_PROTECTED; 1660 $protection['hidden'] = Protection::PROTECTION_PROTECTED; 1661 1662 break; 1663 case 'formula-hidden': 1664 $protection['locked'] = Protection::PROTECTION_UNPROTECTED; 1665 $protection['hidden'] = Protection::PROTECTION_PROTECTED; 1666 1667 break; 1668 case 'protected': 1669 $protection['locked'] = Protection::PROTECTION_PROTECTED; 1670 $protection['hidden'] = Protection::PROTECTION_UNPROTECTED; 1671 1672 break; 1673 case 'none': 1674 $protection['locked'] = Protection::PROTECTION_UNPROTECTED; 1675 $protection['hidden'] = Protection::PROTECTION_UNPROTECTED; 1676 1677 break; 1678 } 1679 1680 return $protection; 1681 } 1682 1683 private const MAP_BORDER_STYLE = [ // default BORDER_THIN 1684 'none' => Border::BORDER_NONE, 1685 'hidden' => Border::BORDER_NONE, 1686 'dotted' => Border::BORDER_DOTTED, 1687 'dash-dot' => Border::BORDER_DASHDOT, 1688 'dash-dot-dot' => Border::BORDER_DASHDOTDOT, 1689 'dashed' => Border::BORDER_DASHED, 1690 'double' => Border::BORDER_DOUBLE, 1691 ]; 1692 1693 private const MAP_BORDER_MEDIUM = [ 1694 Border::BORDER_THIN => Border::BORDER_MEDIUM, 1695 Border::BORDER_DASHDOT => Border::BORDER_MEDIUMDASHDOT, 1696 Border::BORDER_DASHDOTDOT => Border::BORDER_MEDIUMDASHDOTDOT, 1697 Border::BORDER_DASHED => Border::BORDER_MEDIUMDASHED, 1698 ]; 1699 1700 private const MAP_BORDER_THICK = [ 1701 Border::BORDER_THIN => Border::BORDER_THICK, 1702 Border::BORDER_DASHDOT => Border::BORDER_MEDIUMDASHDOT, 1703 Border::BORDER_DASHDOTDOT => Border::BORDER_MEDIUMDASHDOTDOT, 1704 Border::BORDER_DASHED => Border::BORDER_MEDIUMDASHED, 1705 ]; 1706 1707 /** @return array{ 1708 * bottom?: array{borderStyle:string, color:array{rgb: string}}, 1709 * top?: array{borderStyle:string, color:array{rgb: string}}, 1710 * left?: array{borderStyle:string, color:array{rgb: string}}, 1711 * right?: array{borderStyle:string, color:array{rgb: string}}, 1712 * diagonal?: array{borderStyle:string, color:array{rgb: string}}, 1713 * diagonalDirection?: int, 1714 * } 1715 */ 1716 protected function getBorderStyles(DOMElement $tableCellProperties, string $fontNs, string $styleNs): array 1717 { 1718 $borders = []; 1719 $temp = $tableCellProperties->getAttributeNs($fontNs, 'border'); 1720 $diagonalIndex = Borders::DIAGONAL_NONE; 1721 foreach (['bottom', 'left', 'right', 'top', 'diagonal-tl-br', 'diagonal-bl-tr'] as $direction) { 1722 if (str_starts_with($direction, 'diagonal')) { 1723 $directionIndex = 'diagonal'; 1724 $temp = $tableCellProperties->getAttributeNs($styleNs, $direction); 1725 } else { 1726 $directionIndex = $direction; 1727 $temp = $tableCellProperties->getAttributeNs($fontNs, "border-$direction"); 1728 } 1729 if (Preg::isMatch('/^(\d+(?:[.]\d+)?)pt\s+([-\w]+)\s+#([0-9a-fA-F]{6})$/', $temp, $matches)) { 1730 $style = self::MAP_BORDER_STYLE[$matches[2]] ?? Border::BORDER_THIN; 1731 $width = (float) $matches[1]; 1732 if ($width >= 2.5) { 1733 $style = self::MAP_BORDER_THICK[$style] ?? $style; 1734 } elseif ($width >= 1.75) { 1735 $style = self::MAP_BORDER_MEDIUM[$style] ?? $style; 1736 } 1737 $color = $matches[3]; 1738 $borders[$directionIndex] = ['borderStyle' => $style, 'color' => ['rgb' => $matches[3]]]; 1739 if ($direction === 'diagonal-tl-br') { 1740 $diagonalIndex = Borders::DIAGONAL_DOWN; 1741 } elseif ($direction === 'diagonal-bl-tr') { 1742 $diagonalIndex = ($diagonalIndex === Borders::DIAGONAL_NONE) ? Borders::DIAGONAL_UP : Borders::DIAGONAL_BOTH; 1743 } 1744 } 1745 } 1746 if ($diagonalIndex !== Borders::DIAGONAL_NONE) { 1747 $borders['diagonalDirection'] = $diagonalIndex; 1748 } 1749 1750 return $borders; // @phpstan-ignore-line 1751 } 1102 1752 } -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Reader/Ods/PageSettings.php
r3463039 r3473263 69 69 $marginBottom = ($nullsafeVariable8 = $pageLayoutProperties) ? $nullsafeVariable8->getAttributeNS($this->stylesFo, 'margin-bottom') : null; 70 70 $header = $styleSet->getElementsByTagNameNS($this->stylesNs, 'header-style')->item(0); 71 $headerProperties = ($nullsafeVariable9 = ($nullsafeVariable1 3 = $header) ? $nullsafeVariable13->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties') : null) ? $nullsafeVariable9->item(0) : null;72 $marginHeader = ($nullsafeVariable1 0 = $headerProperties) ? $nullsafeVariable10->getAttributeNS($this->stylesFo, 'min-height') : null;71 $headerProperties = ($nullsafeVariable9 = ($nullsafeVariable10 = $header) ? $nullsafeVariable10->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties') : null) ? $nullsafeVariable9->item(0) : null; 72 $marginHeader = ($nullsafeVariable11 = $headerProperties) ? $nullsafeVariable11->getAttributeNS($this->stylesFo, 'min-height') : null; 73 73 $footer = $styleSet->getElementsByTagNameNS($this->stylesNs, 'footer-style')->item(0); 74 $footerProperties = ($nullsafeVariable1 1 = ($nullsafeVariable14 = $footer) ? $nullsafeVariable14->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties') : null) ? $nullsafeVariable11->item(0) : null;75 $marginFooter = ($nullsafeVariable1 2 = $footerProperties) ? $nullsafeVariable12->getAttributeNS($this->stylesFo, 'min-height') : null;74 $footerProperties = ($nullsafeVariable12 = ($nullsafeVariable13 = $footer) ? $nullsafeVariable13->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties') : null) ? $nullsafeVariable12->item(0) : null; 75 $marginFooter = ($nullsafeVariable14 = $footerProperties) ? $nullsafeVariable14->getAttributeNS($this->stylesFo, 'min-height') : null; 76 76 77 77 $this->pageLayoutStyles[$styleName] = (object) [ -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Reader/Xlsx.php
r3463039 r3473263 699 699 $this->styleReader 700 700 ->readStyle($objStyle, $style); 701 if (isset($xfTag->extLst)) { 702 foreach ($xfTag->extLst->ext as $extTag) { 703 $attributes = $extTag->attributes(); 704 if (isset($attributes['uri'])) { 705 if ((string) $attributes['uri'] === Namespaces::STYLE_CHECKBOX_URI) { 706 $objStyle->setCheckBox(true); 707 } 708 } 709 } 710 } 701 711 foreach ($this->styleReader->getFontCharsets() as $fontName => $charset) { 702 712 $excel->addFontCharset($fontName, $charset); … … 1599 1609 if (isset($images[$linkImageKey])) { 1600 1610 $url = str_replace('xl/drawings/', '', $images[$linkImageKey]); 1601 $objDrawing->setPath($url, false, null, $this->allowExternalImages );1611 $objDrawing->setPath($url, false, null, $this->allowExternalImages, $this->isWhitelisted); 1602 1612 } 1603 1613 if ($objDrawing->getPath() === '') { … … 1703 1713 if (isset($images[$linkImageKey])) { 1704 1714 $url = str_replace('xl/drawings/', '', $images[$linkImageKey]); 1705 $objDrawing->setPath($url, false, null, $this->allowExternalImages );1715 $objDrawing->setPath($url, false, null, $this->allowExternalImages, $this->isWhitelisted); 1706 1716 } 1707 1717 if ($objDrawing->getPath() === '') { … … 2233 2243 if (str_contains($item[1], 'px')) { 2234 2244 $item[1] = str_replace('px', '', $item[1]); 2235 } 2236 if (str_contains($item[1], 'pt')) { 2245 } elseif (str_contains($item[1], 'pt')) { 2237 2246 $item[1] = str_replace('pt', '', $item[1]); 2238 $item[1] = (string) Font::fontSizeToPixels((int) $item[1]); 2239 } 2240 if (str_contains($item[1], 'in')) { 2247 $item[1] = Font::fontSizeToPixels((float) $item[1]); 2248 } elseif (str_contains($item[1], 'in')) { 2241 2249 $item[1] = str_replace('in', '', $item[1]); 2242 $item[1] = (string) Font::inchSizeToPixels((int) $item[1]); 2243 } 2244 if (str_contains($item[1], 'cm')) { 2250 $item[1] = (int) Font::inchSizeToPixels((float) $item[1]); 2251 } elseif (str_contains($item[1], 'cm')) { 2245 2252 $item[1] = str_replace('cm', '', $item[1]); 2246 $item[1] = (string) Font::centimeterSizeToPixels((int) $item[1]); 2253 $item[1] = (int) Font::centimeterSizeToPixels((float) $item[1]); 2254 } elseif (str_contains($item[1], 'mm')) { 2255 $item[1] = str_replace('mm', '', $item[1]); 2256 $item[1] = (int) Font::centimeterSizeToPixels((float) $item[1] / 10); 2247 2257 } 2248 2258 -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Reader/Xlsx/Namespaces.php
r3463039 r3473263 130 130 131 131 const RELATIONSHIPS_RICH_VALUE_REL = 'http://schemas.microsoft.com/office/2022/10/relationships/richValueRel'; 132 133 const FEATURE_PROPERTY_BAG = 'http://schemas.microsoft.com/office/spreadsheetml/2022/featurepropertybag'; 134 const RELATIONSHIPS_FEATURE_PROPERTY_BAG = 'http://schemas.microsoft.com/office/2022/11/relationships/FeaturePropertyBag'; 135 const STYLE_CHECKBOX_URI = '{C7286773-470A-42A8-94C5-96B5CB345126}'; 132 136 } -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Spreadsheet.php
r3463039 r3473263 3 3 namespace TablePress\PhpOffice\PhpSpreadsheet; 4 4 5 use TablePress\Composer\Pcre\Preg; 5 6 use JsonSerializable; 6 7 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Calculation; … … 1065 1066 if ($worksheet !== null) { 1066 1067 $wsTitle = StringHelper::strToUpper($worksheet->getTitle()); 1067 $definedName = (string) preg_replace('/^.*!/', '', $definedName);1068 $definedName = Preg::replace('/^.*!/', '', $definedName); 1068 1069 foreach ($this->definedNames as $dn) { 1069 1070 $sheet = $dn->getScope() ?? $dn->getWorksheet(); … … 1870 1871 } 1871 1872 1873 /** 1874 * Change all 2-digit-year date styles to use 4-digit year; 1875 * change all dd-mm-yyyy and mm-dd-yyyy styles to yyyy-mm-dd; 1876 * dd-mmm-yyyy is unambiguous and left unchanged. 1877 */ 1878 public function disambiguateDateStyles(): void 1879 { 1880 foreach ($this->cellXfCollection as $style) { 1881 $numberFormat = $style->getNumberFormat(); 1882 $oldFormat = (string) $numberFormat->getFormatCode(); 1883 $newFormat = Preg::replace('/\byy\b/i', 'yyyy', $oldFormat); 1884 $newFormat = Preg::replace( 1885 '~\bdd?(-|/|"-"|"/")' 1886 . 'mm?(-|/|"-"|"/")' 1887 . 'yyyy~', 1888 'yyyy-mm-dd', 1889 $newFormat 1890 ); 1891 $newFormat = Preg::replace( 1892 '~\bmm?(-|/|"-"|"/")' 1893 . 'dd?(-|/|"-"|"/")' 1894 . 'yyyy~', 1895 'yyyy-mm-dd', 1896 $newFormat 1897 ); 1898 if ($newFormat !== $oldFormat) { 1899 $numberFormat->setFormatCode($newFormat); 1900 } 1901 } 1902 } 1903 1872 1904 public function returnArrayAsArray(): void 1873 1905 { … … 1904 1936 return $this->domainWhiteList; 1905 1937 } 1938 1939 private bool $usesCheckBoxStyle = false; 1940 1941 public function getUsesCheckBoxStyle(): bool 1942 { 1943 return $this->usesCheckBoxStyle; 1944 } 1945 1946 public function setUsesCheckBoxStyle(): bool 1947 { 1948 $this->usesCheckBoxStyle = false; 1949 foreach ($this->getCellXfCollection() as $cellXf) { 1950 if ($cellXf->getCheckBox()) { 1951 $this->usesCheckBoxStyle = true; 1952 1953 break; 1954 } 1955 } 1956 1957 return $this->usesCheckBoxStyle; 1958 } 1906 1959 } -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Style/Alignment.php
r3420898 r3473263 366 366 } 367 367 } else { 368 throw new PhpSpreadsheetException( 'Text rotation should be a value between -90 and 90.');368 throw new PhpSpreadsheetException("Text rotation $angleInDegrees should be a value between -90 and 90."); 369 369 } 370 370 -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Style/Font.php
r3350024 r3473263 178 178 * </code> 179 179 * 180 * @param array{name?: string, latin?: string, eastAsian?: string, complexScript?: string, bold?: bool, italic?: bool, superscript?: bool, subscript?: bool, underline?: bool|string, strikethrough?: bool, color?: string[], size?: ?int, chartColor?: ChartColor, scheme?: string, cap?: string, autoColor?: bool} $styleArray Array containing style information 180 * @param array{ 181 * autoColor?: bool, 182 * bold?: bool, 183 * cap?: string, 184 * chartColor?: ChartColor, 185 * color?: string[], 186 * complexScript?: string, 187 * eastAsian?: string, 188 * italic?: bool, 189 * latin?: string, 190 * name?: string, 191 * scheme?: string, 192 * size?: null|float|int, 193 * strikethrough?: bool, 194 * superscript?: bool, 195 * subscript?: bool, 196 * underline?: bool|string, 197 * } $styleArray Array containing style information 181 198 * 182 199 * @return $this -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Style/NumberFormat.php
r3385566 r3473263 24 24 const FORMAT_DATE_YYYYMMDD = 'yyyy-mm-dd'; 25 25 const FORMAT_DATE_DDMMYYYY = 'dd/mm/yyyy'; 26 const FORMAT_DATE_DMYSLASH = 'd /m/yy';26 const FORMAT_DATE_DMYSLASH = 'd"/"m"/"yy'; 27 27 const FORMAT_DATE_DMYMINUS = 'd-m-yy'; 28 28 const FORMAT_DATE_DMMINUS = 'd-m'; … … 31 31 const FORMAT_DATE_XLSX14_ACTUAL = 'm/d/yyyy'; 32 32 const FORMAT_DATE_XLSX15 = 'd-mmm-yy'; 33 const FORMAT_DATE_XLSX15_YYYY = 'd-mmm-yyyy'; 33 34 const FORMAT_DATE_XLSX16 = 'd-mmm'; 34 35 const FORMAT_DATE_XLSX17 = 'mmm-yy'; … … 36 37 const FORMAT_DATE_XLSX22_ACTUAL = 'm/d/yyyy h:mm'; 37 38 const FORMAT_DATE_DATETIME = 'd/m/yy h:mm'; 39 const FORMAT_DATE_DATETIME_BETTER = 'yyyy-mm-dd hh:mm'; 38 40 const FORMAT_DATE_TIME1 = 'h:mm AM/PM'; 39 41 const FORMAT_DATE_TIME2 = 'h:mm:ss AM/PM'; … … 44 46 const FORMAT_DATE_TIME7 = 'i:s.S'; 45 47 const FORMAT_DATE_TIME8 = 'h:mm:ss;@'; 46 const FORMAT_DATE_YYYYMMDDSLASH = 'yyyy/mm/dd;@'; 48 const FORMAT_DATE_TIME_INTERVAL_HMS = '[hh]:mm:ss'; 49 const FORMAT_DATE_YYYYMMDDSLASH = 'yyyy"/"mm"/"dd;@'; 47 50 const FORMAT_DATE_LONG_DATE = 'dddd, mmmm d, yyyy'; 48 51 … … 62 65 self::FORMAT_DATE_XLSX22_ACTUAL, 63 66 self::FORMAT_DATE_DATETIME, 67 self::FORMAT_DATE_DATETIME_BETTER, 64 68 self::FORMAT_DATE_TIME1, 65 69 self::FORMAT_DATE_TIME2, … … 70 74 self::FORMAT_DATE_TIME7, 71 75 self::FORMAT_DATE_TIME8, 76 self::FORMAT_DATE_TIME_INTERVAL_HMS, 72 77 self::FORMAT_DATE_YYYYMMDDSLASH, 73 78 self::FORMAT_DATE_LONG_DATE, … … 76 81 self::FORMAT_DATE_XLSX22, 77 82 self::FORMAT_DATE_DATETIME, 83 self::FORMAT_DATE_DATETIME_BETTER, 78 84 self::FORMAT_DATE_TIME1, 79 85 self::FORMAT_DATE_TIME2, … … 84 90 self::FORMAT_DATE_TIME7, 85 91 self::FORMAT_DATE_TIME8, 92 self::FORMAT_DATE_TIME_INTERVAL_HMS, 86 93 ]; 87 94 88 const FORMAT_CURRENCY_USD_INTEGER = '$#,##0_-'; 89 const FORMAT_CURRENCY_USD = '$#,##0.00_-'; 95 private const FORMAT_CURRENCY_AMOUNT_INTEGER = '#,##0_-'; 96 private const FORMAT_CURRENCY_AMOUNT_FLOAT = '#,##0.00_-'; 97 const FORMAT_CURRENCY_USD_INTEGER = '$' . self::FORMAT_CURRENCY_AMOUNT_INTEGER; 98 const FORMAT_CURRENCY_USD = '$' . self::FORMAT_CURRENCY_AMOUNT_FLOAT; 99 const FORMAT_CURRENCY_GBP_INTEGER = '£' . self::FORMAT_CURRENCY_AMOUNT_INTEGER; 100 const FORMAT_CURRENCY_GBP = '£' . self::FORMAT_CURRENCY_AMOUNT_FLOAT; 101 const FORMAT_CURRENCY_YEN_YUAN_INTEGER = '¥' . self::FORMAT_CURRENCY_AMOUNT_INTEGER; 102 const FORMAT_CURRENCY_YEN_YUAN = '¥' . self::FORMAT_CURRENCY_AMOUNT_FLOAT; 90 103 const FORMAT_CURRENCY_EUR_INTEGER = '#,##0_-[$€]'; 91 104 const FORMAT_CURRENCY_EUR = '#,##0.00_-[$€]'; -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php
r3420898 r3473263 3 3 namespace TablePress\PhpOffice\PhpSpreadsheet\Style\NumberFormat; 4 4 5 use TablePress\Composer\Pcre\Preg; 5 6 use TablePress\PhpOffice\PhpSpreadsheet\Shared\Date; 6 7 use TablePress\PhpOffice\PhpSpreadsheet\Shared\StringHelper; … … 122 123 public static function format($value, string $format): string 123 124 { 125 if ($value < 0 && Preg::isMatch('/^\[?[hms]/i', $format)) { 126 return '-' . self::format(-$value, $format); 127 } 124 128 // strip off first part containing e.g. [$-F800] or [$USD-409] 125 129 // general syntax: [$<Currency string>-<language info>] 126 130 // language info is in hexadecimal 127 131 // strip off chinese part like [DBNum1][$-804] 128 $format = (string) preg_replace('/^(\[DBNum\d\])*(\[\$[^\]]*\])/i', '', $format);132 $format = Preg::replace('/^(\[DBNum\d\])*(\[\$[^\]]*\])/i', '', $format); 129 133 130 134 // OpenOffice.org uses upper-case number formats, e.g. 'YYYY', convert to lower-case; 131 135 // but we don't want to change any quoted strings 132 /** @var callable $callable */ 133 $callable = [self::class, 'setLowercaseCallback']; 134 $format = (string) preg_replace_callback('/(?:^|")([^"]*)(?:$|")/', $callable, $format); 136 $format = Preg::replaceCallback('/(?:^|")([^"]*)(?:$|")/', \Closure::fromCallable([self::class, 'setLowerCaseCallback']), $format); 135 137 136 138 // Only process the non-quoted blocks for date format characters … … 160 162 161 163 // escape any quoted characters so that DateTime format() will render them correctly 162 /** @var callable $callback */ 163 $callback = [self::class, 'escapeQuotesCallback']; 164 $format = (string) preg_replace_callback('/"(.*)"/U', $callback, $format); 164 $format = Preg::replaceCallback('/"(.*)"/U', \Closure::fromCallable([self::class, 'escapeQuotesCallback']), $format); 165 165 166 166 try { … … 172 172 // Excel 2003 XML formats, m will not have been changed to i above. 173 173 // Change it now. 174 $format = (string) \preg_replace('/\\\:m/', ':i', $format);174 $format = Preg::replace('/\\\:m/', ':i', $format); 175 175 $microseconds = (int) $dateObj->format('u'); 176 176 if (str_contains($format, ':s.000')) { … … 208 208 } 209 209 210 /** @param string[]$matches */210 /** @param array<?string> $matches */ 211 211 private static function setLowercaseCallback(array $matches): string 212 212 { 213 /** @var string[] $matches */ 213 214 return mb_strtolower($matches[0]); 214 215 } 215 216 216 /** @param string[]$matches */217 /** @param array<?string> $matches */ 217 218 private static function escapeQuotesCallback(array $matches): string 218 219 { 220 /** @var string[] $matches */ 219 221 return '\\' . implode('\\', mb_str_split($matches[1], 1, 'UTF-8')); 220 222 } -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Style/Style.php
r3385566 r3473263 52 52 */ 53 53 protected bool $quotePrefix = false; 54 55 protected bool $checkBox = false; 54 56 55 57 /** … … 485 487 * numberFormat?: string[], 486 488 * protection?: array{locked?: string, hidden?: string}, 489 * checkBox?: bool, 487 490 * quotePrefix?: bool} $styleArray */ 491 if (isset($styleArray['checkBox'])) { 492 $this->checkBox = (bool) $styleArray['checkBox']; 493 } 488 494 if (isset($styleArray['fill'])) { 489 495 $this->getFill() … … 701 707 } 702 708 709 public function getCheckBox(): bool 710 { 711 if ($this->isSupervisor) { 712 return $this->getSharedComponent()->getCheckBox(); 713 } 714 715 return $this->checkBox; 716 } 717 718 /** 719 * @return static 720 */ 721 public function setCheckBox(bool $checkBox) 722 { 723 if ($this->isSupervisor) { 724 $styleArray = ['checkBox' => $checkBox]; 725 $this->getActiveSheet() 726 ->getStyle($this->getSelectedCells()) 727 ->applyFromArray($styleArray); 728 } else { 729 $this->checkBox = $checkBox; 730 } 731 732 return $this; 733 } 734 703 735 /** 704 736 * Get hash code. … … 716 748 . $this->protection->getHashCode() 717 749 . ($this->quotePrefix ? 't' : 'f') 750 . ($this->checkBox ? 't' : 'f') 718 751 . __CLASS__ 719 752 ); -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Worksheet/Drawing.php
r3420898 r3473263 90 90 * @param bool $verifyFile Verify file 91 91 * @param ?ZipArchive $zip Zip archive instance 92 * @param null|callable(string):bool $isWhitelisted 92 93 * 93 94 * @return $this 94 95 */ 95 public function setPath(string $path, bool $verifyFile = true, ?ZipArchive $zip = null, bool $allowExternal = true )96 public function setPath(string $path, bool $verifyFile = true, ?ZipArchive $zip = null, bool $allowExternal = true, ?callable $isWhitelisted = null) 96 97 { 97 98 $this->isUrl = false; … … 103 104 104 105 $this->path = ''; 106 if ($zip instanceof ZipArchive) { 107 $zipPath = explode('#', $path)[1]; 108 $locate = @$zip->locateName($zipPath); 109 if ($locate !== false) { 110 if ($this->isImage($path)) { 111 $this->path = $path; 112 $this->setSizesAndType($path); 113 } 114 } 105 115 // Check if a URL has been passed. https://stackoverflow.com/a/2058596/1252979 106 if (filter_var($path, FILTER_VALIDATE_URL) || (preg_match('/^([\w\s\x00-\x1f]+):/u', $path) && !preg_match('/^([\w]+):/u', $path))) {116 } elseif (filter_var($path, FILTER_VALIDATE_URL) || (preg_match('/^([\w\s\x00-\x1f]+):/u', $path) && !preg_match('/^([\w]+):/u', $path))) { 107 117 if (!preg_match('/^(http|https|file|ftp|s3):/', $path)) { 108 118 throw new PhpSpreadsheetException('Invalid protocol for linked drawing'); 109 119 } 110 120 if (!$allowExternal) { 121 return $this; 122 } 123 if ($isWhitelisted !== null && !$isWhitelisted($path)) { 111 124 return $this; 112 125 } … … 145 158 } 146 159 } 147 } elseif ($zip instanceof ZipArchive) {148 $zipPath = explode('#', $path)[1];149 $locate = @$zip->locateName($zipPath);150 if ($locate !== false) {151 if ($this->isImage($path)) {152 $this->path = $path;153 $this->setSizesAndType($path);154 }155 }156 160 } else { 157 161 $exists = @file_exists($path); -
tablepress/trunk/libraries/vendor/PhpSpreadsheet/Worksheet/Worksheet.php
r3463039 r3473263 2981 2981 * @param bool $formatData Whether to format data according to cell's style. 2982 2982 * @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value 2983 * @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead. 2983 2984 * 2984 2985 * @throws Exception … … 2986 2987 * @return mixed 2987 2988 */ 2988 protected function cellToArray(Cell $cell, bool $calculateFormulas, bool $formatData, $nullValue, bool $lessFloatPrecision = false )2989 protected function cellToArray(Cell $cell, bool $calculateFormulas, bool $formatData, $nullValue, bool $lessFloatPrecision = false, $oldCalculatedValue = false) 2989 2990 { 2990 2991 $returnValue = $nullValue; … … 2993 2994 if ($cell->getValue() instanceof RichText) { 2994 2995 $returnValue = $cell->getValue()->getPlainText(); 2996 } elseif ($calculateFormulas) { 2997 $returnValue = $cell->getCalculatedValue(); 2998 } elseif ($oldCalculatedValue && ($cell->getDataType() === DataType::TYPE_FORMULA)) { 2999 $returnValue = $cell->getOldCalculatedValue() ?? $cell->getValue(); 2995 3000 } else { 2996 $returnValue = ($calculateFormulas) ? $cell->getCalculatedValue() :$cell->getValue();3001 $returnValue = $cell->getValue(); 2997 3002 } 2998 3003 … … 3020 3025 * @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value. 3021 3026 * @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value 3027 * @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead. 3022 3028 * 3023 3029 * @return mixed[][] … … 3031 3037 bool $ignoreHidden = false, 3032 3038 bool $reduceArrays = false, 3033 bool $lessFloatPrecision = false 3039 bool $lessFloatPrecision = false, 3040 bool $oldCalculatedValue = false 3034 3041 ): array { 3035 3042 $returnValue = []; 3036 3043 3037 3044 // Loop through rows 3038 foreach ($this->rangeToArrayYieldRows($range, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision ) as $rowRef => $rowArray) {3045 foreach ($this->rangeToArrayYieldRows($range, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision, $oldCalculatedValue) as $rowRef => $rowArray) { 3039 3046 /** @var int $rowRef */ 3040 3047 $returnValue[$rowRef] = $rowArray; … … 3057 3064 * @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value. 3058 3065 * @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value 3066 * @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead. 3059 3067 * 3060 3068 * @return mixed[][] … … 3068 3076 bool $ignoreHidden = false, 3069 3077 bool $reduceArrays = false, 3070 bool $lessFloatPrecision = false 3078 bool $lessFloatPrecision = false, 3079 bool $oldCalculatedValue = false 3071 3080 ): array { 3072 3081 $returnValue = []; … … 3075 3084 foreach ($parts as $part) { 3076 3085 // Loop through rows 3077 foreach ($this->rangeToArrayYieldRows($part, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision ) as $rowRef => $rowArray) {3086 foreach ($this->rangeToArrayYieldRows($part, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision, $oldCalculatedValue) as $rowRef => $rowArray) { 3078 3087 /** @var int $rowRef */ 3079 3088 $returnValue[$rowRef] = $rowArray; … … 3097 3106 * @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value. 3098 3107 * @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value 3108 * @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead. 3099 3109 * 3100 3110 * @return Generator<array<mixed>> … … 3108 3118 bool $ignoreHidden = false, 3109 3119 bool $reduceArrays = false, 3110 bool $lessFloatPrecision = false 3120 bool $lessFloatPrecision = false, 3121 bool $oldCalculatedValue = false 3111 3122 ) { 3112 3123 $range = Validations::validateCellOrCellRange($range); … … 3174 3185 $cell = $this->cellCollection->get("{$col}{$thisRow}"); 3175 3186 if ($cell !== null) { 3176 $value = $this->cellToArray($cell, $calculateFormulas, $formatData, $nullValue, $lessFloatPrecision );3187 $value = $this->cellToArray($cell, $calculateFormulas, $formatData, $nullValue, $lessFloatPrecision, $oldCalculatedValue); 3177 3188 if ($reduceArrays) { 3178 3189 while (is_array($value)) { … … 3277 3288 * @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value. 3278 3289 * @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value 3290 * @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead. 3279 3291 * 3280 3292 * @return mixed[][] … … 3288 3300 bool $ignoreHidden = false, 3289 3301 bool $reduceArrays = false, 3290 bool $lessFloatPrecision = false 3302 bool $lessFloatPrecision = false, 3303 bool $oldCalculatedValue = false 3291 3304 ): array { 3292 3305 $retVal = []; … … 3297 3310 $workSheet = $namedRange->getWorksheet(); 3298 3311 if ($workSheet !== null) { 3299 $retVal = $workSheet->rangeToArray($cellRange, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision );3312 $retVal = $workSheet->rangeToArray($cellRange, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision, $oldCalculatedValue); 3300 3313 } 3301 3314 } … … 3316 3329 * @param bool $reduceArrays If true and result is a formula which evaluates to an array, reduce it to the top leftmost value. 3317 3330 * @param bool $lessFloatPrecision If true, formatting unstyled floats will convert them to a more human-friendly but less computationally accurate value 3331 * @param bool $oldCalculatedValue If calculateFormulas is false and this is true, use oldCalculatedFormula instead. 3318 3332 * 3319 3333 * @return mixed[][] … … 3326 3340 bool $ignoreHidden = false, 3327 3341 bool $reduceArrays = false, 3328 bool $lessFloatPrecision = false 3342 bool $lessFloatPrecision = false, 3343 bool $oldCalculatedValue = false 3329 3344 ): array { 3330 3345 // Garbage collect... … … 3337 3352 3338 3353 // Return 3339 return $this->rangeToArray("A1:{$maxCol}{$maxRow}", $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision );3354 return $this->rangeToArray("A1:{$maxCol}{$maxRow}", $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays, $lessFloatPrecision, $oldCalculatedValue); 3340 3355 } 3341 3356 -
tablepress/trunk/libraries/vendor/autoload-classmap.php
r3463039 r3473263 263 263 'TablePress\PhpOffice\PhpSpreadsheet\Calculation\Database\DCount' => $strauss_src . '/PhpSpreadsheet/Calculation/Database/DCount.php', 264 264 'TablePress\PhpOffice\PhpSpreadsheet\Calculation\Database\DSum' => $strauss_src . '/PhpSpreadsheet/Calculation/Database/DSum.php', 265 'TablePress\PhpOffice\PhpSpreadsheet\Calculation\CalculationParserOnly' => $strauss_src . '/PhpSpreadsheet/Calculation/CalculationParserOnly.php', 265 266 'TablePress\PhpOffice\PhpSpreadsheet\Calculation\FunctionArray' => $strauss_src . '/PhpSpreadsheet/Calculation/FunctionArray.php', 266 267 'TablePress\PhpOffice\PhpSpreadsheet\Calculation\Information\Info' => $strauss_src . '/PhpSpreadsheet/Calculation/Information/Info.php', -
tablepress/trunk/readme.txt
r3463039 r3473263 6 6 Requires PHP: 7.4 7 7 Tested up to: 6.9 8 Stable tag: 3.2. 78 Stable tag: 3.2.8 9 9 License: GPLv2 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 108 108 109 109 Changes in recent versions are shown below. For earlier changes, please see the [changelog history](https://tablepress.org/info/#changelog). 110 111 = Version 3.2.8 (March 3, 2026) = 112 113 * Bugfix: Whitespace handling for the “Filter Term Separator” setting in the “Column Filter Dropdowns” feature module now works properly again. (TablePress Pro and Max only.) 114 * Enhancement: The “Column Filter Dropdowns” feature module integration when using “Server-side Processing” is now more reliable. (TablePress Max only.) 115 * Cleaned up and simplified code, for easier future maintenance, to follow WordPress Coding Standards, and to offer helpful inline documentation. 116 * Several external code libraries and build tools have been updated to benefit from enhancements and bug fixes. 117 * Improved support for PHP 8.5. 110 118 111 119 = Version 3.2.7 (February 17, 2026) = … … 212 220 == Upgrade Notice == 213 221 214 = 3.2. 7=222 = 3.2.8 = 215 223 This update is an enhancement, stability, maintenance, and compatibility release. Updating is highly recommended! 216 224 -
tablepress/trunk/tablepress.php
r3463039 r3473263 5 5 * @package TablePress 6 6 * @author Tobias Bäthge 7 * @version 3.2. 77 * @version 3.2.8 8 8 * 9 9 * … … 11 11 * Plugin URI: https://tablepress.org/ 12 12 * Description: Embed beautiful and interactive tables into your WordPress website’s posts and pages, without having to write code! 13 * Version: 3.2. 713 * Version: 3.2.8 14 14 * Requires at least: 6.2 15 15 * Requires PHP: 7.4 … … 70 70 'has_addons' => false, 71 71 'has_paid_plans' => true, 72 'is_org_compliant' => true, 72 73 'menu' => array( 73 74 'slug' => 'tablepress',
Note: See TracChangeset
for help on using the changeset viewer.