From e55ecbac8cef04faa29e0e0bb3ecc8b8930f527f Mon Sep 17 00:00:00 2001 From: meirzamoodle Date: Thu, 31 Aug 2023 10:09:16 +0700 Subject: [PATCH] MDL-79210 lib: Upgrade PHPSpreadSheet to 1.29.0 --- lib/phpspreadsheet/vendor/autoload.php | 2 +- .../vendor/composer/ClassLoader.php | 12 +- .../vendor/composer/InstalledVersions.php | 17 +- .../vendor/composer/autoload_real.php | 8 +- .../vendor/composer/autoload_static.php | 8 +- .../vendor/composer/installed.json | 76 ++--- .../vendor/composer/installed.php | 24 +- .../phpoffice/phpspreadsheet/CHANGELOG.md | 61 ++++ .../phpoffice/phpspreadsheet/CONTRIBUTING.md | 39 ++- .../vendor/phpoffice/phpspreadsheet/README.md | 24 +- .../phpoffice/phpspreadsheet/composer.json | 18 +- .../phpspreadsheet/phpunit10.xml.dist | 15 + .../Calculation/Calculation.php | 50 +++- .../Calculation/DateTimeExcel/DateValue.php | 5 + .../Calculation/DateTimeExcel/Month.php | 2 + .../Calculation/DateTimeExcel/TimeValue.php | 5 + .../Calculation/Engine/FormattedNumber.php | 23 +- .../Engine/Operands/StructuredReference.php | 6 +- .../Calculation/Engineering.php | 22 -- .../Calculation/Engineering/Complex.php | 2 +- .../Calculation/Engineering/ConvertBinary.php | 6 +- .../Calculation/LookupRef/HLookup.php | 2 +- .../Calculation/LookupRef/VLookup.php | 2 +- .../Calculation/MathTrig/Sum.php | 2 +- .../Calculation/TextData/Extract.php | 4 +- .../Calculation/TextData/Format.php | 21 +- .../Calculation/TextData/Text.php | 4 +- .../Cell/AdvancedValueBinder.php | 7 +- .../src/PhpSpreadsheet/Cell/Cell.php | 13 +- .../src/PhpSpreadsheet/Cell/DataValidator.php | 54 +++- .../src/PhpSpreadsheet/Cell/IgnoredErrors.php | 66 +++++ .../PhpSpreadsheet/CellReferenceHelper.php | 4 +- .../src/PhpSpreadsheet/Chart/Axis.php | 38 +++ .../src/PhpSpreadsheet/Chart/AxisText.php | 56 ++++ .../src/PhpSpreadsheet/Chart/Chart.php | 25 ++ .../src/PhpSpreadsheet/Chart/Layout.php | 44 ++- .../src/PhpSpreadsheet/Chart/Legend.php | 40 +++ .../src/PhpSpreadsheet/Chart/PlotArea.php | 45 +++ .../Chart/Renderer/JpGraphRendererBase.php | 29 +- .../Chart/Renderer/MtJpGraphRenderer.php | 6 +- .../PhpSpreadsheet/Document/Properties.php | 16 +- .../src/PhpSpreadsheet/Helper/Downloader.php | 89 ++++++ .../src/PhpSpreadsheet/Helper/Handler.php | 46 +++ .../src/PhpSpreadsheet/Helper/Html.php | 35 +-- .../src/PhpSpreadsheet/Helper/Sample.php | 47 ++- .../src/PhpSpreadsheet/Helper/TextGrid.php | 16 +- .../src/PhpSpreadsheet/Reader/Gnumeric.php | 51 ++-- .../src/PhpSpreadsheet/Reader/Html.php | 162 +++++++++-- .../src/PhpSpreadsheet/Reader/Ods.php | 40 +++ .../Reader/Security/XmlScanner.php | 2 +- .../src/PhpSpreadsheet/Reader/Xlsx.php | 192 ++++++++++--- .../src/PhpSpreadsheet/Reader/Xlsx/Chart.php | 159 ++++++++++- .../Reader/Xlsx/DataValidations.php | 12 + .../PhpSpreadsheet/Reader/Xlsx/Properties.php | 3 + .../Reader/Xlsx/SharedFormula.php | 26 ++ .../src/PhpSpreadsheet/Reader/Xlsx/Styles.php | 16 +- .../src/PhpSpreadsheet/Reader/Xml.php | 162 ++++++++--- .../Reader/Xml/DataValidations.php | 177 ++++++++++++ .../Reader/Xml/PageSettings.php | 9 +- .../PhpSpreadsheet/Reader/Xml/Properties.php | 19 +- .../src/PhpSpreadsheet/Reader/Xml/Style.php | 25 +- .../PhpSpreadsheet/Reader/Xml/Style/Font.php | 4 +- .../src/PhpSpreadsheet/ReferenceHelper.php | 81 +++--- .../PhpSpreadsheet/RichText/TextElement.php | 2 +- .../src/PhpSpreadsheet/Settings.php | 2 +- .../src/PhpSpreadsheet/Shared/Date.php | 2 +- .../src/PhpSpreadsheet/Shared/File.php | 22 +- .../src/PhpSpreadsheet/Shared/Font.php | 40 +-- .../PhpSpreadsheet/Shared/StringHelper.php | 12 + .../src/PhpSpreadsheet/Shared/Trend/Trend.php | 1 - .../src/PhpSpreadsheet/Spreadsheet.php | 31 ++ .../src/PhpSpreadsheet/Style/Color.php | 17 +- .../src/PhpSpreadsheet/Style/Conditional.php | 2 +- .../src/PhpSpreadsheet/Style/Font.php | 49 +++- .../Style/NumberFormat/Formatter.php | 21 +- .../Style/NumberFormat/Wizard/Accounting.php | 4 +- .../Style/NumberFormat/Wizard/Date.php | 125 ++++++++ .../Style/NumberFormat/Wizard/DateTime.php | 50 ++++ .../NumberFormat/Wizard/DateTimeWizard.php | 44 +++ .../Style/NumberFormat/Wizard/Duration.php | 153 ++++++++++ .../Style/NumberFormat/Wizard/Time.php | 105 +++++++ .../src/PhpSpreadsheet/Style/RgbTint.php | 175 ++++++++++++ .../src/PhpSpreadsheet/Style/Style.php | 14 +- .../src/PhpSpreadsheet/Theme.php | 269 ++++++++++++++++++ .../PhpSpreadsheet/Worksheet/AutoFilter.php | 8 +- .../PhpSpreadsheet/Worksheet/PageMargins.php | 15 - .../PhpSpreadsheet/Worksheet/PageSetup.php | 15 - .../PhpSpreadsheet/Worksheet/SheetView.php | 15 - .../src/PhpSpreadsheet/Worksheet/Table.php | 4 +- .../PhpSpreadsheet/Worksheet/Table/Column.php | 4 +- .../PhpSpreadsheet/Worksheet/Validations.php | 5 +- .../PhpSpreadsheet/Worksheet/Worksheet.php | 200 ++++++++----- .../src/PhpSpreadsheet/Writer/Html.php | 45 ++- .../src/PhpSpreadsheet/Writer/Ods.php | 7 +- .../src/PhpSpreadsheet/Writer/Ods/Content.php | 9 + .../src/PhpSpreadsheet/Writer/Xlsx.php | 9 +- .../src/PhpSpreadsheet/Writer/Xlsx/Chart.php | 185 ++++++++---- .../PhpSpreadsheet/Writer/Xlsx/DocProps.php | 3 + .../Writer/Xlsx/FunctionPrefix.php | 2 +- .../Writer/Xlsx/StringTable.php | 9 +- .../src/PhpSpreadsheet/Writer/Xlsx/Style.php | 22 +- .../src/PhpSpreadsheet/Writer/Xlsx/Theme.php | 187 ++++-------- .../PhpSpreadsheet/Writer/Xlsx/Worksheet.php | 60 +++- .../src/PhpSpreadsheet/Writer/ZipStream0.php | 17 ++ .../src/PhpSpreadsheet/Writer/ZipStream2.php | 21 ++ .../src/PhpSpreadsheet/Writer/ZipStream3.php | 22 ++ .../vendor/psr/http-client/README.md | 2 +- .../vendor/psr/http-client/composer.json | 4 +- .../vendor/psr/http-factory/README.md | 12 +- .../vendor/psr/http-factory/composer.json | 4 +- .../vendor/psr/http-message/README.md | 5 +- .../vendor/psr/http-message/composer.json | 6 +- .../psr/http-message/docs/PSR7-Interfaces.md | 130 +++++++++ .../psr/http-message/docs/PSR7-Usage.md | 159 +++++++++++ .../psr/http-message/src/MessageInterface.php | 22 +- .../psr/http-message/src/RequestInterface.php | 15 +- .../http-message/src/ResponseInterface.php | 6 +- .../src/ServerRequestInterface.php | 24 +- .../psr/http-message/src/StreamInterface.php | 30 +- .../src/UploadedFileInterface.php | 12 +- .../psr/http-message/src/UriInterface.php | 33 +-- 121 files changed, 3869 insertions(+), 875 deletions(-) create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/phpunit10.xml.dist create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/IgnoredErrors.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/AxisText.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/Downloader.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/Handler.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/SharedFormula.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/DataValidations.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Date.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTime.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTimeWizard.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Duration.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Time.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/RgbTint.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Theme.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/ZipStream0.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/ZipStream2.php create mode 100644 lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/ZipStream3.php create mode 100644 lib/phpspreadsheet/vendor/psr/http-message/docs/PSR7-Interfaces.md create mode 100644 lib/phpspreadsheet/vendor/psr/http-message/docs/PSR7-Usage.md diff --git a/lib/phpspreadsheet/vendor/autoload.php b/lib/phpspreadsheet/vendor/autoload.php index ddbeffdfabf..887dca7fcad 100644 --- a/lib/phpspreadsheet/vendor/autoload.php +++ b/lib/phpspreadsheet/vendor/autoload.php @@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) { require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInitdb9a9022baf20d73f1edf8437bc648d7::getLoader(); +return ComposerAutoloaderInitf14832faa9ea8f0ad137e596f5daa06a::getLoader(); diff --git a/lib/phpspreadsheet/vendor/composer/ClassLoader.php b/lib/phpspreadsheet/vendor/composer/ClassLoader.php index fd56bd7d840..a72151c77c8 100644 --- a/lib/phpspreadsheet/vendor/composer/ClassLoader.php +++ b/lib/phpspreadsheet/vendor/composer/ClassLoader.php @@ -429,7 +429,8 @@ class ClassLoader public function loadClass($class) { if ($file = $this->findFile($class)) { - (self::$includeFile)($file); + $includeFile = self::$includeFile; + $includeFile($file); return true; } @@ -560,7 +561,10 @@ class ClassLoader return false; } - private static function initializeIncludeClosure(): void + /** + * @return void + */ + private static function initializeIncludeClosure() { if (self::$includeFile !== null) { return; @@ -574,8 +578,8 @@ class ClassLoader * @param string $file * @return void */ - self::$includeFile = static function($file) { + self::$includeFile = \Closure::bind(static function($file) { include $file; - }; + }, null, null); } } diff --git a/lib/phpspreadsheet/vendor/composer/InstalledVersions.php b/lib/phpspreadsheet/vendor/composer/InstalledVersions.php index c6b54af7ba2..51e734a774b 100644 --- a/lib/phpspreadsheet/vendor/composer/InstalledVersions.php +++ b/lib/phpspreadsheet/vendor/composer/InstalledVersions.php @@ -98,7 +98,7 @@ class InstalledVersions { foreach (self::getInstalled() as $installed) { if (isset($installed['versions'][$packageName])) { - return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; } } @@ -119,7 +119,7 @@ class InstalledVersions */ public static function satisfies(VersionParser $parser, $packageName, $constraint) { - $constraint = $parser->parseConstraints($constraint); + $constraint = $parser->parseConstraints((string) $constraint); $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); return $provided->matches($constraint); @@ -328,7 +328,9 @@ class InstalledVersions if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) { - $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require $vendorDir.'/composer/installed.php'; + $installed[] = self::$installedByVendor[$vendorDir] = $required; if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { self::$installed = $installed[count($installed) - 1]; } @@ -340,12 +342,17 @@ class InstalledVersions // only require the installed.php file if this file is loaded from its dumped location, // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 if (substr(__DIR__, -8, 1) !== 'C') { - self::$installed = require __DIR__ . '/installed.php'; + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; } else { self::$installed = array(); } } - $installed[] = self::$installed; + + if (self::$installed !== array()) { + $installed[] = self::$installed; + } return $installed; } diff --git a/lib/phpspreadsheet/vendor/composer/autoload_real.php b/lib/phpspreadsheet/vendor/composer/autoload_real.php index 0d4ed17ebaf..d51084dc0ec 100644 --- a/lib/phpspreadsheet/vendor/composer/autoload_real.php +++ b/lib/phpspreadsheet/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInitdb9a9022baf20d73f1edf8437bc648d7 +class ComposerAutoloaderInitf14832faa9ea8f0ad137e596f5daa06a { private static $loader; @@ -24,12 +24,12 @@ class ComposerAutoloaderInitdb9a9022baf20d73f1edf8437bc648d7 require __DIR__ . '/platform_check.php'; - spl_autoload_register(array('ComposerAutoloaderInitdb9a9022baf20d73f1edf8437bc648d7', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInitf14832faa9ea8f0ad137e596f5daa06a', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); - spl_autoload_unregister(array('ComposerAutoloaderInitdb9a9022baf20d73f1edf8437bc648d7', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInitf14832faa9ea8f0ad137e596f5daa06a', 'loadClassLoader')); require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInitdb9a9022baf20d73f1edf8437bc648d7::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInitf14832faa9ea8f0ad137e596f5daa06a::getInitializer($loader)); $loader->register(true); diff --git a/lib/phpspreadsheet/vendor/composer/autoload_static.php b/lib/phpspreadsheet/vendor/composer/autoload_static.php index 24dfbe45a4a..e90be9b6b69 100644 --- a/lib/phpspreadsheet/vendor/composer/autoload_static.php +++ b/lib/phpspreadsheet/vendor/composer/autoload_static.php @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInitdb9a9022baf20d73f1edf8437bc648d7 +class ComposerStaticInitf14832faa9ea8f0ad137e596f5daa06a { public static $prefixLengthsPsr4 = array ( 'P' => @@ -59,9 +59,9 @@ class ComposerStaticInitdb9a9022baf20d73f1edf8437bc648d7 public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInitdb9a9022baf20d73f1edf8437bc648d7::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInitdb9a9022baf20d73f1edf8437bc648d7::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInitdb9a9022baf20d73f1edf8437bc648d7::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInitf14832faa9ea8f0ad137e596f5daa06a::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitf14832faa9ea8f0ad137e596f5daa06a::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInitf14832faa9ea8f0ad137e596f5daa06a::$classMap; }, null, ClassLoader::class); } diff --git a/lib/phpspreadsheet/vendor/composer/installed.json b/lib/phpspreadsheet/vendor/composer/installed.json index dc75dbb47f8..f37a4542a31 100644 --- a/lib/phpspreadsheet/vendor/composer/installed.json +++ b/lib/phpspreadsheet/vendor/composer/installed.json @@ -115,17 +115,17 @@ }, { "name": "phpoffice/phpspreadsheet", - "version": "1.28.0", - "version_normalized": "1.28.0.0", + "version": "1.29.0", + "version_normalized": "1.29.0.0", "source": { "type": "git", "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", - "reference": "6e81cf39bbd93ebc3a4e8150444c41e8aa9b769a" + "reference": "fde2ccf55eaef7e86021ff1acce26479160a0fa0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/6e81cf39bbd93ebc3a4e8150444c41e8aa9b769a", - "reference": "6e81cf39bbd93ebc3a4e8150444c41e8aa9b769a", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/fde2ccf55eaef7e86021ff1acce26479160a0fa0", + "reference": "fde2ccf55eaef7e86021ff1acce26479160a0fa0", "shasum": "" }, "require": { @@ -143,7 +143,7 @@ "ext-zip": "*", "ext-zlib": "*", "ezyang/htmlpurifier": "^4.15", - "maennchen/zipstream-php": "^2.1", + "maennchen/zipstream-php": "^2.1 || ^3.0", "markbaker/complex": "^3.0", "markbaker/matrix": "^3.0", "php": "^7.4 || ^8.0", @@ -155,12 +155,12 @@ "dealerdirect/phpcodesniffer-composer-installer": "dev-main", "dompdf/dompdf": "^1.0 || ^2.0", "friendsofphp/php-cs-fixer": "^3.2", - "mitoteam/jpgraph": "^10.2.4", + "mitoteam/jpgraph": "^10.3", "mpdf/mpdf": "^8.1.1", "phpcompatibility/php-compatibility": "^9.3", "phpstan/phpstan": "^1.1", "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^8.5 || ^9.0", + "phpunit/phpunit": "^8.5 || ^9.0 || ^10.0", "squizlabs/php_codesniffer": "^3.7", "tecnickcom/tcpdf": "^6.5" }, @@ -171,7 +171,7 @@ "mpdf/mpdf": "Option for rendering PDF with PDF Writer", "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" }, - "time": "2023-02-25T12:24:49+00:00", + "time": "2023-06-14T22:48:31+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -217,30 +217,30 @@ ], "support": { "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", - "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.28.0" + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.29.0" }, "install-path": "../phpoffice/phpspreadsheet" }, { "name": "psr/http-client", - "version": "1.0.1", - "version_normalized": "1.0.1.0", + "version": "1.0.2", + "version_normalized": "1.0.2.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-client.git", - "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", - "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31", + "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31", "shasum": "" }, "require": { "php": "^7.0 || ^8.0", - "psr/http-message": "^1.0" + "psr/http-message": "^1.0 || ^2.0" }, - "time": "2020-06-29T06:28:15+00:00", + "time": "2023-04-10T20:12:12+00:00", "type": "library", "extra": { "branch-alias": { @@ -260,7 +260,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP clients", @@ -272,30 +272,30 @@ "psr-18" ], "support": { - "source": "https://github.com/php-fig/http-client/tree/master" + "source": "https://github.com/php-fig/http-client/tree/1.0.2" }, "install-path": "../psr/http-client" }, { "name": "psr/http-factory", - "version": "1.0.1", - "version_normalized": "1.0.1.0", + "version": "1.0.2", + "version_normalized": "1.0.2.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + "reference": "e616d01114759c4c489f93b099585439f795fe35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", + "reference": "e616d01114759c4c489f93b099585439f795fe35", "shasum": "" }, "require": { "php": ">=7.0.0", - "psr/http-message": "^1.0" + "psr/http-message": "^1.0 || ^2.0" }, - "time": "2019-04-30T12:38:16+00:00", + "time": "2023-04-10T20:10:41+00:00", "type": "library", "extra": { "branch-alias": { @@ -315,7 +315,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interfaces for PSR-7 HTTP message factories", @@ -330,33 +330,33 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-factory/tree/master" + "source": "https://github.com/php-fig/http-factory/tree/1.0.2" }, "install-path": "../psr/http-factory" }, { "name": "psr/http-message", - "version": "1.0.1", - "version_normalized": "1.0.1.0", + "version": "2.0", + "version_normalized": "2.0.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": "^7.2 || ^8.0" }, - "time": "2016-08-06T14:39:51+00:00", + "time": "2023-04-04T09:54:51+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "installation-source": "dist", @@ -372,7 +372,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP messages", @@ -386,7 +386,7 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/master" + "source": "https://github.com/php-fig/http-message/tree/2.0" }, "install-path": "../psr/http-message" }, diff --git a/lib/phpspreadsheet/vendor/composer/installed.php b/lib/phpspreadsheet/vendor/composer/installed.php index a12fefd1f0b..e8b22835b1d 100644 --- a/lib/phpspreadsheet/vendor/composer/installed.php +++ b/lib/phpspreadsheet/vendor/composer/installed.php @@ -56,36 +56,36 @@ ), ), 'phpoffice/phpspreadsheet' => array( - 'pretty_version' => '1.28.0', - 'version' => '1.28.0.0', - 'reference' => '6e81cf39bbd93ebc3a4e8150444c41e8aa9b769a', + 'pretty_version' => '1.29.0', + 'version' => '1.29.0.0', + 'reference' => 'fde2ccf55eaef7e86021ff1acce26479160a0fa0', 'type' => 'library', 'install_path' => __DIR__ . '/../phpoffice/phpspreadsheet', 'aliases' => array(), 'dev_requirement' => false, ), 'psr/http-client' => array( - 'pretty_version' => '1.0.1', - 'version' => '1.0.1.0', - 'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621', + 'pretty_version' => '1.0.2', + 'version' => '1.0.2.0', + 'reference' => '0955afe48220520692d2d09f7ab7e0f93ffd6a31', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/http-client', 'aliases' => array(), 'dev_requirement' => false, ), 'psr/http-factory' => array( - 'pretty_version' => '1.0.1', - 'version' => '1.0.1.0', - 'reference' => '12ac7fcd07e5b077433f5f2bee95b3a771bf61be', + 'pretty_version' => '1.0.2', + 'version' => '1.0.2.0', + 'reference' => 'e616d01114759c4c489f93b099585439f795fe35', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/http-factory', 'aliases' => array(), 'dev_requirement' => false, ), 'psr/http-message' => array( - 'pretty_version' => '1.0.1', - 'version' => '1.0.1.0', - 'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363', + 'pretty_version' => '2.0', + 'version' => '2.0.0.0', + 'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/http-message', 'aliases' => array(), diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/CHANGELOG.md b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/CHANGELOG.md index 2f383e23fd9..38836217ca0 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/CHANGELOG.md +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/CHANGELOG.md @@ -5,6 +5,67 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com) and this project adheres to [Semantic Versioning](https://semver.org). +## 1.29.0 - 2023-06-15 + +### Added + +- Wizards for defining Number Format masks for Dates and Times, including Durations/Intervals. [PR #3458](https://github.com/PHPOffice/PhpSpreadsheet/pull/3458) +- Specify data type in html tags. [Issue #3444](https://github.com/PHPOffice/PhpSpreadsheet/issues/3444) [PR #3445](https://github.com/PHPOffice/PhpSpreadsheet/pull/3445) +- Provide option to ignore hidden rows/columns in `toArray()` methods. [PR #3494](https://github.com/PHPOffice/PhpSpreadsheet/pull/3494) +- Font/Effects/Theme support for Chart Data Labels and Axis. [PR #3476](https://github.com/PHPOffice/PhpSpreadsheet/pull/3476) +- Font Themes support. [PR #3486](https://github.com/PHPOffice/PhpSpreadsheet/pull/3486) +- Ability to Ignore Cell Errors in Excel. [Issue #1141](https://github.com/PHPOffice/PhpSpreadsheet/issues/1141) [PR #3508](https://github.com/PHPOffice/PhpSpreadsheet/pull/3508) +- Unzipped Gnumeric file [PR #3591](https://github.com/PHPOffice/PhpSpreadsheet/pull/3591) + +### Changed + +- Xlsx Color schemes read in will be written out (previously Excel 2007-2010 Color scheme was always written); manipulation of those schemes before write, including restoring prior behavior, is provided [PR #3476](https://github.com/PHPOffice/PhpSpreadsheet/pull/3476) +- Memory and speed optimisations for Read Filters with Xlsx Files and Shared Formulae. [PR #3474](https://github.com/PHPOffice/PhpSpreadsheet/pull/3474) +- Allow `CellRange` and `CellAddress` objects for the `range` argument in the `rangeToArray()` method. [PR #3494](https://github.com/PHPOffice/PhpSpreadsheet/pull/3494) +- Stock charts will now read and reproduce `upDownBars` and subsidiary tags; these were previously ignored on read and hard-coded on write. [PR #3515](https://github.com/PHPOffice/PhpSpreadsheet/pull/3515) + +### Deprecated + +- Nothing + +### Removed + +- Nothing + +### Fixed + +- Updates Cell formula absolute ranges/references, and Defined Name absolute ranges/references when inserting/deleting rows/columns. [Issue #3368](https://github.com/PHPOffice/PhpSpreadsheet/issues/3368) [PR #3402](https://github.com/PHPOffice/PhpSpreadsheet/pull/3402) +- EOMONTH() and EDATE() Functions should round date value before evaluation. [Issue #3436](https://github.com/PHPOffice/PhpSpreadsheet/issues/3436) [PR #3437](https://github.com/PHPOffice/PhpSpreadsheet/pull/3437) +- NETWORKDAYS function erroneously being converted to NETWORK_xlfn.DAYS in Xlsx Writer. [Issue #3461](https://github.com/PHPOffice/PhpSpreadsheet/issues/3461) [PR #3463](https://github.com/PHPOffice/PhpSpreadsheet/pull/3463) +- Getting a style for a CellAddress instance fails if the worksheet is set in the CellAddress instance. [Issue #3439](https://github.com/PHPOffice/PhpSpreadsheet/issues/3439) [PR #3469](https://github.com/PHPOffice/PhpSpreadsheet/pull/3469) +- Shared Formulae outside the filter range when reading with a filter are not always being identified. [Issue #3473](https://github.com/PHPOffice/PhpSpreadsheet/issues/3473) [PR #3474](https://github.com/PHPOffice/PhpSpreadsheet/pull/3474) +- Xls Reader Conditional Styles. [PR #3400](https://github.com/PHPOffice/PhpSpreadsheet/pull/3400) +- Allow use of # and 0 digit placeholders in fraction masks. [PR #3401](https://github.com/PHPOffice/PhpSpreadsheet/pull/3401) +- Modify Date/Time check in the NumberFormatter for decimal/fractional times. [PR #3413](https://github.com/PHPOffice/PhpSpreadsheet/pull/3413) +- Misplaced Xml Writing Chart Label FillColor. [Issue #3397](https://github.com/PHPOffice/PhpSpreadsheet/issues/3397) [PR #3404](https://github.com/PHPOffice/PhpSpreadsheet/pull/3404) +- TEXT function ignores Time in DateTimeStamp. [Issue #3409](https://github.com/PHPOffice/PhpSpreadsheet/issues/3409) [PR #3411](https://github.com/PHPOffice/PhpSpreadsheet/pull/3411) +- Xlsx Column Autosize Approximate for CJK. [Issue #3405](https://github.com/PHPOffice/PhpSpreadsheet/issues/3405) [PR #3416](https://github.com/PHPOffice/PhpSpreadsheet/pull/3416) +- Correct Xlsx Parsing of quotePrefix="0". [Issue #3435](https://github.com/PHPOffice/PhpSpreadsheet/issues/3435) [PR #3438](https://github.com/PHPOffice/PhpSpreadsheet/pull/3438) +- More Display Options for Chart Axis and Legend. [Issue #3414](https://github.com/PHPOffice/PhpSpreadsheet/issues/3414) [PR #3434](https://github.com/PHPOffice/PhpSpreadsheet/pull/3434) +- Apply strict type checking to Complex suffix. [PR #3452](https://github.com/PHPOffice/PhpSpreadsheet/pull/3452) +- Incorrect Font Color Read Xlsx Rich Text Indexed Color Custom Palette. [Issue #3464](https://github.com/PHPOffice/PhpSpreadsheet/issues/3464) [PR #3465](https://github.com/PHPOffice/PhpSpreadsheet/pull/3465) +- Xlsx Writer Honor Alignment in Default Font. [Issue #3443](https://github.com/PHPOffice/PhpSpreadsheet/issues/3443) [PR #3459](https://github.com/PHPOffice/PhpSpreadsheet/pull/3459) +- Support Border for Charts. [PR #3462](https://github.com/PHPOffice/PhpSpreadsheet/pull/3462) +- Error in "this row" structured reference calculation (cached result from first row when using a range) [Issue #3504](https://github.com/PHPOffice/PhpSpreadsheet/issues/3504) [PR #3505](https://github.com/PHPOffice/PhpSpreadsheet/pull/3505) +- Allow colour palette index references in Number Format masks [Issue #3511](https://github.com/PHPOffice/PhpSpreadsheet/issues/3511) [PR #3512](https://github.com/PHPOffice/PhpSpreadsheet/pull/3512) +- Xlsx Reader formula with quotePrefix [Issue #3495](https://github.com/PHPOffice/PhpSpreadsheet/issues/3495) [PR #3497](https://github.com/PHPOffice/PhpSpreadsheet/pull/3497) +- Handle REF error as part of range [Issue #3453](https://github.com/PHPOffice/PhpSpreadsheet/issues/3453) [PR #3467](https://github.com/PHPOffice/PhpSpreadsheet/pull/3467) +- Handle Absolute Pathnames in Rels File [Issue #3553](https://github.com/PHPOffice/PhpSpreadsheet/issues/3553) [PR #3554](https://github.com/PHPOffice/PhpSpreadsheet/pull/3554) +- Return Page Breaks in Order [Issue #3552](https://github.com/PHPOffice/PhpSpreadsheet/issues/3552) [PR #3555](https://github.com/PHPOffice/PhpSpreadsheet/pull/3555) +- Add position attribute for MemoryDrawing in Html [Issue #3529](https://github.com/PHPOffice/PhpSpreadsheet/issues/3529 [PR #3535](https://github.com/PHPOffice/PhpSpreadsheet/pull/3535) +- Allow Index_number as Array for VLOOKUP/HLOOKUP [Issue #3561](https://github.com/PHPOffice/PhpSpreadsheet/issues/3561 [PR #3570](https://github.com/PHPOffice/PhpSpreadsheet/pull/3570) +- Add Unsupported Options in Xml Spreadsheet [Issue #3566](https://github.com/PHPOffice/PhpSpreadsheet/issues/3566 [Issue #3568](https://github.com/PHPOffice/PhpSpreadsheet/issues/3568 [Issue #3569](https://github.com/PHPOffice/PhpSpreadsheet/issues/3569 [PR #3567](https://github.com/PHPOffice/PhpSpreadsheet/pull/3567) +- Changes to NUMBERVALUE, VALUE, DATEVALUE, TIMEVALUE [Issue #3574](https://github.com/PHPOffice/PhpSpreadsheet/issues/3574 [PR #3575](https://github.com/PHPOffice/PhpSpreadsheet/pull/3575) +- Redo calculation of color tinting [Issue #3550](https://github.com/PHPOffice/PhpSpreadsheet/issues/3550) [PR #3580](https://github.com/PHPOffice/PhpSpreadsheet/pull/3580) +- Accommodate Slash with preg_quote [PR #3582](https://github.com/PHPOffice/PhpSpreadsheet/pull/3582) [PR #3583](https://github.com/PHPOffice/PhpSpreadsheet/pull/3583) [PR #3584](https://github.com/PHPOffice/PhpSpreadsheet/pull/3584) +- HyperlinkBase Property and Html Handling of Properties [Issue #3573](https://github.com/PHPOffice/PhpSpreadsheet/issues/3573) [PR #3589](https://github.com/PHPOffice/PhpSpreadsheet/pull/3589) +- Improvements for Data Validation [Issue #3592](https://github.com/PHPOffice/PhpSpreadsheet/issues/3592) [Issue #3594](https://github.com/PHPOffice/PhpSpreadsheet/issues/3594) [PR #3605](https://github.com/PHPOffice/PhpSpreadsheet/pull/3605) + ## 1.28.0 - 2023-02-25 ### Added diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/CONTRIBUTING.md b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/CONTRIBUTING.md index f59535331c1..09794b56511 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/CONTRIBUTING.md +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/CONTRIBUTING.md @@ -2,19 +2,44 @@ If you would like to contribute, here are some notes and guidelines: - - All new development happens on feature/fix branches, and are then merged to the `master` branch once stable; so the `master` branch is always the most up-to-date, working code - - Tagged releases are made from the `master` branch - - If you are going to be submitting a pull request, please fork from `master`, and submit your pull request back as a fix/feature branch referencing the GitHub issue number - - Code style might be automatically fixed by `composer fix` - - All code changes must be validated by `composer check` + - All new development should be on feature/fix branches, which are then merged to the `master` branch once stable and approved; so the `master` branch is always the most up-to-date, working code + - If you are going to submit a pull request, please fork from `master`, and submit your pull request back as a fix/feature branch referencing the GitHub issue number + - The code must work with all PHP versions that we support (currently PHP 7.4 to PHP 8.2). + - You can call `composer versions` to test version compatibility. + - Code style should be maintained. + - `composer style` will identify any issues with Coding Style`. + - `composer fix` will fix most issues with Coding Style. + - All code changes must be validated by `composer check`. + - Please include Unit Tests to verify that a bug exists, and that this PR fixes it. + - Please include Unit Tests to show that a new Feature works as expected. + - Please don't "bundle" several changes into a single PR; submit a PR for each discrete change/fix. + - Remember to update documentation if necessary. + - [Helpful article about forking](https://help.github.com/articles/fork-a-repo/ "Forking a GitHub repository") - [Helpful article about pull requests](https://help.github.com/articles/using-pull-requests/ "Pull Requests") +## Unit Tests + +When writing Unit Tests, please + - Always try to write Unit Tests for both the happy and unhappy paths. + - Put all assertions in the Test itself, not in an abstract class that the Test extends (even if this means code duplication between tests). + - Include any necessary `setup()` and `tearDown()` in the Test itself. + - If you change any global settings (such as system locale, or Compatibility Mode for Excel Function tests), make sure that you reset to the default in the `tearDown()`. + - Use the `ExcelError` functions in assertions for Excel Error values in Excel Function implementations. +
Not only does it reduce the risk of typos; but at some point in the future, ExcelError values will be an object rather than a string, and we won't then need to update all the tests. + - Don't over-complicate test code by testing happy and unhappy paths in the same test. + +This makes it easier to see exactly what is being tested when reviewing the PR. I want to be able to see it in the PR, not have to hunt in other unchanged classes to see what the test is doing. + ## How to release 1. Complete CHANGELOG.md and commit 2. Create an annotated tag 1. `git tag -a 1.2.3` 2. Tag subject must be the version number, eg: `1.2.3` - 3. Tag body must be a copy-paste of the changelog entries -3. Push tag with `git push --tags`, GitHub Actions will create a GitHub release automatically + 3. Tag body must be a copy-paste of the changelog entries. +3. Push the tag with `git push --tags`, GitHub Actions will create a GitHub release automatically, and the release details will automatically be sent to packagist. +4. Github seems to remove markdown headings in the Release Notes, so you should edit to restore these. + +> **Note:** Tagged releases are made from the `master` branch. Only in an emergency should a tagged release be made from the `release` branch. (i.e. cherry-picked hot-fixes.) + diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/README.md b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/README.md index d9a80732671..a69c3afc956 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/README.md +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/README.md @@ -32,7 +32,7 @@ If you are building your installation on a development machine that is on a diff ```json { "require": { - "phpoffice/phpspreadsheet": "^1.23" + "phpoffice/phpspreadsheet": "^1.28" }, "config": { "platform": { @@ -74,16 +74,20 @@ or the appropriate PDF Writer wrapper for the library that you have chosen to in For Chart export, we support following packages, which you will also need to install yourself using `composer require` - [jpgraph/jpgraph](https://packagist.org/packages/jpgraph/jpgraph) (this package was abandoned at version 4.0. You can manually download the latest version that supports PHP 8 and above from [jpgraph.net](https://jpgraph.net/)) - - [mitoteam/jpgraph](https://packagist.org/packages/mitoteam/jpgraph) (fork with php 8.1 support) + - [mitoteam/jpgraph](https://packagist.org/packages/mitoteam/jpgraph) - up to date fork with modern PHP versions support and some bugs fixed. and then configure PhpSpreadsheet using: ```php -Settings::setChartRenderer(\PhpOffice\PhpSpreadsheet\Chart\Renderer\JpGraph::class); // to use jpgraph/jpgraph +// to use jpgraph/jpgraph +Settings::setChartRenderer(\PhpOffice\PhpSpreadsheet\Chart\Renderer\JpGraph::class); //or -Settings::setChartRenderer(\PhpOffice\PhpSpreadsheet\Chart\Renderer\MtJpGraphRenderer::class); // to use mitoteam/jpgraph +// to use mitoteam/jpgraph +Settings::setChartRenderer(\PhpOffice\PhpSpreadsheet\Chart\Renderer\MtJpGraphRenderer::class); ``` -One or the other of these libraries is necessary if you want to generate HTML or PDF files that include charts. +One or the other of these libraries is necessary if you want to generate HTML or PDF files that include charts; or to render a Chart to an Image format from within your code. +They are not necessary to define charts for writing to `Xlsx` files. +Other file formats don't support writing Charts. ## Documentation @@ -103,10 +107,15 @@ Posts already available to Patreon supporters: - Looping the Loop - Advice on Iterating through the rows and cells in a worksheet. -The next post (currently being written) will be: +And for Patrons at levels actively using PhpSpreadsheet: - Behind the Mask - A look at Number Format Masks. +The Next Article (currently Work in Progress): + - Formula for Success + - How to debug formulae that don't produce the expected result. + + My aim is to post at least one article each month, taking a detailed look at some feature of MS Excel and how to use that feature in PhpSpreadsheet, or on how to perform different activities in PhpSpreadsheet. Planned posts for the future include topics like: @@ -116,8 +125,9 @@ Planned posts for the future include topics like: - Array Formulae - Conditional Formatting - Data Validation - - Formula Debugging - Value Binders + - Images + - Charts After a period of six months exclusive to Patreon supporters, articles will be incorporated into the public documentation for the library. diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/composer.json b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/composer.json index 1e8e5f6c07e..4b05be334be 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/composer.json +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/composer.json @@ -42,13 +42,19 @@ ], "scripts": { "check": [ + "phpcs src/ tests/ --report=checkstyle", + "phpcs --report-width=200 samples/ src/ tests/ --ignore=samples/Header.php --standard=PHPCompatibility --runtime-set testVersion 7.4- -n", "php-cs-fixer fix --ansi --dry-run --diff", - "phpcs", "phpunit --color=always", - "phpstan analyse --ansi" + "phpstan analyse --ansi --memory-limit=2048M" + ], + "style": [ + "phpcs src/ tests/ --report=checkstyle", + "php-cs-fixer fix --ansi --dry-run --diff" ], "fix": [ - "php-cs-fixer fix --ansi" + "phpcbf src/ tests/ --report=checkstyle", + "php-cs-fixer fix" ], "versions": [ "phpcs --report-width=200 samples/ src/ tests/ --ignore=samples/Header.php --standard=PHPCompatibility --runtime-set testVersion 7.4- -n" @@ -70,7 +76,7 @@ "ext-zip": "*", "ext-zlib": "*", "ezyang/htmlpurifier": "^4.15", - "maennchen/zipstream-php": "^2.1", + "maennchen/zipstream-php": "^2.1 || ^3.0", "markbaker/complex": "^3.0", "markbaker/matrix": "^3.0", "psr/http-client": "^1.0", @@ -81,12 +87,12 @@ "dealerdirect/phpcodesniffer-composer-installer": "dev-main", "dompdf/dompdf": "^1.0 || ^2.0", "friendsofphp/php-cs-fixer": "^3.2", - "mitoteam/jpgraph": "^10.2.4", + "mitoteam/jpgraph": "^10.3", "mpdf/mpdf": "^8.1.1", "phpcompatibility/php-compatibility": "^9.3", "phpstan/phpstan": "^1.1", "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^8.5 || ^9.0", + "phpunit/phpunit": "^8.5 || ^9.0 || ^10.0", "squizlabs/php_codesniffer": "^3.7", "tecnickcom/tcpdf": "^6.5" }, diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/phpunit10.xml.dist b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/phpunit10.xml.dist new file mode 100644 index 00000000000..207d8ec9785 --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/phpunit10.xml.dist @@ -0,0 +1,15 @@ + + + + + + + + ./tests/PhpSpreadsheetTests + + + + ./src + + + diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Calculation.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Calculation.php index 6de546fa29a..c88656b4a09 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Calculation.php @@ -19,6 +19,7 @@ use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use ReflectionClassConstant; use ReflectionMethod; use ReflectionParameter; +use Throwable; class Calculation { @@ -3556,7 +3557,7 @@ class Calculation } } - throw new Exception($e->getMessage()); + throw new Exception($e->getMessage(), $e->getCode(), $e); } if ((is_array($result)) && (self::$returnArrayAsType != self::RETURN_ARRAY_AS_ARRAY)) { @@ -4210,7 +4211,7 @@ class Calculation try { $this->branchPruner->closingBrace($d['value']); } catch (Exception $e) { - return $this->raiseFormulaError($e->getMessage()); + return $this->raiseFormulaError($e->getMessage(), $e->getCode(), $e); } $functionName = $matches[1]; // Get the function name @@ -4249,7 +4250,7 @@ class Calculation } elseif ($expectedArgumentCount != '*') { $isOperandOrFunction = preg_match('/(\d*)([-+,])(\d*)/', $expectedArgumentCount, $argMatch); self::doNothing($isOperandOrFunction); - switch ($argMatch[2]) { + switch ($argMatch[2] ?? '') { case '+': if ($argumentCount < $argMatch[1]) { $argumentCountError = true; @@ -4282,7 +4283,7 @@ class Calculation try { $this->branchPruner->argumentSeparator(); } catch (Exception $e) { - return $this->raiseFormulaError($e->getMessage()); + return $this->raiseFormulaError($e->getMessage(), $e->getCode(), $e); } while (($o2 = $stack->pop()) && $o2['value'] !== '(') { // Pop off the stack back to the last ( @@ -4364,8 +4365,12 @@ class Calculation $rangeStartCellRef = $output[count($output) - 2]['value'] ?? ''; } preg_match('/^' . self::CALCULATION_REGEXP_CELLREF . '$/miu', $rangeStartCellRef, $rangeStartMatches); - if ($rangeStartMatches[2] > '') { - $val = $rangeStartMatches[2] . '!' . $val; + if (array_key_exists(2, $rangeStartMatches)) { + if ($rangeStartMatches[2] > '') { + $val = $rangeStartMatches[2] . '!' . $val; + } + } else { + $val = Information\ExcelError::REF(); } } else { $rangeStartCellRef = $output[count($output) - 1]['value'] ?? ''; @@ -4391,7 +4396,7 @@ class Calculation try { $structuredReference = Operands\StructuredReference::fromParser($formula, $index, $matches); } catch (Exception $e) { - return $this->raiseFormulaError($e->getMessage()); + return $this->raiseFormulaError($e->getMessage(), $e->getCode(), $e); } $val = $structuredReference->value(); @@ -4434,6 +4439,8 @@ class Calculation } $val = $address; } + } elseif ($val === Information\ExcelError::REF()) { + $stackItemReference = $val; } else { $startRowColRef = $output[count($output) - 1]['value'] ?? ''; [$rangeWS1, $startRowColRef] = Worksheet::extractSheetTitle($startRowColRef, true); @@ -4731,7 +4738,7 @@ class Calculation $cellRange = $token->parse($cell); if (strpos($cellRange, ':') !== false) { $this->debugLog->writeDebugLog('Evaluating Structured Reference %s as Cell Range %s', $token->value(), $cellRange); - $rangeValue = self::getInstance($cell->getWorksheet()->getParent())->_calculateFormulaValue("={$cellRange}", $token->value(), $cell); + $rangeValue = self::getInstance($cell->getWorksheet()->getParent())->_calculateFormulaValue("={$cellRange}", $cellRange, $cell); $stack->push('Value', $rangeValue); $this->debugLog->writeDebugLog('Evaluated Structured Reference %s as value %s', $token->value(), $this->showValue($rangeValue)); } else { @@ -4745,7 +4752,7 @@ class Calculation $stack->push('Error', Information\ExcelError::REF(), null); $this->debugLog->writeDebugLog('Evaluated Structured Reference %s as error value %s', $token->value(), Information\ExcelError::REF()); } else { - return $this->raiseFormulaError($e->getMessage()); + return $this->raiseFormulaError($e->getMessage(), $e->getCode(), $e); } } } elseif (!is_numeric($token) && !is_object($token) && isset(self::BINARY_OPERATORS[$token])) { @@ -4793,7 +4800,7 @@ class Calculation } } } - if (strpos($operand1Data['reference'], '!') !== false) { + if (strpos($operand1Data['reference'] ?? '', '!') !== false) { [$sheet1, $operand1Data['reference']] = Worksheet::extractSheetTitle($operand1Data['reference'], true); } else { $sheet1 = ($pCellWorksheet !== null) ? $pCellWorksheet->getTitle() : ''; @@ -4830,10 +4837,21 @@ class Calculation $oData = array_merge(explode(':', $operand1Data['reference']), explode(':', $operand2Data['reference'])); $oCol = $oRow = []; + $breakNeeded = false; foreach ($oData as $oDatum) { - $oCR = Coordinate::coordinateFromString($oDatum); - $oCol[] = Coordinate::columnIndexFromString($oCR[0]) - 1; - $oRow[] = $oCR[1]; + try { + $oCR = Coordinate::coordinateFromString($oDatum); + $oCol[] = Coordinate::columnIndexFromString($oCR[0]) - 1; + $oRow[] = $oCR[1]; + } catch (\Exception $e) { + $stack->push('Error', Information\ExcelError::REF(), null); + $breakNeeded = true; + + break; + } + } + if ($breakNeeded) { + break; } $cellRef = Coordinate::stringFromColumnIndex(min($oCol) + 1) . min($oRow) . ':' . Coordinate::stringFromColumnIndex(max($oCol) + 1) . max($oRow); if ($pCellParent !== null && $this->spreadsheet !== null) { @@ -4842,8 +4860,10 @@ class Calculation return $this->raiseFormulaError('Unable to access Cell Reference'); } + $this->debugLog->writeDebugLog('Evaluation Result is %s', $this->showTypeDetails($cellValue)); $stack->push('Cell Reference', $cellValue, $cellRef); } else { + $this->debugLog->writeDebugLog('Evaluation Result is a #REF! Error'); $stack->push('Error', Information\ExcelError::REF(), null); } @@ -5434,13 +5454,13 @@ class Calculation * * @return false */ - protected function raiseFormulaError(string $errorMessage) + protected function raiseFormulaError(string $errorMessage, int $code = 0, ?Throwable $exception = null) { $this->formulaError = $errorMessage; $this->cyclicReferenceStack->clear(); $suppress = /** @scrutinizer ignore-deprecated */ $this->suppressFormulaErrors ?? $this->suppressFormulaErrorsNew; if (!$suppress) { - throw new Exception($errorMessage); + throw new Exception($errorMessage, $code, $exception); } return false; diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php index 9a9870d91dc..1d59988c3c5 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php @@ -45,6 +45,11 @@ class DateValue return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $dateValue); } + // try to parse as date iff there is at least one digit + if (is_string($dateValue) && preg_match('/\\d/', $dateValue) !== 1) { + return ExcelError::VALUE(); + } + $dti = new DateTimeImmutable(); $baseYear = SharedDateHelper::getExcelCalendar(); $dateValue = trim($dateValue ?? '', '"'); diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/DateTimeExcel/Month.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/DateTimeExcel/Month.php index c72d006b925..5c42eac0854 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/DateTimeExcel/Month.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/DateTimeExcel/Month.php @@ -45,6 +45,7 @@ class Month } catch (Exception $e) { return $e->getMessage(); } + $dateValue = floor($dateValue); $adjustmentMonths = floor($adjustmentMonths); // Execute function @@ -88,6 +89,7 @@ class Month } catch (Exception $e) { return $e->getMessage(); } + $dateValue = floor($dateValue); $adjustmentMonths = floor($adjustmentMonths); // Execute function diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php index bb9036f7829..78d67b837d2 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php @@ -42,6 +42,11 @@ class TimeValue return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $timeValue); } + // try to parse as time iff there is at least one digit + if (is_string($timeValue) && preg_match('/\\d/', $timeValue) !== 1) { + return ExcelError::VALUE(); + } + $timeValue = trim($timeValue ?? '', '"'); $timeValue = str_replace(['/', '.'], '-', $timeValue); diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php index 3e88ece550f..331fa448be2 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php @@ -48,9 +48,9 @@ class FormattedNumber */ public static function convertToNumberIfNumeric(string &$operand): bool { - $thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator()); + $thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator(), '/'); $value = preg_replace(['/(\d)' . $thousandsSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1$2', '$1$2'], trim($operand)); - $decimalSeparator = preg_quote(StringHelper::getDecimalSeparator()); + $decimalSeparator = preg_quote(StringHelper::getDecimalSeparator(), '/'); $value = preg_replace(['/(\d)' . $decimalSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1.$2', '$1$2'], $value ?? ''); if (is_numeric($value)) { @@ -90,9 +90,9 @@ class FormattedNumber */ public static function convertToNumberIfPercent(string &$operand): bool { - $thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator()); + $thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator(), '/'); $value = preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', trim($operand)); - $decimalSeparator = preg_quote(StringHelper::getDecimalSeparator()); + $decimalSeparator = preg_quote(StringHelper::getDecimalSeparator(), '/'); $value = preg_replace(['/(\d)' . $decimalSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1.$2', '$1$2'], $value ?? ''); $match = []; @@ -116,17 +116,22 @@ class FormattedNumber public static function convertToNumberIfCurrency(string &$operand): bool { $currencyRegexp = self::currencyMatcherRegexp(); - $thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator()); + $thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator(), '/'); $value = preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $operand); $match = []; if ($value !== null && preg_match($currencyRegexp, $value, $match, PREG_UNMATCHED_AS_NULL)) { //Determine the sign $sign = ($match['PrefixedSign'] ?? $match['PrefixedSign2'] ?? $match['PostfixedSign']) ?? ''; + $decimalSeparator = StringHelper::getDecimalSeparator(); //Cast to a float - $operand = (float) ($sign . ($match['PostfixedValue'] ?? $match['PrefixedValue'])); + $intermediate = (string) ($match['PostfixedValue'] ?? $match['PrefixedValue']); + $intermediate = str_replace($decimalSeparator, '.', $intermediate); + if (is_numeric($intermediate)) { + $operand = (float) ($sign . str_replace($decimalSeparator, '.', $intermediate)); - return true; + return true; + } } return false; @@ -134,8 +139,8 @@ class FormattedNumber public static function currencyMatcherRegexp(): string { - $currencyCodes = sprintf(self::CURRENCY_CONVERSION_LIST, preg_quote(StringHelper::getCurrencyCode())); - $decimalSeparator = preg_quote(StringHelper::getDecimalSeparator()); + $currencyCodes = sprintf(self::CURRENCY_CONVERSION_LIST, preg_quote(StringHelper::getCurrencyCode(), '/')); + $decimalSeparator = preg_quote(StringHelper::getDecimalSeparator(), '/'); return '~^(?:(?: *(?[-+])? *(?[' . $currencyCodes . ']) *(?[-+])? *(?[0-9]+[' . $decimalSeparator . ']?[0-9*]*(?:E[-+]?[0-9]*)?) *)|(?: *(?[-+])? *(?[0-9]+' . $decimalSeparator . '?[0-9]*(?:E[-+]?[0-9]*)?) *(?[' . $currencyCodes . ']) *))$~ui'; } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engine/Operands/StructuredReference.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engine/Operands/StructuredReference.php index 266f1b2bb1a..59cc3e3d278 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engine/Operands/StructuredReference.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engine/Operands/StructuredReference.php @@ -190,8 +190,8 @@ final class StructuredReference implements Operand { if ($columnName !== '') { $cellReference = $columnId . $cell->getRow(); - $pattern1 = '/\[' . preg_quote($columnName) . '\]/miu'; - $pattern2 = '/@' . preg_quote($columnName) . '/miu'; + $pattern1 = '/\[' . preg_quote($columnName, '/') . '\]/miu'; + $pattern2 = '/@' . preg_quote($columnName, '/') . '/miu'; if (preg_match($pattern1, $reference) === 1) { $reference = preg_replace($pattern1, $cellReference, $reference); } elseif (preg_match($pattern2, $reference) === 1) { @@ -328,7 +328,7 @@ final class StructuredReference implements Operand $cellFrom = "{$columnId}{$startRow}"; $cellTo = "{$columnId}{$endRow}"; $cellReference = ($cellFrom === $cellTo) ? $cellFrom : "{$cellFrom}:{$cellTo}"; - $pattern = '/\[' . preg_quote($columnName) . '\]/mui'; + $pattern = '/\[' . preg_quote($columnName, '/') . '\]/mui'; if (preg_match($pattern, $reference) === 1) { $columnsSelected = true; $reference = preg_replace($pattern, $cellReference, $reference); diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engineering.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engineering.php index e3a2bd65cd8..fdee7503ef3 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engineering.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engineering.php @@ -20,28 +20,6 @@ class Engineering */ public const EULER = 2.71828182845904523536; - /** - * parseComplex. - * - * Parses a complex number into its real and imaginary parts, and an I or J suffix - * - * @deprecated 1.12.0 No longer used by internal code. Please use the \Complex\Complex class instead - * - * @param string $complexNumber The complex number - * - * @return mixed[] Indexed on "real", "imaginary" and "suffix" - */ - public static function parseComplex($complexNumber) - { - $complex = new Complex($complexNumber); - - return [ - 'real' => $complex->getReal(), - 'imaginary' => $complex->getImaginary(), - 'suffix' => $complex->getSuffix(), - ]; - } - /** * BESSELI. * diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engineering/Complex.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engineering/Complex.php index 691de8b704f..f7ec02d43cf 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engineering/Complex.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engineering/Complex.php @@ -49,7 +49,7 @@ class Complex return $e->getMessage(); } - if (($suffix == 'i') || ($suffix == 'j') || ($suffix == '')) { + if (($suffix === 'i') || ($suffix === 'j') || ($suffix === '')) { $complex = new ComplexObject($realNumber, $imaginary, $suffix); return (string) $complex; diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engineering/ConvertBinary.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engineering/ConvertBinary.php index 4741f301008..04bf3e50607 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engineering/ConvertBinary.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Engineering/ConvertBinary.php @@ -40,7 +40,7 @@ class ConvertBinary extends ConvertBase return $e->getMessage(); } - if (strlen($value) == 10) { + if (strlen($value) == 10 && $value[0] === '1') { // Two's Complement $value = substr($value, -9); @@ -91,7 +91,7 @@ class ConvertBinary extends ConvertBase return $e->getMessage(); } - if (strlen($value) == 10) { + if (strlen($value) == 10 && $value[0] === '1') { $high2 = substr($value, 0, 2); $low8 = substr($value, 2); $xarr = ['00' => '00000000', '01' => '00000001', '10' => 'FFFFFFFE', '11' => 'FFFFFFFF']; @@ -144,7 +144,7 @@ class ConvertBinary extends ConvertBase return $e->getMessage(); } - if (strlen($value) == 10 && substr($value, 0, 1) === '1') { // Two's Complement + if (strlen($value) == 10 && $value[0] === '1') { // Two's Complement return str_repeat('7', 6) . strtoupper(decoct((int) bindec("11$value"))); } $octVal = (string) decoct((int) bindec($value)); diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php index e2d27bde241..bc425f873ba 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php @@ -27,7 +27,7 @@ class HLookup extends LookupBase */ public static function lookup($lookupValue, $lookupArray, $indexNumber, $notExactMatch = true) { - if (is_array($lookupValue)) { + if (is_array($lookupValue) || is_array($indexNumber)) { return self::evaluateArrayArgumentsIgnore([self::class, __FUNCTION__], 1, $lookupValue, $lookupArray, $indexNumber, $notExactMatch); } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php index edeb1aa8cc2..badd1057392 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php @@ -26,7 +26,7 @@ class VLookup extends LookupBase */ public static function lookup($lookupValue, $lookupArray, $indexNumber, $notExactMatch = true) { - if (is_array($lookupValue)) { + if (is_array($lookupValue) || is_array($indexNumber)) { return self::evaluateArrayArgumentsIgnore([self::class, __FUNCTION__], 1, $lookupValue, $lookupArray, $indexNumber, $notExactMatch); } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/MathTrig/Sum.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/MathTrig/Sum.php index 1a797c8a248..56b0861c6e5 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/MathTrig/Sum.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/MathTrig/Sum.php @@ -66,8 +66,8 @@ class Sum $returnValue += (int) $arg; } elseif (ErrorValue::isError($arg)) { return $arg; - // ignore non-numerics from cell, but fail as literals (except null) } elseif ($arg !== null && !Functions::isCellValue($k)) { + // ignore non-numerics from cell, but fail as literals (except null) return ExcelError::VALUE(); } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/TextData/Extract.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/TextData/Extract.php index 519607c0800..24ddff2ec5e 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/TextData/Extract.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/TextData/Extract.php @@ -261,7 +261,7 @@ class Extract $delimiter = Functions::flattenArray($delimiter); $quotedDelimiters = array_map( function ($delimiter) { - return preg_quote($delimiter ?? ''); + return preg_quote($delimiter ?? '', '/'); }, $delimiter ); @@ -270,7 +270,7 @@ class Extract return '(' . $delimiters . ')'; } - return '(' . preg_quote($delimiter ?? '') . ')'; + return '(' . preg_quote($delimiter ?? '', '/') . ')'; } private static function matchFlags(int $matchMode): string diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/TextData/Format.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/TextData/Format.php index 93e728202f2..57d33166371 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/TextData/Format.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/TextData/Format.php @@ -129,7 +129,7 @@ class Format $format = Helpers::extractString($format); if (!is_numeric($value) && Date::isDateTimeFormatCode($format)) { - $value = DateTimeExcel\DateValue::fromString($value); + $value = DateTimeExcel\DateValue::fromString($value) + DateTimeExcel\TimeValue::fromString($value); } return (string) NumberFormat::toFormattedString($value, $format); @@ -140,7 +140,7 @@ class Format * * @return mixed */ - private static function convertValue($value) + private static function convertValue($value, bool $spacesMeanZero = false) { $value = $value ?? 0; if (is_bool($value)) { @@ -150,6 +150,12 @@ class Format throw new CalcExp(ExcelError::VALUE()); } } + if (is_string($value)) { + $value = trim($value); + if ($spacesMeanZero && $value === '') { + $value = 0; + } + } return $value; } @@ -181,6 +187,9 @@ class Format '', trim($value, " \t\n\r\0\x0B" . StringHelper::getCurrencyCode()) ); + if ($numberValue === '') { + return ExcelError::VALUE(); + } if (is_numeric($numberValue)) { return (float) $numberValue; } @@ -277,7 +286,7 @@ class Format } try { - $value = self::convertValue($value); + $value = self::convertValue($value, true); $decimalSeparator = self::getDecimalSeparator($decimalSeparator); $groupSeparator = self::getGroupSeparator($groupSeparator); } catch (CalcExp $e) { @@ -285,12 +294,12 @@ class Format } if (!is_numeric($value)) { - $decimalPositions = preg_match_all('/' . preg_quote($decimalSeparator) . '/', $value, $matches, PREG_OFFSET_CAPTURE); + $decimalPositions = preg_match_all('/' . preg_quote($decimalSeparator, '/') . '/', $value, $matches, PREG_OFFSET_CAPTURE); if ($decimalPositions > 1) { return ExcelError::VALUE(); } - $decimalOffset = array_pop($matches[0])[1]; // @phpstan-ignore-line - if (strpos($value, $groupSeparator, $decimalOffset) !== false) { + $decimalOffset = array_pop($matches[0])[1] ?? null; + if ($decimalOffset === null || strpos($value, $groupSeparator, $decimalOffset) !== false) { return ExcelError::VALUE(); } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/TextData/Text.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/TextData/Text.php index 8e6a575a292..b8a730767cb 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/TextData/Text.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/TextData/Text.php @@ -193,7 +193,7 @@ class Text if (is_array($delimiter) && count($valueSet) > 1) { $quotedDelimiters = array_map( function ($delimiter) { - return preg_quote($delimiter ?? ''); + return preg_quote($delimiter ?? '', '/'); }, $valueSet ); @@ -202,7 +202,7 @@ class Text return '(' . $delimiters . ')'; } - return '(' . preg_quote(/** @scrutinizer ignore-type */ Functions::flattenSingleValue($delimiter)) . ')'; + return '(' . preg_quote(/** @scrutinizer ignore-type */ Functions::flattenSingleValue($delimiter), '/') . ')'; } private static function matchFlags(bool $matchMode): string diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php index 1bf73ba8294..c0fb3877532 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php @@ -51,8 +51,9 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder return $this->setImproperFraction($matches, $cell); } - $decimalSeparator = preg_quote(StringHelper::getDecimalSeparator()); - $thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator()); + $decimalSeparatorNoPreg = StringHelper::getDecimalSeparator(); + $decimalSeparator = preg_quote($decimalSeparatorNoPreg, '/'); + $thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator(), '/'); // Check for percentage if (preg_match('/^\-?\d*' . $decimalSeparator . '?\d*\s?\%$/', preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $value))) { @@ -64,7 +65,7 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder // Convert value to number $sign = ($matches['PrefixedSign'] ?? $matches['PrefixedSign2'] ?? $matches['PostfixedSign']) ?? null; $currencyCode = $matches['PrefixedCurrency'] ?? $matches['PostfixedCurrency']; - $value = (float) ($sign . trim(str_replace([$decimalSeparator, $currencyCode, ' ', '-'], ['.', '', '', ''], preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $value)))); // @phpstan-ignore-line + $value = (float) ($sign . trim(str_replace([$decimalSeparatorNoPreg, $currencyCode, ' ', '-'], ['.', '', '', ''], preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $value)))); // @phpstan-ignore-line return $this->setCurrency($value, $cell, $currencyCode); // @phpstan-ignore-line } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/Cell.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/Cell.php index a53294e53ef..e9e41d7c7bc 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/Cell.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/Cell.php @@ -71,6 +71,9 @@ class Cell */ private $formulaAttributes; + /** @var IgnoredErrors */ + private $ignoredErrors; + /** * Update the cell into the cell collection. * @@ -119,6 +122,7 @@ class Cell } elseif (self::getValueBinder()->bindValue($this, $value) === false) { throw new Exception('Value could not be bound to cell.'); } + $this->ignoredErrors = new IgnoredErrors(); } /** @@ -391,7 +395,9 @@ class Cell } throw new \PhpOffice\PhpSpreadsheet\Calculation\Exception( - $this->getWorksheet()->getTitle() . '!' . $this->getCoordinate() . ' -> ' . $ex->getMessage() + $this->getWorksheet()->getTitle() . '!' . $this->getCoordinate() . ' -> ' . $ex->getMessage(), + $ex->getCode(), + $ex ); } @@ -794,4 +800,9 @@ class Cell { return (string) $this->getValue(); } + + public function getIgnoredErrors(): IgnoredErrors + { + return $this->ignoredErrors; + } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/DataValidator.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/DataValidator.php index 0e395a7ff99..692f316ec00 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/DataValidator.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/DataValidator.php @@ -20,7 +20,7 @@ class DataValidator */ public function isValid(Cell $cell) { - if (!$cell->hasDataValidation()) { + if (!$cell->hasDataValidation() || $cell->getDataValidation()->getType() === DataValidation::TYPE_NONE) { return true; } @@ -31,13 +31,55 @@ class DataValidator return false; } - // TODO: write check on all cases - switch ($dataValidation->getType()) { - case DataValidation::TYPE_LIST: - return $this->isValueInList($cell); + $returnValue = false; + $type = $dataValidation->getType(); + if ($type === DataValidation::TYPE_LIST) { + $returnValue = $this->isValueInList($cell); + } elseif ($type === DataValidation::TYPE_WHOLE) { + if (!is_numeric($cellValue) || fmod((float) $cellValue, 1) != 0) { + $returnValue = false; + } else { + $returnValue = $this->numericOperator($dataValidation, (int) $cellValue); + } + } elseif ($type === DataValidation::TYPE_DECIMAL || $type === DataValidation::TYPE_DATE || $type === DataValidation::TYPE_TIME) { + if (!is_numeric($cellValue)) { + $returnValue = false; + } else { + $returnValue = $this->numericOperator($dataValidation, (float) $cellValue); + } + } elseif ($type === DataValidation::TYPE_TEXTLENGTH) { + $returnValue = $this->numericOperator($dataValidation, mb_strlen((string) $cellValue)); } - return false; + return $returnValue; + } + + /** @param float|int $cellValue */ + private function numericOperator(DataValidation $dataValidation, $cellValue): bool + { + $operator = $dataValidation->getOperator(); + $formula1 = $dataValidation->getFormula1(); + $formula2 = $dataValidation->getFormula2(); + $returnValue = false; + if ($operator === DataValidation::OPERATOR_BETWEEN) { + $returnValue = $cellValue >= $formula1 && $cellValue <= $formula2; + } elseif ($operator === DataValidation::OPERATOR_NOTBETWEEN) { + $returnValue = $cellValue < $formula1 || $cellValue > $formula2; + } elseif ($operator === DataValidation::OPERATOR_EQUAL) { + $returnValue = $cellValue == $formula1; + } elseif ($operator === DataValidation::OPERATOR_NOTEQUAL) { + $returnValue = $cellValue != $formula1; + } elseif ($operator === DataValidation::OPERATOR_LESSTHAN) { + $returnValue = $cellValue < $formula1; + } elseif ($operator === DataValidation::OPERATOR_LESSTHANOREQUAL) { + $returnValue = $cellValue <= $formula1; + } elseif ($operator === DataValidation::OPERATOR_GREATERTHAN) { + $returnValue = $cellValue > $formula1; + } elseif ($operator === DataValidation::OPERATOR_GREATERTHANOREQUAL) { + $returnValue = $cellValue >= $formula1; + } + + return $returnValue; } /** diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/IgnoredErrors.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/IgnoredErrors.php new file mode 100644 index 00000000000..ee4b5156207 --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/IgnoredErrors.php @@ -0,0 +1,66 @@ +numberStoredAsText = $value; + + return $this; + } + + public function getNumberStoredAsText(): bool + { + return $this->numberStoredAsText; + } + + public function setFormula(bool $value): self + { + $this->formula = $value; + + return $this; + } + + public function getFormula(): bool + { + return $this->formula; + } + + public function setTwoDigitTextYear(bool $value): self + { + $this->twoDigitTextYear = $value; + + return $this; + } + + public function getTwoDigitTextYear(): bool + { + return $this->twoDigitTextYear; + } + + public function setEvalError(bool $value): self + { + $this->evalError = $value; + + return $this; + } + + public function getEvalError(): bool + { + return $this->evalError; + } +} diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/CellReferenceHelper.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/CellReferenceHelper.php index 24694d5c62e..0e164543b48 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/CellReferenceHelper.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/CellReferenceHelper.php @@ -118,7 +118,7 @@ class CellReferenceHelper { $newColumn = Coordinate::stringFromColumnIndex(min($newColumnIndex + $this->numberOfColumns, AddressRange::MAX_COLUMN_INT)); - return $absoluteColumn . $newColumn; + return "{$absoluteColumn}{$newColumn}"; } protected function updateRowReference(int $newRowIndex, string $absoluteRow): string @@ -126,6 +126,6 @@ class CellReferenceHelper $newRow = $newRowIndex + $this->numberOfRows; $newRow = ($newRow > AddressRange::MAX_ROW) ? AddressRange::MAX_ROW : $newRow; - return $absoluteRow . (string) $newRow; + return "{$absoluteRow}{$newRow}"; } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Axis.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Axis.php index ade7b99d8ca..3d48134684f 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Axis.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Axis.php @@ -52,6 +52,9 @@ class Axis extends Properties /** @var string */ private $axisType = ''; + /** @var ?AxisText */ + private $axisText; + /** * Axis Options. * @@ -88,6 +91,9 @@ class Axis extends Properties Properties::FORMAT_CODE_DATE_ISO8601, ]; + /** @var bool */ + private $noFill = false; + /** * Get Series Data Type. * @@ -183,6 +189,14 @@ class Axis extends Properties */ public function getAxisOptionsProperty($property) { + if ($property === 'textRotation') { + if ($this->axisText !== null) { + if ($this->axisText->getRotation() !== null) { + return (string) $this->axisText->getRotation(); + } + } + } + return $this->axisOptions[$property]; } @@ -295,4 +309,28 @@ class Axis extends Properties return $this; } + + public function getAxisText(): ?AxisText + { + return $this->axisText; + } + + public function setAxisText(?AxisText $axisText): self + { + $this->axisText = $axisText; + + return $this; + } + + public function setNoFill(bool $noFill): self + { + $this->noFill = $noFill; + + return $this; + } + + public function getNoFill(): bool + { + return $this->noFill; + } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/AxisText.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/AxisText.php new file mode 100644 index 00000000000..cd9ba2ce292 --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/AxisText.php @@ -0,0 +1,56 @@ +font = new Font(); + $this->font->setSize(null, true); + } + + public function setRotation(?int $rotation): self + { + $this->rotation = $rotation; + + return $this; + } + + public function getRotation(): ?int + { + return $this->rotation; + } + + public function getFillColorObject(): ChartColor + { + $fillColor = $this->font->getChartColor(); + if ($fillColor === null) { + $fillColor = new ChartColor(); + $this->font->setChartColorFromObject($fillColor); + } + + return $fillColor; + } + + public function getFont(): Font + { + return $this->font; + } + + public function setFont(Font $font): self + { + $this->font = $font; + + return $this; + } +} diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Chart.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Chart.php index 2ff22a3440c..38c69a4636e 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Chart.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Chart.php @@ -150,6 +150,12 @@ class Chart /** @var bool */ private $roundedCorners = false; + /** @var GridLines */ + private $borderLines; + + /** @var ChartColor */ + private $fillColor; + /** * Create a new Chart. * majorGridlines and minorGridlines are deprecated, moved to Axis. @@ -176,6 +182,8 @@ class Chart if ($minorGridlines !== null) { $this->yAxis->setMinorGridlines($minorGridlines); } + $this->fillColor = new ChartColor(); + $this->borderLines = new GridLines(); } /** @@ -786,4 +794,21 @@ class Chart return $this; } + + public function getBorderLines(): GridLines + { + return $this->borderLines; + } + + public function setBorderLines(GridLines $borderLines): self + { + $this->borderLines = $borderLines; + + return $this; + } + + public function getFillColor(): ChartColor + { + return $this->fillColor; + } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Layout.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Layout.php index 0018d79d72c..ac36c25c9fe 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Layout.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Layout.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Chart; +use PhpOffice\PhpSpreadsheet\Style\Font; + class Layout { /** @@ -127,8 +129,11 @@ class Layout /** @var ?ChartColor */ private $labelBorderColor; - /** @var ?ChartColor */ - private $labelFontColor; + /** @var ?Font */ + private $labelFont; + + /** @var Properties */ + private $labelEffects; /** * Create a new Layout. @@ -172,7 +177,18 @@ class Layout $this->initBoolean($layout, 'numFmtLinked'); $this->initColor($layout, 'labelFillColor'); $this->initColor($layout, 'labelBorderColor'); - $this->initColor($layout, 'labelFontColor'); + $labelFont = $layout['labelFont'] ?? null; + if ($labelFont instanceof Font) { + $this->labelFont = $labelFont; + } + $labelFontColor = $layout['labelFontColor'] ?? null; + if ($labelFontColor instanceof ChartColor) { + $this->setLabelFontColor($labelFontColor); + } + $labelEffects = $layout['labelEffects'] ?? null; + if ($labelEffects instanceof Properties) { + $this->labelEffects = $labelEffects; + } } private function initBoolean(array $layout, string $name): void @@ -493,14 +509,32 @@ class Layout return $this; } + public function getLabelFont(): ?Font + { + return $this->labelFont; + } + + public function getLabelEffects(): ?Properties + { + return $this->labelEffects; + } + public function getLabelFontColor(): ?ChartColor { - return $this->labelFontColor; + if ($this->labelFont === null) { + return null; + } + + return $this->labelFont->getChartColor(); } public function setLabelFontColor(?ChartColor $chartColor): self { - $this->labelFontColor = $chartColor; + if ($this->labelFont === null) { + $this->labelFont = new Font(); + $this->labelFont->setSize(null, true); + } + $this->labelFont->setChartColorFromObject($chartColor); return $this; } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Legend.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Legend.php index edd87015af8..04040aed6a7 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Legend.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Legend.php @@ -48,6 +48,15 @@ class Legend */ private $layout; + /** @var GridLines */ + private $borderLines; + + /** @var ChartColor */ + private $fillColor; + + /** @var ?AxisText */ + private $legendText; + /** * Create a new Legend. * @@ -60,6 +69,13 @@ class Legend $this->setPosition($position); $this->layout = $layout; $this->setOverlay($overlay); + $this->borderLines = new GridLines(); + $this->fillColor = new ChartColor(); + } + + public function getFillColor(): ChartColor + { + return $this->fillColor; } /** @@ -148,4 +164,28 @@ class Legend { return $this->layout; } + + public function getLegendText(): ?AxisText + { + return $this->legendText; + } + + public function setLegendText(?AxisText $legendText): self + { + $this->legendText = $legendText; + + return $this; + } + + public function getBorderLines(): GridLines + { + return $this->borderLines; + } + + public function setBorderLines(GridLines $borderLines): self + { + $this->borderLines = $borderLines; + + return $this; + } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/PlotArea.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/PlotArea.php index ccde4bb2aab..2b78d9a4ebc 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/PlotArea.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/PlotArea.php @@ -163,4 +163,49 @@ class PlotArea { return $this->gradientFillStops; } + + /** @var ?int */ + private $gapWidth; + + /** @var bool */ + private $useUpBars = false; + + /** @var bool */ + private $useDownBars = false; + + public function getGapWidth(): ?int + { + return $this->gapWidth; + } + + public function setGapWidth(?int $gapWidth): self + { + $this->gapWidth = $gapWidth; + + return $this; + } + + public function getUseUpBars(): bool + { + return $this->useUpBars; + } + + public function setUseUpBars(bool $useUpBars): self + { + $this->useUpBars = $useUpBars; + + return $this; + } + + public function getUseDownBars(): bool + { + return $this->useDownBars; + } + + public function setUseDownBars(bool $useDownBars): self + { + $this->useDownBars = $useDownBars; + + return $this; + } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/JpGraphRendererBase.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/JpGraphRendererBase.php index cb9b544b816..d676f1d33b6 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/JpGraphRendererBase.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/JpGraphRendererBase.php @@ -434,12 +434,33 @@ abstract class JpGraphRendererBase implements IRenderer // Loop through each data series in turn for ($i = 0; $i < $seriesCount; ++$i) { - $dataValuesY = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues(); + $plotCategoryByIndex = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i); + if ($plotCategoryByIndex === false) { + $plotCategoryByIndex = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0); + } + $dataValuesY = $plotCategoryByIndex->getDataValues(); $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues(); - foreach ($dataValuesY as $k => $dataValueY) { - $dataValuesY[$k] = $k; + $redoDataValuesY = true; + if ($bubble) { + if (!$bubbleSize) { + $bubbleSize = '10'; + } + $redoDataValuesY = false; + foreach ($dataValuesY as $dataValueY) { + if (!is_int($dataValueY) && !is_float($dataValueY)) { + $redoDataValuesY = true; + + break; + } + } } + if ($redoDataValuesY) { + foreach ($dataValuesY as $k => $dataValueY) { + $dataValuesY[$k] = $k; + } + } + //var_dump($dataValuesY, $dataValuesX, $bubbleSize); $seriesPlot = new ScatterPlot($dataValuesX, $dataValuesY); if ($scatterStyle == 'lineMarker') { @@ -483,7 +504,7 @@ abstract class JpGraphRendererBase implements IRenderer $dataValues = []; foreach ($dataValuesY as $k => $dataValueY) { - $dataValues[$k] = implode(' ', array_reverse($dataValueY)); + $dataValues[$k] = is_array($dataValueY) ? implode(' ', array_reverse($dataValueY)) : $dataValueY; } $tmp = array_shift($dataValues); $dataValues[] = $tmp; diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/MtJpGraphRenderer.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/MtJpGraphRenderer.php index e1f0f90addd..b5e70d3a196 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/MtJpGraphRenderer.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/MtJpGraphRenderer.php @@ -3,12 +3,12 @@ namespace PhpOffice\PhpSpreadsheet\Chart\Renderer; /** - * Jpgraph is not oficially maintained in Composer. + * Jpgraph is not officially maintained by Composer at packagist.org. * * This renderer implementation uses package * https://packagist.org/packages/mitoteam/jpgraph * - * This package is up to date for August 2022 and has PHP 8.1 support. + * This package is up to date for June 2023 and has PHP 8.2 support. */ class MtJpGraphRenderer extends JpGraphRendererBase { @@ -29,7 +29,7 @@ class MtJpGraphRenderer extends JpGraphRendererBase 'regstat', 'scatter', 'stock', - ]); + ], true); // enable Extended mode $loaded = true; } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Document/Properties.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Document/Properties.php index afdeea99624..302afee79ea 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Document/Properties.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Document/Properties.php @@ -107,6 +107,8 @@ class Properties */ private $customProperties = []; + private string $hyperlinkBase = ''; + /** * Create a new Document Properties instance. */ @@ -434,7 +436,7 @@ class Properties * * @param mixed $propertyValue * @param string $propertyType - * 'i' : Integer + * 'i' : Integer * 'f' : Floating Point * 's' : String * 'd' : Date/Time @@ -534,4 +536,16 @@ class Properties { return self::PROPERTY_TYPE_ARRAY[$propertyType] ?? self::PROPERTY_TYPE_UNKNOWN; } + + public function getHyperlinkBase(): string + { + return $this->hyperlinkBase; + } + + public function setHyperlinkBase(string $hyperlinkBase): self + { + $this->hyperlinkBase = $hyperlinkBase; + + return $this; + } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/Downloader.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/Downloader.php new file mode 100644 index 00000000000..e66ae42584f --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/Downloader.php @@ -0,0 +1,89 @@ + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xls' => 'application/vnd.ms-excel', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'csv' => 'text/csv', + 'html' => 'text/html', + 'pdf' => 'application/pdf', + ]; + + public function __construct(string $folder, string $filename, ?string $filetype = null) + { + if ((is_dir($folder) === false) || (is_readable($folder) === false)) { + throw new Exception("Folder {$folder} is not accessable"); + } + $filepath = "{$folder}/{$filename}"; + $this->filepath = (string) realpath($filepath); + $this->filename = basename($filepath); + if ((file_exists($this->filepath) === false) || (is_readable($this->filepath) === false)) { + throw new Exception("{$this->filename} not found, or cannot be read"); + } + + $filetype ??= pathinfo($filename, PATHINFO_EXTENSION); + if (array_key_exists(strtolower($filetype), self::CONTENT_TYPES) === false) { + throw new Exception("Invalid filetype: {$filetype} cannot be downloaded"); + } + $this->filetype = strtolower($filetype); + } + + public function download(): void + { + $this->headers(); + + readfile($this->filepath); + } + + public function headers(): void + { + ob_clean(); + + $this->contentType(); + $this->contentDisposition(); + $this->cacheHeaders(); + $this->fileSize(); + + flush(); + } + + protected function contentType(): void + { + header('Content-Type: ' . self::CONTENT_TYPES[$this->filetype]); + } + + protected function contentDisposition(): void + { + header('Content-Disposition: attachment;filename="' . $this->filename . '"'); + } + + protected function cacheHeaders(): void + { + header('Cache-Control: max-age=0'); + // If you're serving to IE 9, then the following may be needed + header('Cache-Control: max-age=1'); + + // If you're serving to IE over SSL, then the following may be needed + header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past + header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified + header('Cache-Control: cache, must-revalidate'); // HTTP/1.1 + header('Pragma: public'); // HTTP/1.0 + } + + protected function fileSize(): void + { + header('Content-Length: ' . filesize($this->filepath)); + } +} diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/Handler.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/Handler.php new file mode 100644 index 00000000000..d05197cef0f --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/Handler.php @@ -0,0 +1,46 @@ +attributes; if ($attrs !== null) { @@ -737,72 +737,72 @@ class Html } } - private function endFontTag(): void + protected function endFontTag(): void { $this->face = $this->size = $this->color = null; } - private function startBoldTag(): void + protected function startBoldTag(): void { $this->bold = true; } - private function endBoldTag(): void + protected function endBoldTag(): void { $this->bold = false; } - private function startItalicTag(): void + protected function startItalicTag(): void { $this->italic = true; } - private function endItalicTag(): void + protected function endItalicTag(): void { $this->italic = false; } - private function startUnderlineTag(): void + protected function startUnderlineTag(): void { $this->underline = true; } - private function endUnderlineTag(): void + protected function endUnderlineTag(): void { $this->underline = false; } - private function startSubscriptTag(): void + protected function startSubscriptTag(): void { $this->subscript = true; } - private function endSubscriptTag(): void + protected function endSubscriptTag(): void { $this->subscript = false; } - private function startSuperscriptTag(): void + protected function startSuperscriptTag(): void { $this->superscript = true; } - private function endSuperscriptTag(): void + protected function endSuperscriptTag(): void { $this->superscript = false; } - private function startStrikethruTag(): void + protected function startStrikethruTag(): void { $this->strikethrough = true; } - private function endStrikethruTag(): void + protected function endStrikethruTag(): void { $this->strikethrough = false; } - private function breakTag(): void + protected function breakTag(): void { $this->stringData .= "\n"; } @@ -826,8 +826,9 @@ class Html if (isset($callbacks[$callbackTag])) { $elementHandler = $callbacks[$callbackTag]; if (method_exists($this, $elementHandler)) { - /** @phpstan-ignore-next-line */ - call_user_func([$this, $elementHandler], $element); + /** @var callable */ + $callable = [$this, $elementHandler]; + call_user_func($callable, $element); } } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/Sample.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/Sample.php index 5ca546e0770..6244375fe36 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/Sample.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/Sample.php @@ -2,7 +2,9 @@ namespace PhpOffice\PhpSpreadsheet\Helper; +use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\IOFactory; +use PhpOffice\PhpSpreadsheet\Settings; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use PhpOffice\PhpSpreadsheet\Writer\IWriter; @@ -12,6 +14,7 @@ use RecursiveRegexIterator; use ReflectionClass; use RegexIterator; use RuntimeException; +use Throwable; /** * Helper class to be used in sample code. @@ -120,7 +123,7 @@ class Sample * @param string $filename * @param string[] $writers */ - public function write(Spreadsheet $spreadsheet, $filename, array $writers = ['Xlsx', 'Xls']): void + public function write(Spreadsheet $spreadsheet, $filename, array $writers = ['Xlsx', 'Xls'], bool $withCharts = false, ?callable $writerCallback = null): void { // Set active sheet index to the first sheet, so Excel opens this as the first sheet $spreadsheet->setActiveSheetIndex(0); @@ -129,9 +132,16 @@ class Sample foreach ($writers as $writerType) { $path = $this->getFilename($filename, mb_strtolower($writerType)); $writer = IOFactory::createWriter($spreadsheet, $writerType); + $writer->setIncludeCharts($withCharts); + if ($writerCallback !== null) { + $writerCallback($writer); + } $callStartTime = microtime(true); $writer->save($path); $this->logWrite($writer, $path, /** @scrutinizer ignore-type */ $callStartTime); + if ($this->isCli() === false) { + echo 'Download ' . basename($path) . '
'; + } } $this->logEndingNotes(); @@ -147,7 +157,7 @@ class Sample * * @return string */ - private function getTemporaryFolder() + public function getTemporaryFolder() { $tempFolder = sys_get_temp_dir() . '/phpspreadsheet'; if (!$this->isDirOrMkdir($tempFolder)) { @@ -162,10 +172,8 @@ class Sample * * @param string $filename * @param string $extension - * - * @return string */ - public function getFilename($filename, $extension = 'xlsx') + public function getFilename($filename, $extension = 'xlsx'): string { $originalExtension = pathinfo($filename, PATHINFO_EXTENSION); @@ -195,7 +203,29 @@ class Sample public function log(string $message): void { $eol = $this->isCli() ? PHP_EOL : '
'; - echo date('H:i:s ') . $message . $eol; + echo($this->isCli() ? date('H:i:s ') : '') . $message . $eol; + } + + public function renderChart(Chart $chart, string $fileName): void + { + if ($this->isCli() === true) { + return; + } + + Settings::setChartRenderer(\PhpOffice\PhpSpreadsheet\Chart\Renderer\MtJpGraphRenderer::class); + + $fileName = $this->getFilename($fileName, 'png'); + + try { + $chart->render($fileName); + $this->log('Rendered image: ' . $fileName); + $imageData = file_get_contents($fileName); + if ($imageData !== false) { + echo '
'; + } + } catch (Throwable $e) { + $this->log('Error rendering chart: ' . $e->getMessage() . PHP_EOL); + } } public function titles(string $category, string $functionName, ?string $description = null): void @@ -246,7 +276,10 @@ class Sample $callTime = $callEndTime - $callStartTime; $reflection = new ReflectionClass($writer); $format = $reflection->getShortName(); - $message = "Write {$format} format to {$path} in " . sprintf('%.4f', $callTime) . ' seconds'; + + $message = ($this->isCli() === true) + ? "Write {$format} format to {$path} in " . sprintf('%.4f', $callTime) . ' seconds' + : "Write {$format} format to {$path} in " . sprintf('%.4f', $callTime) . ' seconds'; $this->log($message); } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/TextGrid.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/TextGrid.php index ed146a55d8a..3a4a98f0224 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/TextGrid.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Helper/TextGrid.php @@ -48,17 +48,17 @@ class TextGrid public function render(): string { - $this->gridDisplay = $this->isCli ? '' : ''; + $this->gridDisplay = $this->isCli ? '' : '
';
 
         $maxRow = max($this->rows);
-        $maxRowLength = strlen((string) $maxRow) + 1;
+        $maxRowLength = mb_strlen((string) $maxRow) + 1;
         $columnWidths = $this->getColumnWidths();
 
         $this->renderColumnHeader($maxRowLength, $columnWidths);
         $this->renderRows($maxRowLength, $columnWidths);
         $this->renderFooter($maxRowLength, $columnWidths);
 
-        $this->gridDisplay .= $this->isCli ? '' : '';
+        $this->gridDisplay .= $this->isCli ? '' : '
'; return $this->gridDisplay; } @@ -75,9 +75,9 @@ class TextGrid private function renderCells(array $rowData, array $columnWidths): void { foreach ($rowData as $column => $cell) { - $cell = ($this->isCli) ? (string) $cell : htmlentities((string) $cell); + $displayCell = ($this->isCli) ? (string) $cell : htmlentities((string) $cell); $this->gridDisplay .= '| '; - $this->gridDisplay .= str_pad($cell, $columnWidths[$column] + 1, ' '); + $this->gridDisplay .= $displayCell . str_repeat(' ', $columnWidths[$column] - mb_strlen($cell ?? '') + 1); } } @@ -126,12 +126,12 @@ class TextGrid foreach ($columnData as $columnValue) { if (is_string($columnValue)) { - $columnWidth = max($columnWidth, strlen($columnValue)); + $columnWidth = max($columnWidth, mb_strlen($columnValue)); } elseif (is_bool($columnValue)) { - $columnWidth = max($columnWidth, strlen($columnValue ? 'TRUE' : 'FALSE')); + $columnWidth = max($columnWidth, mb_strlen($columnValue ? 'TRUE' : 'FALSE')); } - $columnWidth = max($columnWidth, strlen((string) $columnWidth)); + $columnWidth = max($columnWidth, mb_strlen((string) $columnWidth)); } return $columnWidth; diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Gnumeric.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Gnumeric.php index 17455322574..99e4d6ad6c6 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Gnumeric.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Gnumeric.php @@ -80,17 +80,15 @@ class Gnumeric extends BaseReader */ public function canRead(string $filename): bool { - // Check if gzlib functions are available - if (File::testFileNoThrow($filename) && function_exists('gzread')) { - // Read signature data (first 3 bytes) - $fh = fopen($filename, 'rb'); - if ($fh !== false) { - $data = fread($fh, 2); - fclose($fh); + $data = null; + if (File::testFileNoThrow($filename)) { + $data = $this->gzfileGetContents($filename); + if (strpos($data, self::NAMESPACE_GNM) === false) { + $data = ''; } } - return isset($data) && $data === chr(0x1F) . chr(0x8B); + return !empty($data); } private static function matchXml(XMLReader $xml, string $expectedLocalName): bool @@ -110,9 +108,13 @@ class Gnumeric extends BaseReader public function listWorksheetNames($filename) { File::assertFile($filename); + if (!$this->canRead($filename)) { + throw new Exception($filename . ' is an invalid Gnumeric file.'); + } $xml = new XMLReader(); - $xml->xml($this->getSecurityScannerOrThrow()->scanFile('compress.zlib://' . realpath($filename)), null, Settings::getLibXmlLoaderOptions()); + $contents = $this->gzfileGetContents($filename); + $xml->xml($contents, null, Settings::getLibXmlLoaderOptions()); $xml->setParserProperty(2, true); $worksheetNames = []; @@ -139,9 +141,13 @@ class Gnumeric extends BaseReader public function listWorksheetInfo($filename) { File::assertFile($filename); + if (!$this->canRead($filename)) { + throw new Exception($filename . ' is an invalid Gnumeric file.'); + } $xml = new XMLReader(); - $xml->xml($this->getSecurityScannerOrThrow()->scanFile('compress.zlib://' . realpath($filename)), null, Settings::getLibXmlLoaderOptions()); + $contents = $this->gzfileGetContents($filename); + $xml->xml($contents, null, Settings::getLibXmlLoaderOptions()); $xml->setParserProperty(2, true); $worksheetInfo = []; @@ -185,13 +191,23 @@ class Gnumeric extends BaseReader */ private function gzfileGetContents($filename) { - $file = @gzopen($filename, 'rb'); $data = ''; - if ($file !== false) { - while (!gzeof($file)) { - $data .= gzread($file, 1024); + $contents = @file_get_contents($filename); + if ($contents !== false) { + if (substr($contents, 0, 2) === "\x1f\x8b") { + // Check if gzlib functions are available + if (function_exists('gzdecode')) { + $contents = @gzdecode($contents); + if ($contents !== false) { + $data = $contents; + } + } + } else { + $data = $contents; } - gzclose($file); + } + if ($data !== '') { + $data = $this->getSecurityScannerOrThrow()->scan($data); } return $data; @@ -245,10 +261,13 @@ class Gnumeric extends BaseReader { $this->spreadsheet = $spreadsheet; File::assertFile($filename); + if (!$this->canRead($filename)) { + throw new Exception($filename . ' is an invalid Gnumeric file.'); + } $gFileData = $this->gzfileGetContents($filename); - $xml2 = simplexml_load_string($this->getSecurityScannerOrThrow()->scan($gFileData), 'SimpleXMLElement', Settings::getLibXmlLoaderOptions()); + $xml2 = simplexml_load_string($gFileData, 'SimpleXMLElement', Settings::getLibXmlLoaderOptions()); $xml = self::testSimpleXml($xml2); $gnmXML = $xml->children(self::NAMESPACE_GNM); diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Html.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Html.php index b165b6c17e0..bfb52401aa0 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Html.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Html.php @@ -7,6 +7,8 @@ use DOMElement; use DOMNode; use DOMText; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; +use PhpOffice\PhpSpreadsheet\Cell\DataType; +use PhpOffice\PhpSpreadsheet\Document\Properties; use PhpOffice\PhpSpreadsheet\Helper\Dimension as CssDimension; use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner; use PhpOffice\PhpSpreadsheet\Spreadsheet; @@ -283,15 +285,35 @@ class Html extends BaseReader * @param int|string $row * @param mixed $cellContent */ - protected function flushCell(Worksheet $sheet, $column, $row, &$cellContent): void + protected function flushCell(Worksheet $sheet, $column, $row, &$cellContent, array $attributeArray): void { if (is_string($cellContent)) { // Simple String content if (trim($cellContent) > '') { // Only actually write it if there's content in the string // Write to worksheet to be done here... - // ... we return the cell so we can mess about with styles more easily - $sheet->setCellValue($column . $row, $cellContent); + // ... we return the cell, so we can mess about with styles more easily + + // Set cell value explicitly if there is data-type attribute + if (isset($attributeArray['data-type'])) { + $datatype = $attributeArray['data-type']; + if (in_array($datatype, [DataType::TYPE_STRING, DataType::TYPE_STRING2, DataType::TYPE_INLINE])) { + //Prevent to Excel treat string with beginning equal sign or convert big numbers to scientific number + if (substr($cellContent, 0, 1) === '=') { + $sheet->getCell($column . $row) + ->getStyle() + ->setQuotePrefix(true); + } + } + //catching the Exception and ignoring the invalid data types + try { + $sheet->setCellValueExplicit($column . $row, $cellContent, $attributeArray['data-type']); + } catch (\PhpOffice\PhpSpreadsheet\Exception $exception) { + $sheet->setCellValue($column . $row, $cellContent); + } + } else { + $sheet->setCellValue($column . $row, $cellContent); + } $this->dataArray[$row][$column] = $cellContent; } } else { @@ -305,7 +327,7 @@ class Html extends BaseReader private function processDomElementBody(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child): void { $attributeArray = []; - foreach (($child->attributes ?? []) as $attribute) { + foreach ($child->attributes as $attribute) { $attributeArray[$attribute->name] = $attribute->value; } @@ -355,7 +377,7 @@ class Html extends BaseReader private function processDomElementHr(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { if ($child->nodeName === 'hr') { - $this->flushCell($sheet, $column, $row, $cellContent); + $this->flushCell($sheet, $column, $row, $cellContent, $attributeArray); ++$row; if (isset($this->formats[$child->nodeName])) { $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]); @@ -375,7 +397,7 @@ class Html extends BaseReader $sheet->getStyle($column . $row)->getAlignment()->setWrapText(true); } else { // Otherwise flush our existing content and move the row cursor on - $this->flushCell($sheet, $column, $row, $cellContent); + $this->flushCell($sheet, $column, $row, $cellContent, $attributeArray); ++$row; } } else { @@ -421,11 +443,11 @@ class Html extends BaseReader $this->processDomElement($child, $sheet, $row, $column, $cellContent); } else { if ($cellContent > '') { - $this->flushCell($sheet, $column, $row, $cellContent); + $this->flushCell($sheet, $column, $row, $cellContent, $attributeArray); ++$row; } $this->processDomElement($child, $sheet, $row, $column, $cellContent); - $this->flushCell($sheet, $column, $row, $cellContent); + $this->flushCell($sheet, $column, $row, $cellContent, $attributeArray); if (isset($this->formats[$child->nodeName])) { $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]); @@ -448,11 +470,11 @@ class Html extends BaseReader $this->processDomElement($child, $sheet, $row, $column, $cellContent); } else { if ($cellContent > '') { - $this->flushCell($sheet, $column, $row, $cellContent); + $this->flushCell($sheet, $column, $row, $cellContent, $attributeArray); } ++$row; $this->processDomElement($child, $sheet, $row, $column, $cellContent); - $this->flushCell($sheet, $column, $row, $cellContent); + $this->flushCell($sheet, $column, $row, $cellContent, $attributeArray); $column = 'A'; } } else { @@ -469,10 +491,13 @@ class Html extends BaseReader } } + private string $currentColumn = 'A'; + private function processDomElementTable(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { if ($child->nodeName === 'table') { - $this->flushCell($sheet, $column, $row, $cellContent); + $this->currentColumn = 'A'; + $this->flushCell($sheet, $column, $row, $cellContent, $attributeArray); $column = $this->setTableStartColumn($column); if ($this->tableLevel > 1 && $row > 1) { --$row; @@ -491,7 +516,10 @@ class Html extends BaseReader private function processDomElementTr(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { - if ($child->nodeName === 'tr') { + if ($child->nodeName === 'col') { + $this->applyInlineStyle($sheet, -1, $this->currentColumn, $attributeArray); + ++$this->currentColumn; + } elseif ($child->nodeName === 'tr') { $column = $this->getTableStartColumn(); $cellContent = ''; $this->processDomElement($child, $sheet, $row, $column, $cellContent); @@ -574,7 +602,7 @@ class Html extends BaseReader // apply inline style $this->applyInlineStyle($sheet, $row, $column, $attributeArray); - $this->flushCell($sheet, $column, $row, $cellContent); + $this->flushCell($sheet, $column, $row, $cellContent, $attributeArray); $this->processDomElementBgcolor($sheet, $row, $column, $attributeArray); $this->processDomElementWidth($sheet, $column, $attributeArray); @@ -664,10 +692,94 @@ class Html extends BaseReader if ($loaded === false) { throw new Exception('Failed to load ' . $filename . ' as a DOM Document', 0, $e ?? null); } + self::loadProperties($dom, $spreadsheet); return $this->loadDocument($dom, $spreadsheet); } + private static function loadProperties(DOMDocument $dom, Spreadsheet $spreadsheet): void + { + $properties = $spreadsheet->getProperties(); + foreach ($dom->getElementsByTagName('meta') as $meta) { + $metaContent = (string) $meta->getAttribute('content'); + if ($metaContent !== '') { + $metaName = (string) $meta->getAttribute('name'); + switch ($metaName) { + case 'author': + $properties->setCreator($metaContent); + + break; + case 'category': + $properties->setCategory($metaContent); + + break; + case 'company': + $properties->setCompany($metaContent); + + break; + case 'created': + $properties->setCreated($metaContent); + + break; + case 'description': + $properties->setDescription($metaContent); + + break; + case 'keywords': + $properties->setKeywords($metaContent); + + break; + case 'lastModifiedBy': + $properties->setLastModifiedBy($metaContent); + + break; + case 'manager': + $properties->setManager($metaContent); + + break; + case 'modified': + $properties->setModified($metaContent); + + break; + case 'subject': + $properties->setSubject($metaContent); + + break; + case 'title': + $properties->setTitle($metaContent); + + break; + default: + if (preg_match('/^custom[.](bool|date|float|int|string)[.](.+)$/', $metaName, $matches) === 1) { + switch ($matches[1]) { + case 'bool': + $properties->setCustomProperty($matches[2], (bool) $metaContent, Properties::PROPERTY_TYPE_BOOLEAN); + + break; + case 'float': + $properties->setCustomProperty($matches[2], (float) $metaContent, Properties::PROPERTY_TYPE_FLOAT); + + break; + case 'int': + $properties->setCustomProperty($matches[2], (int) $metaContent, Properties::PROPERTY_TYPE_INTEGER); + + break; + case 'date': + $properties->setCustomProperty($matches[2], $metaContent, Properties::PROPERTY_TYPE_DATE); + + break; + default: // string + $properties->setCustomProperty($matches[2], $metaContent, Properties::PROPERTY_TYPE_STRING); + } + } + } + } + } + if (!empty($dom->baseURI)) { + $properties->setHyperlinkBase($dom->baseURI); + } + } + private static function replaceNonAscii(array $matches): string { return '&#' . mb_ord($matches[0], 'UTF-8') . ';'; @@ -698,8 +810,10 @@ class Html extends BaseReader if ($loaded === false) { throw new Exception('Failed to load content as a DOM Document', 0, $e ?? null); } + $spreadsheet = $spreadsheet ?? new Spreadsheet(); + self::loadProperties($dom, $spreadsheet); - return $this->loadDocument($dom, $spreadsheet ?? new Spreadsheet()); + return $this->loadDocument($dom, $spreadsheet); } /** @@ -769,7 +883,9 @@ class Html extends BaseReader return; } - if (isset($attributeArray['rowspan'], $attributeArray['colspan'])) { + if ($row <= 0 || $column === '') { + $cellStyle = new Style(); + } elseif (isset($attributeArray['rowspan'], $attributeArray['colspan'])) { $columnTo = $column; for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) { ++$columnTo; @@ -901,16 +1017,20 @@ class Html extends BaseReader break; case 'width': - $sheet->getColumnDimension($column)->setWidth( - (new CssDimension($styleValue ?? ''))->width() - ); + if ($column !== '') { + $sheet->getColumnDimension($column)->setWidth( + (new CssDimension($styleValue ?? ''))->width() + ); + } break; case 'height': - $sheet->getRowDimension($row)->setRowHeight( - (new CssDimension($styleValue ?? ''))->height() - ); + if ($row > 0) { + $sheet->getRowDimension($row)->setRowHeight( + (new CssDimension($styleValue ?? ''))->height() + ); + } break; diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Ods.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Ods.php index 25081540079..9913f332520 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Ods.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Ods.php @@ -8,6 +8,7 @@ use DOMElement; use DOMNode; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Cell\DataType; +use PhpOffice\PhpSpreadsheet\Helper\Dimension as HelperDimension; use PhpOffice\PhpSpreadsheet\Reader\Ods\AutoFilter; use PhpOffice\PhpSpreadsheet\Reader\Ods\DefinedNames; use PhpOffice\PhpSpreadsheet\Reader\Ods\FormulaTranslator; @@ -295,11 +296,29 @@ class Ods extends BaseReader $tableNs = $dom->lookupNamespaceUri('table'); $textNs = $dom->lookupNamespaceUri('text'); $xlinkNs = $dom->lookupNamespaceUri('xlink'); + $styleNs = $dom->lookupNamespaceUri('style'); $pageSettings->readStyleCrossReferences($dom); $autoFilterReader = new AutoFilter($spreadsheet, $tableNs); $definedNameReader = new DefinedNames($spreadsheet, $tableNs); + $columnWidths = []; + $automaticStyle0 = $dom->getElementsByTagNameNS($officeNs, 'automatic-styles')->item(0); + $automaticStyles = ($automaticStyle0 === null) ? [] : $automaticStyle0->getElementsByTagNameNS($styleNs, 'style'); + foreach ($automaticStyles as $automaticStyle) { + $styleName = $automaticStyle->getAttributeNS($styleNs, 'name'); + $styleFamily = $automaticStyle->getAttributeNS($styleNs, 'family'); + if ($styleFamily === 'table-column') { + $tcprops = $automaticStyle->getElementsByTagNameNS($styleNs, 'table-column-properties'); + if ($tcprops !== null) { + $tcprop = $tcprops->item(0); + if ($tcprop !== null) { + $columnWidth = $tcprop->getAttributeNs($styleNs, 'column-width'); + $columnWidths[$styleName] = $columnWidth; + } + } + } + } // Content $item0 = $dom->getElementsByTagNameNS($officeNs, 'body')->item(0); @@ -340,6 +359,7 @@ class Ods extends BaseReader // Go through every child of table element $rowID = 1; + $tableColumnIndex = 1; foreach ($worksheetDataSet->childNodes as $childNode) { /** @var DOMElement $childNode */ @@ -366,6 +386,26 @@ class Ods extends BaseReader // $rowData = $cellData; // break; // } + break; + case 'table-column': + if ($childNode->hasAttributeNS($tableNs, 'number-columns-repeated')) { + $rowRepeats = (int) $childNode->getAttributeNS($tableNs, 'number-columns-repeated'); + } else { + $rowRepeats = 1; + } + $tableStyleName = $childNode->getAttributeNS($tableNs, 'style-name'); + if (isset($columnWidths[$tableStyleName])) { + $columnWidth = new HelperDimension($columnWidths[$tableStyleName]); + $tableColumnString = Coordinate::stringFromColumnIndex($tableColumnIndex); + for ($rowRepeats2 = $rowRepeats; $rowRepeats2 > 0; --$rowRepeats2) { + $spreadsheet->getActiveSheet() + ->getColumnDimension($tableColumnString) + ->setWidth($columnWidth->toUnit('cm'), 'cm'); + ++$tableColumnString; + } + } + $tableColumnIndex += $rowRepeats; + break; case 'table-row': if ($childNode->hasAttributeNS($tableNs, 'number-rows-repeated')) { diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Security/XmlScanner.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Security/XmlScanner.php index ad898ae410f..f8eaf39d096 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Security/XmlScanner.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Security/XmlScanner.php @@ -151,7 +151,7 @@ class XmlScanner throw new Reader\Exception('Detected use of ENTITY in XML, spreadsheet file load() aborted to prevent XXE/XEE attacks'); } - if ($this->callback !== null && is_callable($this->callback)) { + if ($this->callback !== null) { $xml = call_user_func($this->callback, $xml); } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php index bf89084706b..1c33fd6811d 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php @@ -16,6 +16,7 @@ use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Hyperlinks; use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Namespaces; use PhpOffice\PhpSpreadsheet\Reader\Xlsx\PageSetup; use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Properties as PropertyReader; +use PhpOffice\PhpSpreadsheet\Reader\Xlsx\SharedFormula; use PhpOffice\PhpSpreadsheet\Reader\Xlsx\SheetViewOptions; use PhpOffice\PhpSpreadsheet\Reader\Xlsx\SheetViews; use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Styles; @@ -61,6 +62,11 @@ class Xlsx extends BaseReader /** @var Styles */ private $styleReader; + /** + * @var array + */ + private $sharedFormulae = []; + /** * Create a new Xlsx Reader instance. */ @@ -128,7 +134,7 @@ class Xlsx extends BaseReader if ($replaceUnclosedBr) { $contents = str_replace('
', '
', $contents); } - $rels = simplexml_load_string( + $rels = @simplexml_load_string( $this->getSecurityScannerOrThrow()->scan($contents), 'SimpleXMLElement', Settings::getLibXmlLoaderOptions(), @@ -246,6 +252,7 @@ class Xlsx extends BaseReader $xmlWorkbook = $this->loadZip($relTarget, $mainNS); if ($xmlWorkbook->sheets) { $dir = dirname($relTarget); + /** @var SimpleXMLElement $eleSheet */ foreach ($xmlWorkbook->sheets->sheet as $eleSheet) { $tmpInfo = [ @@ -261,8 +268,8 @@ class Xlsx extends BaseReader $xml = new XMLReader(); $xml->xml( - $this->getSecurityScannerOrThrow()->scanFile( - 'zip://' . File::realpath($filename) . '#' . $fileWorksheetPath + $this->getSecurityScannerOrThrow()->scan( + $this->getFromZipArchive($this->zip, $fileWorksheetPath) ), null, Settings::getLibXmlLoaderOptions() @@ -324,13 +331,13 @@ class Xlsx extends BaseReader * @param mixed $value * @param mixed $calculatedValue */ - private function castToFormula(?SimpleXMLElement $c, string $r, string &$cellDataType, &$value, &$calculatedValue, array &$sharedFormulas, string $castBaseType): void + private function castToFormula(?SimpleXMLElement $c, string $r, string &$cellDataType, &$value, &$calculatedValue, string $castBaseType, bool $updateSharedCells = true): void { if ($c === null) { return; } $attr = $c->f->attributes(); - $cellDataType = 'f'; + $cellDataType = DataType::TYPE_FORMULA; $value = "={$c->f}"; $calculatedValue = self::$castBaseType($c); @@ -338,17 +345,19 @@ class Xlsx extends BaseReader if (isset($attr['t']) && strtolower((string) $attr['t']) == 'shared') { $instance = (string) $attr['si']; - if (!isset($sharedFormulas[(string) $attr['si']])) { - $sharedFormulas[$instance] = ['master' => $r, 'formula' => $value]; - } else { - $master = Coordinate::indexesFromString($sharedFormulas[$instance]['master']); + if (!isset($this->sharedFormulae[(string) $attr['si']])) { + $this->sharedFormulae[$instance] = new SharedFormula($r, $value); + } elseif ($updateSharedCells === true) { + // It's only worth the overhead of adjusting the shared formula for this cell if we're actually loading + // the cell, which may not be the case if we're using a read filter. + $master = Coordinate::indexesFromString($this->sharedFormulae[$instance]->master()); $current = Coordinate::indexesFromString($r); $difference = [0, 0]; $difference[0] = $current[0] - $master[0]; $difference[1] = $current[1] - $master[1]; - $value = $this->referenceHelper->updateFormulaReferences($sharedFormulas[$instance]['formula'], 'A1', $difference[0], $difference[1]); + $value = $this->referenceHelper->updateFormulaReferences($this->sharedFormulae[$instance]->formula(), 'A1', $difference[0], $difference[1]); } } } @@ -395,12 +404,18 @@ class Xlsx extends BaseReader // Sadly, some 3rd party xlsx generators don't use consistent case for filenaming // so we need to load case-insensitively from the zip file - // Apache POI fixes $contents = $archive->getFromName($fileName, 0, ZipArchive::FL_NOCASE); + + // Apache POI fixes if ($contents === false) { $contents = $archive->getFromName(substr($fileName, 1), 0, ZipArchive::FL_NOCASE); } + // Has the file been saved with Windoze directory separators rather than unix? + if ($contents === false) { + $contents = $archive->getFromName(str_replace('/', '\\', $fileName), 0, ZipArchive::FL_NOCASE); + } + return ($contents === false) ? '' : $contents; } @@ -447,6 +462,7 @@ class Xlsx extends BaseReader $colourScheme = self::getAttributes($xmlTheme->themeElements->clrScheme); $colourSchemeName = (string) $colourScheme['name']; + $excel->getTheme()->setThemeColorName($colourSchemeName); $colourScheme = $xmlTheme->themeElements->clrScheme->children($drawingNS); $themeColours = []; @@ -458,14 +474,46 @@ class Xlsx extends BaseReader if (isset($xmlColour->sysClr)) { $xmlColourData = self::getAttributes($xmlColour->sysClr); $themeColours[$themePos] = (string) $xmlColourData['lastClr']; + $excel->getTheme()->setThemeColor($k, (string) $xmlColourData['lastClr']); } elseif (isset($xmlColour->srgbClr)) { $xmlColourData = self::getAttributes($xmlColour->srgbClr); $themeColours[$themePos] = (string) $xmlColourData['val']; + $excel->getTheme()->setThemeColor($k, (string) $xmlColourData['val']); } } $theme = new Theme($themeName, $colourSchemeName, $themeColours); $this->styleReader->setTheme($theme); + $fontScheme = self::getAttributes($xmlTheme->themeElements->fontScheme); + $fontSchemeName = (string) $fontScheme['name']; + $excel->getTheme()->setThemeFontName($fontSchemeName); + $majorFonts = []; + $minorFonts = []; + $fontScheme = $xmlTheme->themeElements->fontScheme->children($drawingNS); + $majorLatin = self::getAttributes($fontScheme->majorFont->latin)['typeface'] ?? ''; + $majorEastAsian = self::getAttributes($fontScheme->majorFont->ea)['typeface'] ?? ''; + $majorComplexScript = self::getAttributes($fontScheme->majorFont->cs)['typeface'] ?? ''; + $minorLatin = self::getAttributes($fontScheme->minorFont->latin)['typeface'] ?? ''; + $minorEastAsian = self::getAttributes($fontScheme->minorFont->ea)['typeface'] ?? ''; + $minorComplexScript = self::getAttributes($fontScheme->minorFont->cs)['typeface'] ?? ''; + + foreach ($fontScheme->majorFont->font as $xmlFont) { + $fontAttributes = self::getAttributes($xmlFont); + $script = (string) ($fontAttributes['script'] ?? ''); + if (!empty($script)) { + $majorFonts[$script] = (string) ($fontAttributes['typeface'] ?? ''); + } + } + foreach ($fontScheme->minorFont->font as $xmlFont) { + $fontAttributes = self::getAttributes($xmlFont); + $script = (string) ($fontAttributes['script'] ?? ''); + if (!empty($script)) { + $minorFonts[$script] = (string) ($fontAttributes['typeface'] ?? ''); + } + } + $excel->getTheme()->setMajorFontValues($majorLatin, $majorEastAsian, $majorComplexScript, $majorFonts); + $excel->getTheme()->setMinorFontValues($minorLatin, $minorEastAsian, $minorComplexScript, $minorFonts); + break; } } @@ -477,6 +525,10 @@ class Xlsx extends BaseReader foreach ($rels->Relationship as $relx) { $rel = self::getAttributes($relx); $relTarget = (string) $rel['Target']; + // issue 3553 + if ($relTarget[0] === '/') { + $relTarget = substr($relTarget, 1); + } $relType = (string) $rel['Type']; $mainNS = self::REL_TO_MAIN[$relType] ?? Namespaces::MAIN; switch ($relType) { @@ -507,26 +559,6 @@ class Xlsx extends BaseReader $relsWorkbook = $this->loadZip("$dir/_rels/" . basename($relTarget) . '.rels', ''); $relsWorkbook->registerXPathNamespace('rel', Namespaces::RELATIONSHIPS); - $sharedStrings = []; - $relType = "rel:Relationship[@Type='" - //. Namespaces::SHARED_STRINGS - . "$xmlNamespaceBase/sharedStrings" - . "']"; - $xpath = self::getArrayItem($relsWorkbook->xpath($relType)); - - if ($xpath) { - $xmlStrings = $this->loadZip("$dir/$xpath[Target]", $mainNS); - if (isset($xmlStrings->si)) { - foreach ($xmlStrings->si as $val) { - if (isset($val->t)) { - $sharedStrings[] = StringHelper::controlCharacterOOXML2PHP((string) $val->t); - } elseif (isset($val->r)) { - $sharedStrings[] = $this->parseRichText($val); - } - } - } - } - $worksheets = []; $macros = $customUI = null; foreach ($relsWorkbook->Relationship as $elex) { @@ -618,7 +650,7 @@ class Xlsx extends BaseReader $numFmt = NumberFormat::builtInFormatCode((int) $xf['numFmtId']); } } - $quotePrefix = (bool) ($xf['quotePrefix'] ?? false); + $quotePrefix = (bool) (string) ($xf['quotePrefix'] ?? ''); $style = (object) [ 'numFmt' => $numFmt ?? NumberFormat::FORMAT_GENERAL, @@ -653,7 +685,7 @@ class Xlsx extends BaseReader } } - $quotePrefix = (bool) ($xf['quotePrefix'] ?? false); + $quotePrefix = (bool) (string) ($xf['quotePrefix'] ?? ''); $cellStyle = (object) [ 'numFmt' => $numFmt, @@ -682,6 +714,27 @@ class Xlsx extends BaseReader $dxfs = $this->styleReader->dxfs($this->readDataOnly); $styles = $this->styleReader->styles(); + // Read content after setting the styles + $sharedStrings = []; + $relType = "rel:Relationship[@Type='" + //. Namespaces::SHARED_STRINGS + . "$xmlNamespaceBase/sharedStrings" + . "']"; + $xpath = self::getArrayItem($relsWorkbook->xpath($relType)); + + if ($xpath) { + $xmlStrings = $this->loadZip("$dir/$xpath[Target]", $mainNS); + if (isset($xmlStrings->si)) { + foreach ($xmlStrings->si as $val) { + if (isset($val->t)) { + $sharedStrings[] = StringHelper::controlCharacterOOXML2PHP((string) $val->t); + } elseif (isset($val->r)) { + $sharedStrings[] = $this->parseRichText($val); + } + } + } + } + $xmlWorkbook = $this->loadZipNoNamespace($relTarget, $mainNS); $xmlWorkbookNS = $this->loadZip($relTarget, $mainNS); @@ -743,7 +796,8 @@ class Xlsx extends BaseReader $xmlSheet = $this->loadZipNoNamespace("$dir/$fileWorksheet", $mainNS); $xmlSheetNS = $this->loadZip("$dir/$fileWorksheet", $mainNS); - $sharedFormulas = []; + // Shared Formula table is unique to each Worksheet, so we need to reset it here + $this->sharedFormulae = []; if (isset($eleSheetAttr['state']) && (string) $eleSheetAttr['state'] != '') { $docSheet->setSheetState((string) $eleSheetAttr['state']); @@ -789,8 +843,12 @@ class Xlsx extends BaseReader $coordinates = Coordinate::coordinateFromString($r); if (!$this->getReadFilter()->readCell($coordinates[0], (int) $coordinates[1], $docSheet->getTitle())) { - if (isset($cAttr->f)) { - $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError'); + // Normally, just testing for the f attribute should identify this cell as containing a formula + // that we need to read, even though it is outside of the filter range, in case it is a shared formula. + // But in some cases, this attribute isn't set; so we need to delve a level deeper and look at + // whether or not the cell has a child formula element that is shared. + if (isset($cAttr->f) || (isset($c->f, $c->f->attributes()['t']) && strtolower((string) $c->f->attributes()['t']) === 'shared')) { + $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, 'castToError', false); } ++$rowIndex; @@ -822,7 +880,7 @@ class Xlsx extends BaseReader } } else { // Formula - $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToBoolean'); + $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, 'castToBoolean'); if (isset($c->f['t'])) { $att = $c->f; $docSheet->getCell($r)->setFormulaAttributes($att); @@ -832,7 +890,7 @@ class Xlsx extends BaseReader break; case 'inlineStr': if (isset($c->f)) { - $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError'); + $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, 'castToError'); } else { $value = $this->parseRichText($c->is); } @@ -843,7 +901,7 @@ class Xlsx extends BaseReader $value = self::castToError($c); } else { // Formula - $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError'); + $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, 'castToError'); } break; @@ -852,7 +910,7 @@ class Xlsx extends BaseReader $value = self::castToString($c); } else { // Formula - $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToString'); + $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, 'castToString'); if (isset($c->f['t'])) { $attributes = $c->f['t']; $docSheet->getCell($r)->setFormulaAttributes(['t' => (string) $attributes]); @@ -891,6 +949,10 @@ class Xlsx extends BaseReader // no style index means 0, it seems $cell->setXfIndex(isset($styles[(int) ($cAttr['s'])]) ? (int) ($cAttr['s']) : 0); + // issue 3495 + if ($cell->getDataType() === DataType::TYPE_FORMULA) { + $cell->getStyle()->setQuotePrefix(false); + } } } ++$rowIndex; @@ -898,6 +960,12 @@ class Xlsx extends BaseReader ++$cIndex; } } + if ($xmlSheetNS && $xmlSheetNS->ignoredErrors) { + foreach ($xmlSheetNS->ignoredErrors->ignoredError as $ignoredErrorx) { + $ignoredError = self::testSimpleXml($ignoredErrorx); + $this->processIgnoredErrors($ignoredError, $docSheet); + } + } if (!$this->readDataOnly && $xmlSheetNS && $xmlSheetNS->sheetProtection) { $protAttr = $xmlSheetNS->sheetProtection->attributes() ?? []; @@ -2205,4 +2273,48 @@ class Xlsx extends BaseReader return $array; } + + private function processIgnoredErrors(SimpleXMLElement $xml, Worksheet $sheet): void + { + $attributes = self::getAttributes($xml); + $sqref = (string) ($attributes['sqref'] ?? ''); + $numberStoredAsText = (string) ($attributes['numberStoredAsText'] ?? ''); + $formula = (string) ($attributes['formula'] ?? ''); + $twoDigitTextYear = (string) ($attributes['twoDigitTextYear'] ?? ''); + $evalError = (string) ($attributes['evalError'] ?? ''); + if (!empty($sqref)) { + $explodedSqref = explode(' ', $sqref); + $pattern1 = '/^([A-Z]{1,3})([0-9]{1,7})(:([A-Z]{1,3})([0-9]{1,7}))?$/'; + foreach ($explodedSqref as $sqref1) { + if (preg_match($pattern1, $sqref1, $matches) === 1) { + $firstRow = $matches[2]; + $firstCol = $matches[1]; + if (array_key_exists(3, $matches)) { + $lastCol = $matches[4]; + $lastRow = $matches[5]; + } else { + $lastCol = $firstCol; + $lastRow = $firstRow; + } + ++$lastCol; + for ($row = $firstRow; $row <= $lastRow; ++$row) { + for ($col = $firstCol; $col !== $lastCol; ++$col) { + if ($numberStoredAsText === '1') { + $sheet->getCell("$col$row")->getIgnoredErrors()->setNumberStoredAsText(true); + } + if ($formula === '1') { + $sheet->getCell("$col$row")->getIgnoredErrors()->setFormula(true); + } + if ($twoDigitTextYear === '1') { + $sheet->getCell("$col$row")->getIgnoredErrors()->setTwoDigitTextYear(true); + } + if ($evalError === '1') { + $sheet->getCell("$col$row")->getIgnoredErrors()->setEvalError(true); + } + } + } + } + } + } + } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Chart.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Chart.php index 5230cf0d76a..c5a59f55837 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Chart.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Chart.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx; use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError; use PhpOffice\PhpSpreadsheet\Chart\Axis; +use PhpOffice\PhpSpreadsheet\Chart\AxisText; use PhpOffice\PhpSpreadsheet\Chart\ChartColor; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; @@ -76,16 +77,28 @@ class Chart $yAxis = new Axis(); $autoTitleDeleted = null; $chartNoFill = false; + $chartBorderLines = null; + $chartFillColor = null; $gradientArray = []; $gradientLin = null; $roundedCorners = false; + $gapWidth = null; + $useUpBars = null; + $useDownBars = null; foreach ($chartElementsC as $chartElementKey => $chartElement) { switch ($chartElementKey) { case 'spPr': - $possibleNoFill = $chartElementsC->spPr->children($this->aNamespace); - if (isset($possibleNoFill->noFill)) { + $children = $chartElementsC->spPr->children($this->aNamespace); + if (isset($children->noFill)) { $chartNoFill = true; } + if (isset($children->solidFill)) { + $chartFillColor = $this->readColor($children->solidFill); + } + if (isset($children->ln)) { + $chartBorderLines = new GridLines(); + $this->readLineStyle($chartElementsC, $chartBorderLines); + } break; case 'roundedCorners': @@ -157,6 +170,9 @@ class Chart $axisColorArray = $this->readColor($sppr->solidFill); $xAxis->setFillParameters($axisColorArray['value'], $axisColorArray['alpha'], $axisColorArray['type']); } + if (isset($chartDetail->spPr->ln->noFill)) { + $xAxis->setNoFill(true); + } } if (isset($chartDetail->majorGridlines)) { $majorGridlines = new GridLines(); @@ -227,6 +243,9 @@ class Chart $axisColorArray = $this->readColor($sppr->solidFill); $whichAxis->setFillParameters($axisColorArray['value'], $axisColorArray['alpha'], $axisColorArray['type']); } + if (isset($sppr->ln->noFill)) { + $whichAxis->setNoFill(true); + } } if ($whichAxis !== null && isset($chartDetail->majorGridlines)) { $majorGridlines = new GridLines(); @@ -316,6 +335,15 @@ class Chart break; case 'stockChart': $plotSeries[] = $this->chartDataSeries($chartDetail, $chartDetailKey); + if (isset($chartDetail->upDownBars->gapWidth)) { + $gapWidth = self::getAttribute($chartDetail->upDownBars->gapWidth, 'val', 'integer'); + } + if (isset($chartDetail->upDownBars->upBars)) { + $useUpBars = true; + } + if (isset($chartDetail->upDownBars->downBars)) { + $useDownBars = true; + } $plotAttributes = $this->readChartAttributes($chartDetail); break; @@ -332,6 +360,15 @@ class Chart if (!empty($gradientArray)) { $plotArea->setGradientFillProperties($gradientArray, $gradientLin); } + if (is_int($gapWidth)) { + $plotArea->setGapWidth($gapWidth); + } + if ($useUpBars === true) { + $plotArea->setUseUpBars(true); + } + if ($useDownBars === true) { + $plotArea->setUseDownBars(true); + } break; case 'plotVisOnly': @@ -350,6 +387,10 @@ class Chart $legendPos = 'r'; $legendLayout = null; $legendOverlay = false; + $legendBorderLines = null; + $legendFillColor = null; + $legendText = null; + $addLegendText = false; foreach ($chartDetails as $chartDetailKey => $chartDetail) { $chartDetail = Xlsx::testSimpleXml($chartDetail); switch ($chartDetailKey) { @@ -364,10 +405,45 @@ class Chart case 'layout': $legendLayout = $this->chartLayoutDetails($chartDetail); + break; + case 'spPr': + $children = $chartDetails->spPr->children($this->aNamespace); + if (isset($children->solidFill)) { + $legendFillColor = $this->readColor($children->solidFill); + } + if (isset($children->ln)) { + $legendBorderLines = new GridLines(); + $this->readLineStyle($chartDetails, $legendBorderLines); + } + + break; + case 'txPr': + $children = $chartDetails->txPr->children($this->aNamespace); + $addLegendText = false; + $legendText = new AxisText(); + if (isset($children->p->pPr->defRPr->solidFill)) { + $colorArray = $this->readColor($children->p->pPr->defRPr->solidFill); + $legendText->getFillColorObject()->setColorPropertiesArray($colorArray); + $addLegendText = true; + } + if (isset($children->p->pPr->defRPr->effectLst)) { + $this->readEffects($children->p->pPr->defRPr, $legendText, false); + $addLegendText = true; + } + break; } } $legend = new Legend("$legendPos", $legendLayout, (bool) $legendOverlay); + if ($legendFillColor !== null) { + $legend->getFillColor()->setColorPropertiesArray($legendFillColor); + } + if ($legendBorderLines !== null) { + $legend->setBorderLines($legendBorderLines); + } + if ($addLegendText) { + $legend->setLegendText($legendText); + } break; } @@ -378,6 +454,12 @@ class Chart if ($chartNoFill) { $chart->setNoFill(true); } + if ($chartFillColor !== null) { + $chart->getFillColor()->setColorPropertiesArray($chartFillColor); + } + if ($chartBorderLines !== null) { + $chart->setBorderLines($chartBorderLines); + } $chart->setRoundedCorners($roundedCorners); if (is_bool($autoTitleDeleted)) { $chart->setAutoTitleDeleted($autoTitleDeleted); @@ -1082,6 +1164,37 @@ class Chart return $value; } + private function parseFont(SimpleXMLElement $titleDetailPart): ?Font + { + if (!isset($titleDetailPart->pPr->defRPr)) { + return null; + } + $fontArray = []; + $fontArray['size'] = self::getAttribute($titleDetailPart->pPr->defRPr, 'sz', 'integer'); + $fontArray['bold'] = self::getAttribute($titleDetailPart->pPr->defRPr, 'b', 'boolean'); + $fontArray['italic'] = self::getAttribute($titleDetailPart->pPr->defRPr, 'i', 'boolean'); + $fontArray['underscore'] = self::getAttribute($titleDetailPart->pPr->defRPr, 'u', 'string'); + $fontArray['strikethrough'] = self::getAttribute($titleDetailPart->pPr->defRPr, 'strike', 'string'); + + if (isset($titleDetailPart->pPr->defRPr->latin)) { + $fontArray['latin'] = self::getAttribute($titleDetailPart->pPr->defRPr->latin, 'typeface', 'string'); + } + if (isset($titleDetailPart->pPr->defRPr->ea)) { + $fontArray['eastAsian'] = self::getAttribute($titleDetailPart->pPr->defRPr->ea, 'typeface', 'string'); + } + if (isset($titleDetailPart->pPr->defRPr->cs)) { + $fontArray['complexScript'] = self::getAttribute($titleDetailPart->pPr->defRPr->cs, 'typeface', 'string'); + } + if (isset($titleDetailPart->pPr->defRPr->solidFill)) { + $fontArray['chartColor'] = new ChartColor($this->readColor($titleDetailPart->pPr->defRPr->solidFill)); + } + $font = new Font(); + $font->setSize(null, true); + $font->applyFromArray($fontArray); + + return $font; + } + /** * @param ?SimpleXMLElement $chartDetail */ @@ -1128,8 +1241,13 @@ class Chart } if (isset($chartDetail->dLbls->txPr)) { $txpr = $chartDetail->dLbls->txPr->children($this->aNamespace); - if (isset($txpr->p->pPr->defRPr->solidFill)) { - $plotAttributes['labelFontColor'] = new ChartColor($this->readColor($txpr->p->pPr->defRPr->solidFill)); + if (isset($txpr->p)) { + $plotAttributes['labelFont'] = $this->parseFont($txpr->p); + if (isset($txpr->p->pPr->defRPr->effectLst)) { + $labelEffects = new GridLines(); + $this->readEffects($txpr->p->pPr->defRPr, $labelEffects, false); + $plotAttributes['labelEffects'] = $labelEffects; + } } } } @@ -1176,13 +1294,19 @@ class Chart } } - private function readEffects(SimpleXMLElement $chartDetail, ?ChartProperties $chartObject): void + private function readEffects(SimpleXMLElement $chartDetail, ?ChartProperties $chartObject, bool $getSppr = true): void { - if (!isset($chartObject, $chartDetail->spPr)) { + if (!isset($chartObject)) { return; } - $sppr = $chartDetail->spPr->children($this->aNamespace); - + if ($getSppr) { + if (!isset($chartDetail->spPr)) { + return; + } + $sppr = $chartDetail->spPr->children($this->aNamespace); + } else { + $sppr = $chartDetail; + } if (isset($sppr->effectLst->glow)) { $axisGlowSize = (float) self::getAttribute($sppr->effectLst->glow, 'rad', 'integer') / ChartProperties::POINTS_WIDTH_MULTIPLIER; if ($axisGlowSize != 0.0) { @@ -1412,13 +1536,30 @@ class Chart } if (isset($chartDetail->txPr)) { $children = $chartDetail->txPr->children($this->aNamespace); + $addAxisText = false; + $axisText = new AxisText(); if (isset($children->bodyPr)) { /** @var string */ $textRotation = self::getAttribute($children->bodyPr, 'rot', 'string'); if (is_numeric($textRotation)) { - $whichAxis->setAxisOption('textRotation', (string) ChartProperties::xmlToAngle($textRotation)); + $axisText->setRotation((int) ChartProperties::xmlToAngle($textRotation)); + $addAxisText = true; } } + if (isset($children->p->pPr->defRPr)) { + $font = $this->parseFont($children->p); + if ($font !== null) { + $axisText->setFont($font); + $addAxisText = true; + } + } + if (isset($children->p->pPr->defRPr->effectLst)) { + $this->readEffects($children->p->pPr->defRPr, $axisText, false); + $addAxisText = true; + } + if ($addAxisText) { + $whichAxis->setAxisText($axisText); + } } } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/DataValidations.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/DataValidations.php index dac76230cc0..210c322f9d9 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/DataValidations.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/DataValidations.php @@ -22,6 +22,18 @@ class DataValidations public function load(): void { + foreach ($this->worksheetXml->dataValidations->dataValidation as $dataValidation) { + // Uppercase coordinate + $range = strtoupper((string) $dataValidation['sqref']); + $rangeSet = explode(' ', $range); + foreach ($rangeSet as $range) { + if (preg_match('/^[A-Z]{1,3}\\d{1,7}/', $range, $matches) === 1) { + // Ensure left/top row of range exists, thereby + // adjusting high row/column. + $this->worksheet->getCell($matches[0]); + } + } + } foreach ($this->worksheetXml->dataValidations->dataValidation as $dataValidation) { // Uppercase coordinate $range = strtoupper((string) $dataValidation['sqref']); diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Properties.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Properties.php index 72addffd5ba..0d4701afac6 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Properties.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Properties.php @@ -73,6 +73,9 @@ class Properties if (isset($xmlCore->Manager)) { $this->docProps->setManager((string) $xmlCore->Manager); } + if (isset($xmlCore->HyperlinkBase)) { + $this->docProps->setHyperlinkBase((string) $xmlCore->HyperlinkBase); + } } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/SharedFormula.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/SharedFormula.php new file mode 100644 index 00000000000..fb7a39320f8 --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/SharedFormula.php @@ -0,0 +1,26 @@ +master = $master; + $this->formula = $formula; + } + + public function master(): string + { + return $this->master; + } + + public function formula(): string + { + return $this->formula; + } +} diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Styles.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Styles.php index 705b319e755..5a360fda1d8 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Styles.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Styles.php @@ -136,6 +136,10 @@ class Styles extends BaseParserClass } } } + if (isset($fontStyleXml->scheme)) { + $attr = $this->getStyleAttributes($fontStyleXml->scheme); + $fontStyle->setScheme((string) $attr['val']); + } } private function readNumberFormat(NumberFormat $numfmtStyle, SimpleXMLElement $numfmtStyleXml): void @@ -253,10 +257,14 @@ class Styles extends BaseParserClass public function readAlignmentStyle(Alignment $alignment, SimpleXMLElement $alignmentXml): void { - $horizontal = $this->getAttribute($alignmentXml, 'horizontal'); - $alignment->setHorizontal($horizontal); - $vertical = $this->getAttribute($alignmentXml, 'vertical'); - $alignment->setVertical((string) $vertical); + $horizontal = (string) $this->getAttribute($alignmentXml, 'horizontal'); + if ($horizontal !== '') { + $alignment->setHorizontal($horizontal); + } + $vertical = (string) $this->getAttribute($alignmentXml, 'vertical'); + if ($vertical !== '') { + $alignment->setVertical($vertical); + } $textRotation = (int) $this->getAttribute($alignmentXml, 'textRotation'); if ($textRotation > 90) { diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml.php index 9cce7003fb5..6be26fc2c62 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml.php @@ -9,6 +9,7 @@ use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\DefinedName; use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner; +use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Namespaces; use PhpOffice\PhpSpreadsheet\Reader\Xml\PageSettings; use PhpOffice\PhpSpreadsheet\Reader\Xml\Properties; use PhpOffice\PhpSpreadsheet\Reader\Xml\Style; @@ -26,6 +27,8 @@ use SimpleXMLElement; */ class Xml extends BaseReader { + public const NAMESPACES_SS = 'urn:schemas-microsoft-com:office:spreadsheet'; + /** * Formats. * @@ -146,11 +149,9 @@ class Xml extends BaseReader throw new Exception("Problem reading {$filename}"); } - $namespaces = $xml->getNamespaces(true); - - $xml_ss = $xml->children($namespaces['ss']); + $xml_ss = $xml->children(self::NAMESPACES_SS); foreach ($xml_ss->Worksheet as $worksheet) { - $worksheet_ss = self::getAttributes($worksheet, $namespaces['ss']); + $worksheet_ss = self::getAttributes($worksheet, self::NAMESPACES_SS); $worksheetNames[] = (string) $worksheet_ss['Name']; } @@ -178,12 +179,10 @@ class Xml extends BaseReader throw new Exception("Problem reading {$filename}"); } - $namespaces = $xml->getNamespaces(true); - $worksheetID = 1; - $xml_ss = $xml->children($namespaces['ss']); + $xml_ss = $xml->children(self::NAMESPACES_SS); foreach ($xml_ss->Worksheet as $worksheet) { - $worksheet_ss = self::getAttributes($worksheet, $namespaces['ss']); + $worksheet_ss = self::getAttributes($worksheet, self::NAMESPACES_SS); $tmpInfo = []; $tmpInfo['worksheetName'] = ''; @@ -231,6 +230,19 @@ class Xml extends BaseReader return $worksheetInfo; } + /** + * Loads Spreadsheet from string. + */ + public function loadSpreadsheetFromString(string $contents): Spreadsheet + { + // Create new Spreadsheet + $spreadsheet = new Spreadsheet(); + $spreadsheet->removeSheetByIndex(0); + + // Load into this instance + return $this->loadIntoExisting($contents, $spreadsheet, true); + } + /** * Loads Spreadsheet from file. */ @@ -245,17 +257,19 @@ class Xml extends BaseReader } /** - * Loads from file into Spreadsheet instance. + * Loads from file or contents into Spreadsheet instance. * - * @param string $filename - * - * @return Spreadsheet + * @param string $filename file name if useContents is false else file contents */ - public function loadIntoExisting($filename, Spreadsheet $spreadsheet) + public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet, bool $useContents = false): Spreadsheet { - File::assertFile($filename); - if (!$this->canRead($filename)) { - throw new Exception($filename . ' is an Invalid Spreadsheet file.'); + if ($useContents) { + $this->fileContents = $filename; + } else { + File::assertFile($filename); + if (!$this->canRead($filename)) { + throw new Exception($filename . ' is an Invalid Spreadsheet file.'); + } } $xml = $this->trySimpleXMLLoadString($filename); @@ -268,14 +282,17 @@ class Xml extends BaseReader (new Properties($spreadsheet))->readProperties($xml, $namespaces); $this->styles = (new Style())->parseStyles($xml, $namespaces); + if (isset($this->styles['Default'])) { + $spreadsheet->getCellXfCollection()[0]->applyFromArray($this->styles['Default']); + } $worksheetID = 0; - $xml_ss = $xml->children($namespaces['ss']); + $xml_ss = $xml->children(self::NAMESPACES_SS); /** @var null|SimpleXMLElement $worksheetx */ foreach ($xml_ss->Worksheet as $worksheetx) { $worksheet = $worksheetx ?? new SimpleXMLElement(''); - $worksheet_ss = self::getAttributes($worksheet, $namespaces['ss']); + $worksheet_ss = self::getAttributes($worksheet, self::NAMESPACES_SS); if ( isset($this->loadSheetsOnly, $worksheet_ss['Name']) && @@ -295,11 +312,15 @@ class Xml extends BaseReader // the worksheet name in line with the formula, not the reverse $spreadsheet->getActiveSheet()->setTitle($worksheetName, false, false); } + if (isset($worksheet_ss['Protected'])) { + $protection = (string) $worksheet_ss['Protected'] === '1'; + $spreadsheet->getActiveSheet()->getProtection()->setSheet($protection); + } // locally scoped defined names if (isset($worksheet->Names[0])) { foreach ($worksheet->Names[0] as $definedName) { - $definedName_ss = self::getAttributes($definedName, $namespaces['ss']); + $definedName_ss = self::getAttributes($definedName, self::NAMESPACES_SS); $name = (string) $definedName_ss['Name']; $definedValue = (string) $definedName_ss['RefersTo']; $convertedValue = AddressHelper::convertFormulaToA1($definedValue); @@ -313,15 +334,35 @@ class Xml extends BaseReader $columnID = 'A'; if (isset($worksheet->Table->Column)) { foreach ($worksheet->Table->Column as $columnData) { - $columnData_ss = self::getAttributes($columnData, $namespaces['ss']); + $columnData_ss = self::getAttributes($columnData, self::NAMESPACES_SS); + $colspan = 0; + if (isset($columnData_ss['Span'])) { + $spanAttr = (string) $columnData_ss['Span']; + if (is_numeric($spanAttr)) { + $colspan = max(0, (int) $spanAttr); + } + } if (isset($columnData_ss['Index'])) { $columnID = Coordinate::stringFromColumnIndex((int) $columnData_ss['Index']); } + $columnWidth = null; if (isset($columnData_ss['Width'])) { $columnWidth = $columnData_ss['Width']; - $spreadsheet->getActiveSheet()->getColumnDimension($columnID)->setWidth($columnWidth / 5.4); } - ++$columnID; + $columnVisible = null; + if (isset($columnData_ss['Hidden'])) { + $columnVisible = ((string) $columnData_ss['Hidden']) !== '1'; + } + while ($colspan >= 0) { + if (isset($columnWidth)) { + $spreadsheet->getActiveSheet()->getColumnDimension($columnID)->setWidth($columnWidth / 5.4); + } + if (isset($columnVisible)) { + $spreadsheet->getActiveSheet()->getColumnDimension($columnID)->setVisible($columnVisible); + } + ++$columnID; + --$colspan; + } } } @@ -330,14 +371,18 @@ class Xml extends BaseReader $additionalMergedCells = 0; foreach ($worksheet->Table->Row as $rowData) { $rowHasData = false; - $row_ss = self::getAttributes($rowData, $namespaces['ss']); + $row_ss = self::getAttributes($rowData, self::NAMESPACES_SS); if (isset($row_ss['Index'])) { $rowID = (int) $row_ss['Index']; } + if (isset($row_ss['Hidden'])) { + $rowVisible = ((string) $row_ss['Hidden']) !== '1'; + $spreadsheet->getActiveSheet()->getRowDimension($rowID)->setVisible($rowVisible); + } $columnID = 'A'; foreach ($rowData->Cell as $cell) { - $cell_ss = self::getAttributes($cell, $namespaces['ss']); + $cell_ss = self::getAttributes($cell, self::NAMESPACES_SS); if (isset($cell_ss['Index'])) { $columnID = Coordinate::stringFromColumnIndex((int) $cell_ss['Index']); } @@ -379,7 +424,7 @@ class Xml extends BaseReader $cellData = $cell->Data; $cellValue = (string) $cellData; $type = DataType::TYPE_NULL; - $cellData_ss = self::getAttributes($cellData, $namespaces['ss']); + $cellData_ss = self::getAttributes($cellData, self::NAMESPACES_SS); if (isset($cellData_ss['Type'])) { $cellDataType = $cellData_ss['Type']; switch ($cellDataType) { @@ -437,7 +482,7 @@ class Xml extends BaseReader } if (isset($cell->Comment)) { - $this->parseCellComment($cell->Comment, $namespaces, $spreadsheet, $columnID, $rowID); + $this->parseCellComment($cell->Comment, $spreadsheet, $columnID, $rowID); } if (isset($cell_ss['StyleID'])) { @@ -466,11 +511,57 @@ class Xml extends BaseReader ++$rowID; } + } - if (isset($namespaces['x'])) { - $xmlX = $worksheet->children($namespaces['x']); - if (isset($xmlX->WorksheetOptions)) { - (new PageSettings($xmlX, $namespaces))->loadPageSettings($spreadsheet); + $dataValidations = new Xml\DataValidations(); + $dataValidations->loadDataValidations($worksheet, $spreadsheet); + $xmlX = $worksheet->children(Namespaces::URN_EXCEL); + if (isset($xmlX->WorksheetOptions)) { + if (isset($xmlX->WorksheetOptions->FreezePanes)) { + $freezeRow = $freezeColumn = 1; + if (isset($xmlX->WorksheetOptions->SplitHorizontal)) { + $freezeRow = (int) $xmlX->WorksheetOptions->SplitHorizontal + 1; + } + if (isset($xmlX->WorksheetOptions->SplitVertical)) { + $freezeColumn = (int) $xmlX->WorksheetOptions->SplitVertical + 1; + } + $spreadsheet->getActiveSheet()->freezePane(Coordinate::stringFromColumnIndex($freezeColumn) . (string) $freezeRow); + } + (new PageSettings($xmlX))->loadPageSettings($spreadsheet); + if (isset($xmlX->WorksheetOptions->TopRowVisible, $xmlX->WorksheetOptions->LeftColumnVisible)) { + $leftTopRow = (string) $xmlX->WorksheetOptions->TopRowVisible; + $leftTopColumn = (string) $xmlX->WorksheetOptions->LeftColumnVisible; + if (is_numeric($leftTopRow) && is_numeric($leftTopColumn)) { + $leftTopCoordinate = Coordinate::stringFromColumnIndex((int) $leftTopColumn + 1) . (string) ($leftTopRow + 1); + $spreadsheet->getActiveSheet()->setTopLeftCell($leftTopCoordinate); + } + } + $rangeCalculated = false; + if (isset($xmlX->WorksheetOptions->Panes->Pane->RangeSelection)) { + if (1 === preg_match('/^R(\d+)C(\d+):R(\d+)C(\d+)$/', (string) $xmlX->WorksheetOptions->Panes->Pane->RangeSelection, $selectionMatches)) { + $selectedCell = Coordinate::stringFromColumnIndex((int) $selectionMatches[2]) + . $selectionMatches[1] + . ':' + . Coordinate::stringFromColumnIndex((int) $selectionMatches[4]) + . $selectionMatches[3]; + $spreadsheet->getActiveSheet()->setSelectedCells($selectedCell); + $rangeCalculated = true; + } + } + if (!$rangeCalculated) { + if (isset($xmlX->WorksheetOptions->Panes->Pane->ActiveRow)) { + $activeRow = (string) $xmlX->WorksheetOptions->Panes->Pane->ActiveRow; + } else { + $activeRow = 0; + } + if (isset($xmlX->WorksheetOptions->Panes->Pane->ActiveCol)) { + $activeColumn = (string) $xmlX->WorksheetOptions->Panes->Pane->ActiveCol; + } else { + $activeColumn = 0; + } + if (is_numeric($activeRow) && is_numeric($activeColumn)) { + $selectedCell = Coordinate::stringFromColumnIndex((int) $activeColumn + 1) . (string) ($activeRow + 1); + $spreadsheet->getActiveSheet()->setSelectedCells($selectedCell); } } } @@ -478,10 +569,14 @@ class Xml extends BaseReader } // Globally scoped defined names - $activeWorksheet = $spreadsheet->setActiveSheetIndex(0); + $activeSheetIndex = 0; + if (isset($xml->ExcelWorkbook->ActiveSheet)) { + $activeSheetIndex = (int) (string) $xml->ExcelWorkbook->ActiveSheet; + } + $activeWorksheet = $spreadsheet->setActiveSheetIndex($activeSheetIndex); if (isset($xml->Names[0])) { foreach ($xml->Names[0] as $definedName) { - $definedName_ss = self::getAttributes($definedName, $namespaces['ss']); + $definedName_ss = self::getAttributes($definedName, self::NAMESPACES_SS); $name = (string) $definedName_ss['Name']; $definedValue = (string) $definedName_ss['RefersTo']; $convertedValue = AddressHelper::convertFormulaToA1($definedValue); @@ -498,12 +593,11 @@ class Xml extends BaseReader protected function parseCellComment( SimpleXMLElement $comment, - array $namespaces, Spreadsheet $spreadsheet, string $columnID, int $rowID ): void { - $commentAttributes = $comment->attributes($namespaces['ss']); + $commentAttributes = $comment->attributes(self::NAMESPACES_SS); $author = 'unknown'; if (isset($commentAttributes->Author)) { $author = (string) $commentAttributes->Author; diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/DataValidations.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/DataValidations.php new file mode 100644 index 00000000000..31748cb9c2d --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/DataValidations.php @@ -0,0 +1,177 @@ + DataValidation::OPERATOR_BETWEEN, + 'equal' => DataValidation::OPERATOR_EQUAL, + 'greater' => DataValidation::OPERATOR_GREATERTHAN, + 'greaterorequal' => DataValidation::OPERATOR_GREATERTHANOREQUAL, + 'less' => DataValidation::OPERATOR_LESSTHAN, + 'lessorequal' => DataValidation::OPERATOR_LESSTHANOREQUAL, + 'notbetween' => DataValidation::OPERATOR_NOTBETWEEN, + 'notequal' => DataValidation::OPERATOR_NOTEQUAL, + ]; + + private const TYPE_MAPPINGS = [ + 'textlength' => DataValidation::TYPE_TEXTLENGTH, + ]; + + private int $thisRow = 0; + + private int $thisColumn = 0; + + private function replaceR1C1(array $matches): string + { + return AddressHelper::convertToA1($matches[0], $this->thisRow, $this->thisColumn, false); + } + + public function loadDataValidations(SimpleXMLElement $worksheet, Spreadsheet $spreadsheet): void + { + $xmlX = $worksheet->children(Namespaces::URN_EXCEL); + $sheet = $spreadsheet->getActiveSheet(); + /** @var callable */ + $pregCallback = [$this, 'replaceR1C1']; + foreach ($xmlX->DataValidation as $dataValidation) { + $cells = []; + $validation = new DataValidation(); + + // set defaults + $validation->setShowDropDown(true); + $validation->setShowInputMessage(true); + $validation->setShowErrorMessage(true); + $validation->setShowDropDown(true); + $this->thisRow = 1; + $this->thisColumn = 1; + + foreach ($dataValidation as $tagName => $tagValue) { + $tagValue = (string) $tagValue; + $tagValueLower = strtolower($tagValue); + switch ($tagName) { + case 'Range': + foreach (explode(',', $tagValue) as $range) { + $cell = ''; + if (preg_match('/^R(\d+)C(\d+):R(\d+)C(\d+)$/', (string) $range, $selectionMatches) === 1) { + // range + $firstCell = Coordinate::stringFromColumnIndex((int) $selectionMatches[2]) + . $selectionMatches[1]; + $cell = $firstCell + . ':' + . Coordinate::stringFromColumnIndex((int) $selectionMatches[4]) + . $selectionMatches[3]; + $this->thisRow = (int) $selectionMatches[1]; + $this->thisColumn = (int) $selectionMatches[2]; + $sheet->getCell($firstCell); + } elseif (preg_match('/^R(\d+)C(\d+)$/', (string) $range, $selectionMatches) === 1) { + // cell + $cell = Coordinate::stringFromColumnIndex((int) $selectionMatches[2]) + . $selectionMatches[1]; + $sheet->getCell($cell); + $this->thisRow = (int) $selectionMatches[1]; + $this->thisColumn = (int) $selectionMatches[2]; + } elseif (preg_match('/^C(\d+)$/', (string) $range, $selectionMatches) === 1) { + // column + $firstCell = Coordinate::stringFromColumnIndex((int) $selectionMatches[1]) + . '1'; + $cell = $firstCell + . ':' + . Coordinate::stringFromColumnIndex((int) $selectionMatches[1]) + . ((string) AddressRange::MAX_ROW); + $this->thisColumn = (int) $selectionMatches[1]; + $sheet->getCell($firstCell); + } elseif (preg_match('/^R(\d+)$/', (string) $range, $selectionMatches)) { + // row + $firstCell = 'A' + . $selectionMatches[1]; + $cell = $firstCell + . ':' + . AddressRange::MAX_COLUMN + . $selectionMatches[1]; + $this->thisRow = (int) $selectionMatches[1]; + $sheet->getCell($firstCell); + } + + $validation->setSqref($cell); + $stRange = $sheet->shrinkRangeToFit($cell); + $cells = array_merge($cells, Coordinate::extractAllCellReferencesInRange($stRange)); + } + + break; + case 'Type': + $validation->setType(self::TYPE_MAPPINGS[$tagValueLower] ?? $tagValueLower); + + break; + case 'Qualifier': + $validation->setOperator(self::OPERATOR_MAPPINGS[$tagValueLower] ?? $tagValueLower); + + break; + case 'InputTitle': + $validation->setPromptTitle($tagValue); + + break; + case 'InputMessage': + $validation->setPrompt($tagValue); + + break; + case 'InputHide': + $validation->setShowInputMessage(false); + + break; + case 'ErrorStyle': + $validation->setErrorStyle($tagValueLower); + + break; + case 'ErrorTitle': + $validation->setErrorTitle($tagValue); + + break; + case 'ErrorMessage': + $validation->setError($tagValue); + + break; + case 'ErrorHide': + $validation->setShowErrorMessage(false); + + break; + case 'ComboHide': + $validation->setShowDropDown(false); + + break; + case 'UseBlank': + $validation->setAllowBlank(true); + + break; + case 'CellRangeList': + // FIXME missing FIXME + + break; + case 'Min': + case 'Value': + $tagValue = (string) preg_replace_callback(AddressHelper::R1C1_COORDINATE_REGEX, $pregCallback, $tagValue); + $validation->setFormula1($tagValue); + + break; + case 'Max': + $tagValue = (string) preg_replace_callback(AddressHelper::R1C1_COORDINATE_REGEX, $pregCallback, $tagValue); + $validation->setFormula2($tagValue); + + break; + } + } + + foreach ($cells as $cell) { + $sheet->getCell($cell)->setDataValidation(clone $validation); + } + } + } +} diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/PageSettings.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/PageSettings.php index 39535c3e71f..137cabaf308 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/PageSettings.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/PageSettings.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Reader\Xml; +use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Namespaces; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup; use SimpleXMLElement; @@ -14,9 +15,9 @@ class PageSettings */ private $printSettings; - public function __construct(SimpleXMLElement $xmlX, array $namespaces) + public function __construct(SimpleXMLElement $xmlX) { - $printSettings = $this->pageSetup($xmlX, $namespaces, $this->getPrintDefaults()); + $printSettings = $this->pageSetup($xmlX, $this->getPrintDefaults()); $this->printSettings = $this->printSetup($xmlX, $printSettings); } @@ -56,13 +57,13 @@ class PageSettings ]; } - private function pageSetup(SimpleXMLElement $xmlX, array $namespaces, stdClass $printDefaults): stdClass + private function pageSetup(SimpleXMLElement $xmlX, stdClass $printDefaults): stdClass { if (isset($xmlX->WorksheetOptions->PageSetup)) { foreach ($xmlX->WorksheetOptions->PageSetup as $pageSetupData) { foreach ($pageSetupData as $pageSetupKey => $pageSetupValue) { /** @scrutinizer ignore-call */ - $pageSetupAttributes = $pageSetupValue->attributes($namespaces['x']); + $pageSetupAttributes = $pageSetupValue->attributes(Namespaces::URN_EXCEL); if ($pageSetupAttributes !== null) { switch ($pageSetupKey) { case 'Layout': diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/Properties.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/Properties.php index f0346ed02f4..e216c254daf 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/Properties.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/Properties.php @@ -92,6 +92,10 @@ class Properties case 'Manager': $docProps->setManager($stringValue); + break; + case 'HyperlinkBase': + $docProps->setHyperlinkBase($stringValue); + break; case 'Keywords': $docProps->setKeywords($stringValue); @@ -110,17 +114,10 @@ class Properties ?SimpleXMLElement $propertyValue, SimpleXMLElement $propertyAttributes ): void { - $propertyType = DocumentProperties::PROPERTY_TYPE_UNKNOWN; - switch ((string) $propertyAttributes) { - case 'string': - $propertyType = DocumentProperties::PROPERTY_TYPE_STRING; - $propertyValue = trim((string) $propertyValue); - - break; case 'boolean': $propertyType = DocumentProperties::PROPERTY_TYPE_BOOLEAN; - $propertyValue = (bool) $propertyValue; + $propertyValue = (bool) (string) $propertyValue; break; case 'integer': @@ -134,9 +131,15 @@ class Properties break; case 'dateTime.tz': + case 'dateTime.iso8601tz': $propertyType = DocumentProperties::PROPERTY_TYPE_DATE; $propertyValue = trim((string) $propertyValue); + break; + default: + $propertyType = DocumentProperties::PROPERTY_TYPE_STRING; + $propertyValue = trim((string) $propertyValue); + break; } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/Style.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/Style.php index 774fffe8b9c..698acf6ac0f 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/Style.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/Style.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Reader\Xml; +use PhpOffice\PhpSpreadsheet\Style\Protection; use SimpleXMLElement; class Style @@ -30,7 +31,7 @@ class Style $styleID = (string) $style_ss['ID']; $this->styles[$styleID] = $this->styles['Default'] ?? []; - $alignment = $border = $font = $fill = $numberFormat = []; + $alignment = $border = $font = $fill = $numberFormat = $protection = []; foreach ($style as $styleType => $styleDatax) { $styleData = self::getSxml($styleDatax); @@ -64,11 +65,31 @@ class Style $numberFormat = $numberFormatStyleParser->parseStyle($styleAttributes); } + break; + case 'Protection': + $locked = $hidden = null; + $styleAttributesP = $styleData->attributes($namespaces['x']); + if (isset($styleAttributes['Protected'])) { + $locked = ((bool) (string) $styleAttributes['Protected']) ? Protection::PROTECTION_PROTECTED : Protection::PROTECTION_UNPROTECTED; + } + if (isset($styleAttributesP['HideFormula'])) { + $hidden = ((bool) (string) $styleAttributesP['HideFormula']) ? Protection::PROTECTION_PROTECTED : Protection::PROTECTION_UNPROTECTED; + } + if ($locked !== null || $hidden !== null) { + $protection['protection'] = []; + if ($locked !== null) { + $protection['protection']['locked'] = $locked; + } + if ($hidden !== null) { + $protection['protection']['hidden'] = $hidden; + } + } + break; } } - $this->styles[$styleID] = array_merge($alignment, $border, $font, $fill, $numberFormat); + $this->styles[$styleID] = array_merge($alignment, $border, $font, $fill, $numberFormat, $protection); } return $this->styles; diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/Style/Font.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/Style/Font.php index 16ab44d80d0..5f824889a56 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/Style/Font.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml/Style/Font.php @@ -56,11 +56,11 @@ class Font extends StyleBase break; case 'Bold': - $style['font']['bold'] = true; + $style['font']['bold'] = $styleAttributeValue === '1'; break; case 'Italic': - $style['font']['italic'] = true; + $style['font']['italic'] = $styleAttributeValue === '1'; break; case 'Underline': diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/ReferenceHelper.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/ReferenceHelper.php index b4d4d52afd1..90eee534dba 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/ReferenceHelper.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/ReferenceHelper.php @@ -75,14 +75,11 @@ class ReferenceHelper * * @return int */ - public static function columnReverseSort($a, $b) + public static function columnReverseSort(string $a, string $b) { return -strcasecmp(strlen($a) . $a, strlen($b) . $b); } - /** @var int */ - private static $scrutinizer0 = 0; - /** * Compare two cell addresses * Intended for use as a Callback function for sorting cell addresses by column and row. @@ -92,16 +89,16 @@ class ReferenceHelper * * @return int */ - public static function cellSort($a, $b) + public static function cellSort(string $a, string $b) { - $ac = $bc = ''; - $ar = self::$scrutinizer0; - $br = 0; + /** @scrutinizer be-damned */ sscanf($a, '%[A-Z]%d', $ac, $ar); + /** @var int $ar */ + /** @var string $ac */ + /** @scrutinizer be-damned */ sscanf($b, '%[A-Z]%d', $bc, $br); - - $ac = (string) $ac; - $bc = (string) $bc; + /** @var int $br */ + /** @var string $bc */ if ($ar === $br) { return strcasecmp(strlen($ac) . $ac, strlen($bc) . $bc); } @@ -118,16 +115,16 @@ class ReferenceHelper * * @return int */ - public static function cellReverseSort($a, $b) + public static function cellReverseSort(string $a, string $b) { - $ac = $bc = ''; - $ar = self::$scrutinizer0; - $br = 0; + /** @scrutinizer be-damned */ sscanf($a, '%[A-Z]%d', $ac, $ar); + /** @var int $ar */ + /** @var string $ac */ + /** @scrutinizer be-damned */ sscanf($b, '%[A-Z]%d', $bc, $br); - - $ac = (string) $ac; - $bc = (string) $bc; + /** @var int $br */ + /** @var string $bc */ if ($ar === $br) { return -strcasecmp(strlen($ac) . $ac, strlen($bc) . $bc); } @@ -142,7 +139,7 @@ class ReferenceHelper * @param int $numberOfColumns Number of columns to insert/delete (negative values indicate deletion) * @param int $numberOfRows Number of rows to insert/delete (negative values indicate deletion) */ - protected function adjustPageBreaks(Worksheet $worksheet, $numberOfColumns, $numberOfRows): void + protected function adjustPageBreaks(Worksheet $worksheet, int $numberOfColumns, int $numberOfRows): void { $aBreaks = $worksheet->getBreaks(); ($numberOfColumns > 0 || $numberOfRows > 0) @@ -171,7 +168,7 @@ class ReferenceHelper * * @param Worksheet $worksheet The worksheet that we're editing */ - protected function adjustComments($worksheet): void + protected function adjustComments(Worksheet $worksheet): void { $aComments = $worksheet->getComments(); $aNewComments = []; // the new array of all comments @@ -195,7 +192,7 @@ class ReferenceHelper * @param int $numberOfColumns Number of columns to insert/delete (negative values indicate deletion) * @param int $numberOfRows Number of rows to insert/delete (negative values indicate deletion) */ - protected function adjustHyperlinks($worksheet, $numberOfColumns, $numberOfRows): void + protected function adjustHyperlinks(Worksheet $worksheet, int $numberOfColumns, int $numberOfRows): void { $aHyperlinkCollection = $worksheet->getHyperlinkCollection(); ($numberOfColumns > 0 || $numberOfRows > 0) @@ -220,7 +217,7 @@ class ReferenceHelper * @param int $numberOfColumns Number of columns to insert/delete (negative values indicate deletion) * @param int $numberOfRows Number of rows to insert/delete (negative values indicate deletion) */ - protected function adjustConditionalFormatting($worksheet, $numberOfColumns, $numberOfRows): void + protected function adjustConditionalFormatting(Worksheet $worksheet, int $numberOfColumns, int $numberOfRows): void { $aStyles = $worksheet->getConditionalStylesCollection(); ($numberOfColumns > 0 || $numberOfRows > 0) @@ -259,7 +256,7 @@ class ReferenceHelper * @param int $numberOfColumns Number of columns to insert/delete (negative values indicate deletion) * @param int $numberOfRows Number of rows to insert/delete (negative values indicate deletion) */ - protected function adjustDataValidations(Worksheet $worksheet, $numberOfColumns, $numberOfRows): void + protected function adjustDataValidations(Worksheet $worksheet, int $numberOfColumns, int $numberOfRows): void { $aDataValidationCollection = $worksheet->getDataValidationCollection(); ($numberOfColumns > 0 || $numberOfRows > 0) @@ -299,7 +296,7 @@ class ReferenceHelper * @param int $numberOfColumns Number of columns to insert/delete (negative values indicate deletion) * @param int $numberOfRows Number of rows to insert/delete (negative values indicate deletion) */ - protected function adjustProtectedCells(Worksheet $worksheet, $numberOfColumns, $numberOfRows): void + protected function adjustProtectedCells(Worksheet $worksheet, int $numberOfColumns, int $numberOfRows): void { $aProtectedCells = $worksheet->getProtectedCells(); ($numberOfColumns > 0 || $numberOfRows > 0) @@ -412,7 +409,7 @@ class ReferenceHelper $cellCollection = $worksheet->getCellCollection(); $missingCoordinates = array_filter( array_map(function ($row) use ($highestColumn) { - return $highestColumn . $row; + return "{$highestColumn}{$row}"; }, range(1, $highestRow)), function ($coordinate) use ($cellCollection) { return $cellCollection->has($coordinate) === false; @@ -453,9 +450,9 @@ class ReferenceHelper if ($cell->getDataType() === DataType::TYPE_FORMULA) { // Formula should be adjusted $worksheet->getCell($newCoordinate) - ->setValue($this->updateFormulaReferences($cell->getValue(), $beforeCellAddress, $numberOfColumns, $numberOfRows, $worksheet->getTitle())); + ->setValue($this->updateFormulaReferences($cell->getValue(), $beforeCellAddress, $numberOfColumns, $numberOfRows, $worksheet->getTitle(), true)); } else { - // Formula should not be adjusted + // Cell value should not be adjusted $worksheet->getCell($newCoordinate)->setValueExplicit($cell->getValue(), $cell->getDataType()); } @@ -463,10 +460,10 @@ class ReferenceHelper $worksheet->getCellCollection()->delete($coordinate); } else { /* We don't need to update styles for rows/columns before our insertion position, - but we do still need to adjust any formulae in those cells */ + but we do still need to adjust any formulae in those cells */ if ($cell->getDataType() === DataType::TYPE_FORMULA) { // Formula should be adjusted - $cell->setValue($this->updateFormulaReferences($cell->getValue(), $beforeCellAddress, $numberOfColumns, $numberOfRows, $worksheet->getTitle())); + $cell->setValue($this->updateFormulaReferences($cell->getValue(), $beforeCellAddress, $numberOfColumns, $numberOfRows, $worksheet->getTitle(), true)); } } } @@ -609,7 +606,7 @@ class ReferenceHelper // Max worksheet size is 1,048,576 rows by 16,384 columns in Excel 2007, so our adjustments need to be at least one digit more $column = 100000; $row = 10000000 + (int) trim($match[3], '$'); - $cellIndex = $column . $row; + $cellIndex = "{$column}{$row}"; $newCellTokens[$cellIndex] = preg_quote($toString, '/'); $cellTokens[$cellIndex] = '/(?getValue(); $asFormula = ($cellAddress[0] === '='); if ($definedName->getWorksheet() !== null && $definedName->getWorksheet()->getHashCode() === $worksheet->getHashCode()) { + /** + * If we delete the entire range that is referenced by a Named Range, MS Excel sets the value to #REF! + * PhpSpreadsheet still only does a basic adjustment, so the Named Range will still reference Cells. + * Note that this applies only when deleting columns/rows; subsequent insertion won't fix the #REF! + * TODO Can we work out a method to identify Named Ranges that cease to be valid, so that we can replace + * them with a #REF! + */ if ($asFormula === true) { - $formula = $this->updateFormulaReferences($cellAddress, $beforeCellAddress, $numberOfColumns, $numberOfRows, $worksheet->getTitle()); + $formula = $this->updateFormulaReferences($cellAddress, $beforeCellAddress, $numberOfColumns, $numberOfRows, $worksheet->getTitle(), true); $definedName->setValue($formula); } else { - $definedName->setValue($this->updateCellReference(ltrim($cellAddress, '='))); + $definedName->setValue($this->updateCellReference(ltrim($cellAddress, '='), true)); } } } @@ -929,8 +933,15 @@ class ReferenceHelper private function updateNamedFormula(DefinedName $definedName, Worksheet $worksheet, string $beforeCellAddress, int $numberOfColumns, int $numberOfRows): void { if ($definedName->getWorksheet() !== null && $definedName->getWorksheet()->getHashCode() === $worksheet->getHashCode()) { + /** + * If we delete the entire range that is referenced by a Named Formula, MS Excel sets the value to #REF! + * PhpSpreadsheet still only does a basic adjustment, so the Named Formula will still reference Cells. + * Note that this applies only when deleting columns/rows; subsequent insertion won't fix the #REF! + * TODO Can we work out a method to identify Named Ranges that cease to be valid, so that we can replace + * them with a #REF! + */ $formula = $definedName->getValue(); - $formula = $this->updateFormulaReferences($formula, $beforeCellAddress, $numberOfColumns, $numberOfRows, $worksheet->getTitle()); + $formula = $this->updateFormulaReferences($formula, $beforeCellAddress, $numberOfColumns, $numberOfRows, $worksheet->getTitle(), true); $definedName->setValue($formula); } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/RichText/TextElement.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/RichText/TextElement.php index 23733436bb5..ee693a2b3f0 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/RichText/TextElement.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/RichText/TextElement.php @@ -47,7 +47,7 @@ class TextElement implements ITextElement } /** - * Get font. + * Get font. For this class, the return value is always null. * * @return null|\PhpOffice\PhpSpreadsheet\Style\Font */ diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Settings.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Settings.php index 0baf44637a6..d8007fd0097 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Settings.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Settings.php @@ -155,7 +155,7 @@ class Settings /** * Sets the implementation of cache that should be used for cell collection. */ - public static function setCache(CacheInterface $cache): void + public static function setCache(?CacheInterface $cache): void { self::$cache = $cache; } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Date.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Date.php index 26dde93f3ac..4f196731131 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Date.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Date.php @@ -184,7 +184,7 @@ class Date throw new Exception("Invalid string $value supplied for datatype Date"); } - if (preg_match('/^\\d\\d:\\d\\d:\\d\\d/', $value) == 1) { + if (preg_match('/^\\s*\\d?\\d:\\d\\d(:\\d\\d([.]\\d+)?)?\\s*(am|pm)?\\s*$/i', $value) == 1) { $newValue = fmod($newValue, 1.0); } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/File.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/File.php index 63ce0e036a6..737a6eb5912 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/File.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/File.php @@ -114,12 +114,6 @@ class File */ public static function sysGetTempDir(): string { - // Moodle hack! - if (function_exists('make_temp_directory')) { - $temp = make_temp_directory('phpspreadsheet'); - return realpath(dirname($temp)); - } - $path = sys_get_temp_dir(); if (self::$useUploadTempDirectory) { // use upload-directory when defined to allow running on environments having very restricted @@ -162,7 +156,11 @@ class File if ($zipMember !== '') { $zipfile = "zip://$filename#$zipMember"; if (!self::fileExists($zipfile)) { - throw new ReaderException("Could not find zip member $zipfile"); + // Has the file been saved with Windoze directory separators rather than unix? + $zipfile = "zip://$filename#" . str_replace('/', '\\', $zipMember); + if (!self::fileExists($zipfile)) { + throw new ReaderException("Could not find zip member $zipfile"); + } } } } @@ -186,6 +184,14 @@ class File return self::validateZipFirst4($filename); } - return self::fileExists("zip://$filename#$zipMember"); + $zipfile = "zip://$filename#$zipMember"; + if (self::fileExists($zipfile)) { + return true; + } + + // Has the file been saved with Windoze directory separators rather than unix? + $zipfile = "zip://$filename#" . str_replace('/', '\\', $zipMember); + + return self::fileExists($zipfile); } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Font.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Font.php index aa3512ae35d..90c1992a3ab 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Font.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Font.php @@ -380,15 +380,15 @@ class Font $approximate = self::$autoSizeMethod === self::AUTOSIZE_METHOD_APPROX; $columnWidth = 0; if (!$approximate) { - $columnWidthAdjust = ceil( - self::getTextWidthPixelsExact( - str_repeat('n', 1 * (($filterAdjustment ? 3 : 1) + ($indentAdjustment * 2))), - $font, - 0 - ) * 1.07 - ); - try { + $columnWidthAdjust = ceil( + self::getTextWidthPixelsExact( + str_repeat('n', 1 * (($filterAdjustment ? 3 : 1) + ($indentAdjustment * 2))), + $font, + 0 + ) * 1.07 + ); + // Width of text in pixels excl. padding // and addition because Excel adds some padding, just use approx width of 'n' glyph $columnWidth = self::getTextWidthPixelsExact($cellText, $font, $rotation) + $columnWidthAdjust; @@ -453,29 +453,26 @@ class Font $fontName = $font->getName(); $fontSize = $font->getSize(); - // Calculate column width in pixels. We assume fixed glyph width. Result varies with font name and size. + // Calculate column width in pixels. + // We assume fixed glyph width, but count double for "fullwidth" characters. + // Result varies with font name and size. switch ($fontName) { - case 'Calibri': - // value 8.26 was found via interpolation by inspecting real Excel files with Calibri 11 font. - $columnWidth = (int) (8.26 * StringHelper::countCharacters($columnText)); - $columnWidth = $columnWidth * $fontSize / 11; // extrapolate from font size - - break; case 'Arial': // value 8 was set because of experience in different exports at Arial 10 font. - $columnWidth = (int) (8 * StringHelper::countCharacters($columnText)); + $columnWidth = (int) (8 * StringHelper::countCharactersDbcs($columnText)); $columnWidth = $columnWidth * $fontSize / 10; // extrapolate from font size break; case 'Verdana': // value 8 was found via interpolation by inspecting real Excel files with Verdana 10 font. - $columnWidth = (int) (8 * StringHelper::countCharacters($columnText)); + $columnWidth = (int) (8 * StringHelper::countCharactersDbcs($columnText)); $columnWidth = $columnWidth * $fontSize / 10; // extrapolate from font size break; default: // just assume Calibri - $columnWidth = (int) (8.26 * StringHelper::countCharacters($columnText)); + // value 8.26 was found via interpolation by inspecting real Excel files with Calibri 11 font. + $columnWidth = (int) (8.26 * StringHelper::countCharactersDbcs($columnText)); $columnWidth = $columnWidth * $fontSize / 11; // extrapolate from font size break; @@ -564,10 +561,13 @@ class Font if (mb_strlen(self::$trueTypeFontPath) > 1 && mb_substr(self::$trueTypeFontPath, -1) !== '/' && mb_substr(self::$trueTypeFontPath, -1) !== '\\') { $separator = DIRECTORY_SEPARATOR; } - $fontFile = self::$trueTypeFontPath . $separator . $fontFile; + $fontFileAbsolute = preg_match('~^([A-Za-z]:)?[/\\\\]~', $fontFile) === 1; + if (!$fontFileAbsolute) { + $fontFile = self::$trueTypeFontPath . $separator . $fontFile; + } // Check if file actually exists - if ($checkPath && !file_exists($fontFile)) { + if ($checkPath && !file_exists($fontFile) && !$fontFileAbsolute) { $alternateName = $name; if ($index !== 'x' && $fontArray[$name][$index] !== $fontArray[$name]['x']) { // Bold but no italic: diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/StringHelper.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/StringHelper.php index 30bd8c5fd09..c6c198e203c 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/StringHelper.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/StringHelper.php @@ -451,6 +451,18 @@ class StringHelper return mb_strlen($textValue, $encoding); } + /** + * Get character count using mb_strwidth rather than mb_strlen. + * + * @param string $encoding Encoding + * + * @return int Character count + */ + public static function countCharactersDbcs(string $textValue, string $encoding = 'UTF-8'): int + { + return mb_strwidth($textValue, $encoding); + } + /** * Get a substring of a UTF-8 encoded string. * diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Trend/Trend.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Trend/Trend.php index b94609af72d..117848c778b 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Trend/Trend.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/Trend/Trend.php @@ -105,7 +105,6 @@ class Trend $className = '\PhpOffice\PhpSpreadsheet\Shared\Trend\\' . $trendType . 'BestFit'; //* @phpstan-ignore-next-line $bestFit[$trendMethod] = new $className($yValues, $xValues, $const); - //* @phpstan-ignore-next-line $bestFitValue[$trendMethod] = $bestFit[$trendMethod]->getGoodnessOfFit(); } if ($trendType != self::TREND_BEST_FIT_NO_POLY) { diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Spreadsheet.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Spreadsheet.php index f0744cd27f9..110908550f1 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Spreadsheet.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Spreadsheet.php @@ -203,6 +203,14 @@ class Spreadsheet implements JsonSerializable */ private $tabRatio = 600; + /** @var Theme */ + private $theme; + + public function getTheme(): Theme + { + return $this->theme; + } + /** * The workbook has macros ? * @@ -476,6 +484,7 @@ class Spreadsheet implements JsonSerializable { $this->uniqueID = uniqid('', true); $this->calculationEngine = new Calculation($this); + $this->theme = new Theme(); // Initialise worksheet collection and add one worksheet $this->workSheetCollection = []; @@ -1654,4 +1663,26 @@ class Spreadsheet implements JsonSerializable { throw new Exception('Spreadsheet objects cannot be json encoded'); } + + public function resetThemeFonts(): void + { + $majorFontLatin = $this->theme->getMajorFontLatin(); + $minorFontLatin = $this->theme->getMinorFontLatin(); + foreach ($this->cellXfCollection as $cellStyleXf) { + $scheme = $cellStyleXf->getFont()->getScheme(); + if ($scheme === 'major') { + $cellStyleXf->getFont()->setName($majorFontLatin)->setScheme($scheme); + } elseif ($scheme === 'minor') { + $cellStyleXf->getFont()->setName($minorFontLatin)->setScheme($scheme); + } + } + foreach ($this->cellStyleXfCollection as $cellStyleXf) { + $scheme = $cellStyleXf->getFont()->getScheme(); + if ($scheme === 'major') { + $cellStyleXf->getFont()->setName($majorFontLatin)->setScheme($scheme); + } elseif ($scheme === 'minor') { + $cellStyleXf->getFont()->setName($minorFontLatin)->setScheme($scheme); + } + } + } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Color.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Color.php index 3c002b27058..282defc0ce0 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Color.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Color.php @@ -362,23 +362,8 @@ class Color extends Supervisor $green = self::getGreen($hexColourValue, false); /** @var int $blue */ $blue = self::getBlue($hexColourValue, false); - if ($adjustPercentage > 0) { - $red += (255 - $red) * $adjustPercentage; - $green += (255 - $green) * $adjustPercentage; - $blue += (255 - $blue) * $adjustPercentage; - } else { - $red += $red * $adjustPercentage; - $green += $green * $adjustPercentage; - $blue += $blue * $adjustPercentage; - } - $rgb = strtoupper( - str_pad(dechex((int) $red), 2, '0', 0) . - str_pad(dechex((int) $green), 2, '0', 0) . - str_pad(dechex((int) $blue), 2, '0', 0) - ); - - return (($rgba) ? 'FF' : '') . $rgb; + return (($rgba) ? 'FF' : '') . RgbTint::rgbAndTintToRgb($red, $green, $blue, $adjustPercentage); } /** diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Conditional.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Conditional.php index de565d3458b..36069b00c85 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Conditional.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Conditional.php @@ -248,7 +248,7 @@ class Conditional implements IComparable /** * Set Conditions. * - * @param bool|float|int|string|(bool|float|int|string)[] $conditions Condition + * @param (bool|float|int|string)[]|bool|float|int|string $conditions Condition * * @return $this */ diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Font.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Font.php index 3d7bc1bce7b..a8eeaa9861d 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Font.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Font.php @@ -107,6 +107,9 @@ class Font extends Supervisor */ public $colorIndex; + /** @var string */ + protected $scheme = ''; + /** * Create a new Font. * @@ -231,6 +234,12 @@ class Font extends Supervisor if (isset($styleArray['size'])) { $this->setSize($styleArray['size']); } + if (isset($styleArray['chartColor'])) { + $this->chartColor = $styleArray['chartColor']; + } + if (isset($styleArray['scheme'])) { + $this->setScheme($styleArray['scheme']); + } } return $this; @@ -278,13 +287,11 @@ class Font extends Supervisor } /** - * Set Name. + * Set Name and turn off Scheme. * * @param string $fontname - * - * @return $this */ - public function setName($fontname) + public function setName($fontname): self { if ($fontname == '') { $fontname = 'Calibri'; @@ -296,7 +303,7 @@ class Font extends Supervisor $this->name = $fontname; } - return $this; + return $this->setScheme(''); } public function setLatin(string $fontname): self @@ -634,6 +641,13 @@ class Font extends Supervisor return $this; } + public function setChartColorFromObject(?ChartColor $chartColor): self + { + $this->chartColor = $chartColor; + + return $this; + } + /** * Get Underline. * @@ -774,6 +788,7 @@ class Font extends Supervisor $this->underline . ($this->strikethrough ? 't' : 'f') . $this->color->getHashCode() . + $this->scheme . implode( '*', [ @@ -802,6 +817,7 @@ class Font extends Supervisor $this->exportArray2($exportedArray, 'italic', $this->getItalic()); $this->exportArray2($exportedArray, 'latin', $this->getLatin()); $this->exportArray2($exportedArray, 'name', $this->getName()); + $this->exportArray2($exportedArray, 'scheme', $this->getScheme()); $this->exportArray2($exportedArray, 'size', $this->getSize()); $this->exportArray2($exportedArray, 'strikethrough', $this->getStrikethrough()); $this->exportArray2($exportedArray, 'strikeType', $this->getStrikeType()); @@ -812,4 +828,27 @@ class Font extends Supervisor return $exportedArray; } + + public function getScheme(): string + { + if ($this->isSupervisor) { + return $this->getSharedComponent()->getScheme(); + } + + return $this->scheme; + } + + public function setScheme(string $scheme): self + { + if ($scheme === '' || $scheme === 'major' || $scheme === 'minor') { + if ($this->isSupervisor) { + $styleArray = $this->getStyleArray(['scheme' => $scheme]); + $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); + } else { + $this->scheme = $scheme; + } + } + + return $this; + } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php index de3666ae1d6..41a17151d37 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Style\NumberFormat; use PhpOffice\PhpSpreadsheet\Calculation\Calculation; +use PhpOffice\PhpSpreadsheet\Reader\Xls\Color\BIFF8; use PhpOffice\PhpSpreadsheet\RichText\RichText; use PhpOffice\PhpSpreadsheet\Style\Color; use PhpOffice\PhpSpreadsheet\Style\NumberFormat; @@ -67,14 +68,19 @@ class Formatter // 3 sections: [POSITIVE/TEXT] [NEGATIVE] [ZERO] // 4 sections: [POSITIVE] [NEGATIVE] [ZERO] [TEXT] $sectionCount = count($sections); - $color_regex = '/\\[(' . implode('|', Color::NAMED_COLORS) . ')\\]/mui'; + // Colour could be a named colour, or a numeric index entry in the colour-palette + $color_regex = '/\\[(' . implode('|', Color::NAMED_COLORS) . '|color\\s*(\\d+))\\]/mui'; $cond_regex = '/\\[(>|>=|<|<=|=|<>)([+-]?\\d+([.]\\d+)?)\\]/'; $colors = ['', '', '', '', '']; $conditionOperations = ['', '', '', '', '']; $conditionComparisonValues = [0, 0, 0, 0, 0]; for ($idx = 0; $idx < $sectionCount; ++$idx) { if (preg_match($color_regex, $sections[$idx], $matches)) { - $colors[$idx] = $matches[0]; + if (isset($matches[2])) { + $colors[$idx] = '#' . BIFF8::lookup((int) $matches[2] + 7)['rgb']; + } else { + $colors[$idx] = $matches[0]; + } $sections[$idx] = (string) preg_replace($color_regex, '', $sections[$idx]); } if (preg_match($cond_regex, $sections[$idx], $matches)) { @@ -170,10 +176,11 @@ class Formatter $format = (string) preg_replace('/_.?/ui', ' ', $format); // Let's begin inspecting the format and converting the value to a formatted string - // Check for date/time characters (not inside quotes) if ( - (preg_match('/(\[\$[A-Z]*-[0-9A-F]*\])*[hmsdy](?=(?:[^"]|"[^"]*")*$)/miu', $format)) && - (preg_match('/0(?![^\[]*\])/miu', $format) === 0) + // Check for date/time characters (not inside quotes) + (preg_match('/(\[\$[A-Z]*-[0-9A-F]*\])*[hmsdy](?=(?:[^"]|"[^"]*")*$)/miu', $format)) + // A date/time with a decimal time shouldn't have a digit placeholder before the decimal point + && (preg_match('/[0\?#]\.(?![^\[]*\])/miu', $format) === 0) ) { // datetime format $value = DateFormatter::format($value, $format); @@ -194,8 +201,6 @@ class Formatter $value = $writerInstance->$function($value, $colors); } - $value = str_replace(chr(0x00), '.', $value); - - return $value; + return str_replace(chr(0x00), '.', $value); } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Accounting.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Accounting.php index a138ab7f1dd..c30028601e0 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Accounting.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Accounting.php @@ -89,13 +89,13 @@ class Accounting extends Currency ( $this->currencySymbolPosition === self::LEADING_SYMBOL && $this->currencySymbolSpacing === self::SYMBOL_WITH_SPACING - ) ? ' ' : '', + ) ? "\u{a0}" : '', $this->thousandsSeparator ? '#,##' : null, $this->decimals > 0 ? '.' . str_repeat('0', $this->decimals) : null, ( $this->currencySymbolPosition === self::TRAILING_SYMBOL && $this->currencySymbolSpacing === self::SYMBOL_WITH_SPACING - ) ? ' ' : '', + ) ? "\u{a0}" : '', $this->currencySymbolPosition === self::TRAILING_SYMBOL ? $this->formatCurrencyCode() : null ); } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Date.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Date.php new file mode 100644 index 00000000000..61ac117b79c --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Date.php @@ -0,0 +1,125 @@ +separators = $this->padSeparatorArray( + is_array($separators) ? $separators : [$separators], + count($formatBlocks) - 1 + ); + $this->formatBlocks = array_map([$this, 'mapFormatBlocks'], $formatBlocks); + } + + private function mapFormatBlocks(string $value): string + { + // Any date masking codes are returned as lower case values + if (in_array(mb_strtolower($value), self::DATE_BLOCKS, true)) { + return mb_strtolower($value); + } + + // Wrap any string literals in quotes, so that they're clearly defined as string literals + return $this->wrapLiteral($value); + } + + public function format(): string + { + return implode('', array_map([$this, 'intersperse'], $this->formatBlocks, $this->separators)); + } +} diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTime.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTime.php new file mode 100644 index 00000000000..292c1efc9d8 --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTime.php @@ -0,0 +1,50 @@ + + */ + protected array $formatBlocks; + + /** + * @param null|string|string[] $separators + * If you want to use only a single format block, then pass a null as the separator argument + * @param DateTimeWizard|string ...$formatBlocks + */ + public function __construct($separators, ...$formatBlocks) + { + $this->separators = $this->padSeparatorArray( + is_array($separators) ? $separators : [$separators], + count($formatBlocks) - 1 + ); + $this->formatBlocks = array_map([$this, 'mapFormatBlocks'], $formatBlocks); + } + + /** + * @param DateTimeWizard|string $value + */ + private function mapFormatBlocks($value): string + { + // Any date masking codes are returned as lower case values + if (is_object($value)) { + // We can't explicitly test for Stringable until PHP >= 8.0 + return $value; + } + + // Wrap any string literals in quotes, so that they're clearly defined as string literals + return $this->wrapLiteral($value); + } + + public function format(): string + { + return implode('', array_map([$this, 'intersperse'], $this->formatBlocks, $this->separators)); + } +} diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTimeWizard.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTimeWizard.php new file mode 100644 index 00000000000..b14a6190fb7 --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/DateTimeWizard.php @@ -0,0 +1,44 @@ += "; + + protected function padSeparatorArray(array $separators, int $count): array + { + $lastSeparator = array_pop($separators); + + return $separators + array_fill(0, $count, $lastSeparator); + } + + protected function escapeSingleCharacter(string $value): string + { + if (strpos(self::NO_ESCAPING_NEEDED, $value) !== false) { + return $value; + } + + return "\\{$value}"; + } + + protected function wrapLiteral(string $value): string + { + if (mb_strlen($value, 'UTF-8') === 1) { + return $this->escapeSingleCharacter($value); + } + + // Wrap any other string literals in quotes, so that they're clearly defined as string literals + return '"' . str_replace('"', '""', $value) . '"'; + } + + protected function intersperse(string $formatBlock, ?string $separator): string + { + return "{$formatBlock}{$separator}"; + } + + public function __toString(): string + { + return $this->format(); + } +} diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Duration.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Duration.php new file mode 100644 index 00000000000..b81f77acb78 --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Duration.php @@ -0,0 +1,153 @@ + self::DAYS_DURATION, + self::HOURS_DURATION => self::HOURS_SHORT, + self::MINUTES_DURATION => self::MINUTES_LONG, + self::SECONDS_DURATION => self::SECONDS_LONG, + ]; + + protected const DURATION_DEFAULTS = [ + self::HOURS_LONG => self::HOURS_DURATION, + self::HOURS_SHORT => self::HOURS_DURATION, + self::MINUTES_LONG => self::MINUTES_DURATION, + self::MINUTES_SHORT => self::MINUTES_DURATION, + self::SECONDS_LONG => self::SECONDS_DURATION, + self::SECONDS_SHORT => self::SECONDS_DURATION, + ]; + + public const SEPARATOR_COLON = ':'; + public const SEPARATOR_SPACE_NONBREAKING = "\u{a0}"; + public const SEPARATOR_SPACE = ' '; + + public const DURATION_DEFAULT = [ + self::HOURS_DURATION, + self::MINUTES_LONG, + self::SECONDS_LONG, + ]; + + /** + * @var string[] + */ + protected array $separators; + + /** + * @var string[] + */ + protected array $formatBlocks; + + protected bool $durationIsSet = false; + + /** + * @param null|string|string[] $separators + * If you want to use the same separator for all format blocks, then it can be passed as a string literal; + * if you wish to use different separators, then they should be passed as an array. + * If you want to use only a single format block, then pass a null as the separator argument + */ + public function __construct($separators = self::SEPARATOR_COLON, string ...$formatBlocks) + { + $separators ??= self::SEPARATOR_COLON; + $formatBlocks = (count($formatBlocks) === 0) ? self::DURATION_DEFAULT : $formatBlocks; + + $this->separators = $this->padSeparatorArray( + is_array($separators) ? $separators : [$separators], + count($formatBlocks) - 1 + ); + $this->formatBlocks = array_map([$this, 'mapFormatBlocks'], $formatBlocks); + + if ($this->durationIsSet === false) { + // We need at least one duration mask, so if none has been set we change the first mask element + // to a duration. + $this->formatBlocks[0] = self::DURATION_DEFAULTS[mb_strtolower($this->formatBlocks[0])]; + } + } + + private function mapFormatBlocks(string $value): string + { + // Any duration masking codes are returned as lower case values + if (in_array(mb_strtolower($value), self::DURATION_BLOCKS, true)) { + if (array_key_exists(mb_strtolower($value), self::DURATION_MASKS)) { + if ($this->durationIsSet) { + // We should only have a single duration mask, the first defined in the mask set, + // so convert any additional duration masks to standard time masks. + $value = self::DURATION_MASKS[mb_strtolower($value)]; + } + $this->durationIsSet = true; + } + + return mb_strtolower($value); + } + + // Wrap any string literals in quotes, so that they're clearly defined as string literals + return $this->wrapLiteral($value); + } + + public function format(): string + { + return implode('', array_map([$this, 'intersperse'], $this->formatBlocks, $this->separators)); + } +} diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Time.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Time.php new file mode 100644 index 00000000000..64b9104a69f --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Time.php @@ -0,0 +1,105 @@ +separators = $this->padSeparatorArray( + is_array($separators) ? $separators : [$separators], + count($formatBlocks) - 1 + ); + $this->formatBlocks = array_map([$this, 'mapFormatBlocks'], $formatBlocks); + } + + private function mapFormatBlocks(string $value): string + { + // Any date masking codes are returned as lower case values + // except for AM/PM, which is set to uppercase + if (in_array(mb_strtolower($value), self::TIME_BLOCKS, true)) { + return mb_strtolower($value); + } elseif (mb_strtoupper($value) === self::MORNING_AFTERNOON) { + return mb_strtoupper($value); + } + + // Wrap any string literals in quotes, so that they're clearly defined as string literals + return $this->wrapLiteral($value); + } + + public function format(): string + { + return implode('', array_map([$this, 'intersperse'], $this->formatBlocks, $this->separators)); + } +} diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/RgbTint.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/RgbTint.php new file mode 100644 index 00000000000..582ae483974 --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/RgbTint.php @@ -0,0 +1,175 @@ += 0.0) ? $hue : (1.0 + $hue); + } + + /** + * Convert red/green/blue to HLSMAX-based hue/luminance/saturation. + * + * @return int[] + */ + private static function rgbToMsHls(int $red, int $green, int $blue): array + { + $red01 = $red / self::RGBMAX; + $green01 = $green / self::RGBMAX; + $blue01 = $blue / self::RGBMAX; + [$hue, $luminance, $saturation] = self::rgbToHls($red01, $green01, $blue01); + + return [ + (int) round($hue * self::HLSMAX), + (int) round($luminance * self::HLSMAX), + (int) round($saturation * self::HLSMAX), + ]; + } + + /** + * Converts HLSMAX based HLS values to rgb values in the range (0,1). + * + * @return float[] + */ + private static function msHlsToRgb(int $hue, int $lightness, int $saturation): array + { + return self::hlsToRgb($hue / self::HLSMAX, $lightness / self::HLSMAX, $saturation / self::HLSMAX); + } + + /** + * Tints HLSMAX based luminance. + * + * @see http://ciintelligence.blogspot.co.uk/2012/02/converting-excel-theme-color-and-tint.html + */ + private static function tintLuminance(float $tint, float $luminance): int + { + if ($tint < 0) { + return (int) round($luminance * (1.0 + $tint)); + } + + return (int) round($luminance * (1.0 - $tint) + (self::HLSMAX - self::HLSMAX * (1.0 - $tint))); + } + + /** + * Return result of tinting supplied rgb as 6 hex digits. + */ + public static function rgbAndTintToRgb(int $red, int $green, int $blue, float $tint): string + { + [$hue, $luminance, $saturation] = self::rgbToMsHls($red, $green, $blue); + [$red, $green, $blue] = self::msHlsToRgb($hue, self::tintLuminance($tint, $luminance), $saturation); + + return sprintf( + '%02X%02X%02X', + (int) round($red * self::RGBMAX), + (int) round($green * self::RGBMAX), + (int) round($blue * self::RGBMAX) + ); + } +} diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Style.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Style.php index be70639eb2c..9309830bfa1 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Style.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Style/Style.php @@ -2,7 +2,10 @@ namespace PhpOffice\PhpSpreadsheet\Style; +use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; +use PhpOffice\PhpSpreadsheet\Exception; +use PhpOffice\PhpSpreadsheet\Shared\StringHelper; use PhpOffice\PhpSpreadsheet\Spreadsheet; class Style extends Supervisor @@ -122,7 +125,7 @@ class Style extends Supervisor public function getSharedComponent(): self { $activeSheet = $this->getActiveSheet(); - $selectedCell = $this->getActiveCell(); // e.g. 'A1' + $selectedCell = Functions::trimSheetFromCellReference($this->getActiveCell()); // e.g. 'A1' if ($activeSheet->cellExists($selectedCell)) { $xfIndex = $activeSheet->getCell($selectedCell)->getXfIndex(); @@ -203,8 +206,15 @@ class Style extends Supervisor if ($this->isSupervisor) { $pRange = $this->getSelectedCells(); - // Uppercase coordinate + // Uppercase coordinate and strip any Worksheet reference from the selected range $pRange = strtoupper($pRange); + if (strpos($pRange, '!') !== false) { + $pRangeWorksheet = StringHelper::strToUpper(trim(substr($pRange, 0, (int) strrpos($pRange, '!')), "'")); + if ($pRangeWorksheet !== '' && StringHelper::strToUpper($this->getActiveSheet()->getTitle()) !== $pRangeWorksheet) { + throw new Exception('Invalid Worksheet for specified Range'); + } + $pRange = strtoupper(Functions::trimSheetFromCellReference($pRange)); + } // Is it a cell range or a single cell? if (strpos($pRange, ':') === false) { diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Theme.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Theme.php new file mode 100644 index 00000000000..ab101f01ee0 --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Theme.php @@ -0,0 +1,269 @@ + '000000', + 'lt1' => 'FFFFFF', + 'dk2' => '44546A', + 'lt2' => 'E7E6E6', + 'accent1' => '4472C4', + 'accent2' => 'ED7D31', + 'accent3' => 'A5A5A5', + 'accent4' => 'FFC000', + 'accent5' => '5B9BD5', + 'accent6' => '70AD47', + 'hlink' => '0563C1', + 'folHlink' => '954F72', + ]; + + public const COLOR_SCHEME_2007_2010_NAME = 'Office 2007-2010'; + public const COLOR_SCHEME_2007_2010 = [ + 'dk1' => '000000', + 'lt1' => 'FFFFFF', + 'dk2' => '1F497D', + 'lt2' => 'EEECE1', + 'accent1' => '4F81BD', + 'accent2' => 'C0504D', + 'accent3' => '9BBB59', + 'accent4' => '8064A2', + 'accent5' => '4BACC6', + 'accent6' => 'F79646', + 'hlink' => '0000FF', + 'folHlink' => '800080', + ]; + + /** @var string[] */ + private $themeColors = self::COLOR_SCHEME_2007_2010; + + /** @var string */ + private $majorFontLatin = 'Cambria'; + + /** @var string */ + private $majorFontEastAsian = ''; + + /** @var string */ + private $majorFontComplexScript = ''; + + /** @var string */ + private $minorFontLatin = 'Calibri'; + + /** @var string */ + private $minorFontEastAsian = ''; + + /** @var string */ + private $minorFontComplexScript = ''; + + /** + * Map of Major (header) fonts to write. + * + * @var string[] + */ + private $majorFontSubstitutions = self::FONTS_TIMES_SUBSTITUTIONS; + + /** + * Map of Minor (body) fonts to write. + * + * @var string[] + */ + private $minorFontSubstitutions = self::FONTS_ARIAL_SUBSTITUTIONS; + + public const FONTS_TIMES_SUBSTITUTIONS = [ + 'Jpan' => 'MS Pゴシック', + 'Hang' => '맑은 고딕', + 'Hans' => '宋体', + 'Hant' => '新細明體', + 'Arab' => 'Times New Roman', + 'Hebr' => 'Times New Roman', + 'Thai' => 'Tahoma', + 'Ethi' => 'Nyala', + 'Beng' => 'Vrinda', + 'Gujr' => 'Shruti', + 'Khmr' => 'MoolBoran', + 'Knda' => 'Tunga', + 'Guru' => 'Raavi', + 'Cans' => 'Euphemia', + 'Cher' => 'Plantagenet Cherokee', + 'Yiii' => 'Microsoft Yi Baiti', + 'Tibt' => 'Microsoft Himalaya', + 'Thaa' => 'MV Boli', + 'Deva' => 'Mangal', + 'Telu' => 'Gautami', + 'Taml' => 'Latha', + 'Syrc' => 'Estrangelo Edessa', + 'Orya' => 'Kalinga', + 'Mlym' => 'Kartika', + 'Laoo' => 'DokChampa', + 'Sinh' => 'Iskoola Pota', + 'Mong' => 'Mongolian Baiti', + 'Viet' => 'Times New Roman', + 'Uigh' => 'Microsoft Uighur', + 'Geor' => 'Sylfaen', + ]; + + public const FONTS_ARIAL_SUBSTITUTIONS = [ + 'Jpan' => 'MS Pゴシック', + 'Hang' => '맑은 고딕', + 'Hans' => '宋体', + 'Hant' => '新細明體', + 'Arab' => 'Arial', + 'Hebr' => 'Arial', + 'Thai' => 'Tahoma', + 'Ethi' => 'Nyala', + 'Beng' => 'Vrinda', + 'Gujr' => 'Shruti', + 'Khmr' => 'DaunPenh', + 'Knda' => 'Tunga', + 'Guru' => 'Raavi', + 'Cans' => 'Euphemia', + 'Cher' => 'Plantagenet Cherokee', + 'Yiii' => 'Microsoft Yi Baiti', + 'Tibt' => 'Microsoft Himalaya', + 'Thaa' => 'MV Boli', + 'Deva' => 'Mangal', + 'Telu' => 'Gautami', + 'Taml' => 'Latha', + 'Syrc' => 'Estrangelo Edessa', + 'Orya' => 'Kalinga', + 'Mlym' => 'Kartika', + 'Laoo' => 'DokChampa', + 'Sinh' => 'Iskoola Pota', + 'Mong' => 'Mongolian Baiti', + 'Viet' => 'Arial', + 'Uigh' => 'Microsoft Uighur', + 'Geor' => 'Sylfaen', + ]; + + public function getThemeColors(): array + { + return $this->themeColors; + } + + public function setThemeColor(string $key, string $value): self + { + $this->themeColors[$key] = $value; + + return $this; + } + + public function getThemeColorName(): string + { + return $this->themeColorName; + } + + public function setThemeColorName(string $name, ?array $themeColors = null): self + { + $this->themeColorName = $name; + if ($name === self::COLOR_SCHEME_2007_2010_NAME) { + $themeColors = $themeColors ?? self::COLOR_SCHEME_2007_2010; + } elseif ($name === self::COLOR_SCHEME_2013_PLUS_NAME) { + $themeColors = $themeColors ?? self::COLOR_SCHEME_2013_PLUS; + } + if ($themeColors !== null) { + $this->themeColors = $themeColors; + } + + return $this; + } + + public function getMajorFontLatin(): string + { + return $this->majorFontLatin; + } + + public function getMajorFontEastAsian(): string + { + return $this->majorFontEastAsian; + } + + public function getMajorFontComplexScript(): string + { + return $this->majorFontComplexScript; + } + + public function getMajorFontSubstitutions(): array + { + return $this->majorFontSubstitutions; + } + + /** @param null|array $substitutions */ + public function setMajorFontValues(?string $latin, ?string $eastAsian, ?string $complexScript, $substitutions): self + { + if (!empty($latin)) { + $this->majorFontLatin = $latin; + } + if ($eastAsian !== null) { + $this->majorFontEastAsian = $eastAsian; + } + if ($complexScript !== null) { + $this->majorFontComplexScript = $complexScript; + } + if ($substitutions !== null) { + $this->majorFontSubstitutions = $substitutions; + } + + return $this; + } + + public function getMinorFontLatin(): string + { + return $this->minorFontLatin; + } + + public function getMinorFontEastAsian(): string + { + return $this->minorFontEastAsian; + } + + public function getMinorFontComplexScript(): string + { + return $this->minorFontComplexScript; + } + + public function getMinorFontSubstitutions(): array + { + return $this->minorFontSubstitutions; + } + + /** @param null|array $substitutions */ + public function setMinorFontValues(?string $latin, ?string $eastAsian, ?string $complexScript, $substitutions): self + { + if (!empty($latin)) { + $this->minorFontLatin = $latin; + } + if ($eastAsian !== null) { + $this->minorFontEastAsian = $eastAsian; + } + if ($complexScript !== null) { + $this->minorFontComplexScript = $complexScript; + } + if ($substitutions !== null) { + $this->minorFontSubstitutions = $substitutions; + } + + return $this; + } + + public function getThemeFontName(): string + { + return $this->themeFontName; + } + + public function setThemeFontName(?string $name): self + { + if (!empty($name)) { + $this->themeFontName = $name; + } + + return $this; + } +} diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/AutoFilter.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/AutoFilter.php index d6041985d59..cbc4ff65fec 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/AutoFilter.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/AutoFilter.php @@ -321,7 +321,7 @@ class AutoFilter * * @return bool */ - private static function filterTestInSimpleDataSet($cellValue, $dataSet) + protected static function filterTestInSimpleDataSet($cellValue, $dataSet) { $dataSetValues = $dataSet['filterValues']; $blanks = $dataSet['blanks']; @@ -340,7 +340,7 @@ class AutoFilter * * @return bool */ - private static function filterTestInDateGroupSet($cellValue, $dataSet) + protected static function filterTestInDateGroupSet($cellValue, $dataSet) { $dateSet = $dataSet['filterValues']; $blanks = $dataSet['blanks']; @@ -384,7 +384,7 @@ class AutoFilter * * @return bool */ - private static function filterTestInCustomDataSet($cellValue, $ruleSet) + protected static function filterTestInCustomDataSet($cellValue, $ruleSet) { /** @var array[] */ $dataSet = $ruleSet['filterRules']; @@ -509,7 +509,7 @@ class AutoFilter * * @return bool */ - private static function filterTestInPeriodDateSet($cellValue, $monthSet) + protected static function filterTestInPeriodDateSet($cellValue, $monthSet) { // Blank cells are always ignored, so return a FALSE if (($cellValue == '') || ($cellValue === null)) { diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/PageMargins.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/PageMargins.php index 34e1145e04a..d51023fcc1c 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/PageMargins.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/PageMargins.php @@ -197,21 +197,6 @@ class PageMargins return $this; } - /** - * Implement PHP __clone to create a deep clone, not just a shallow copy. - */ - public function __clone() - { - $vars = get_object_vars($this); - foreach ($vars as $key => $value) { - if (is_object($value)) { - $this->$key = clone $value; - } else { - $this->$key = $value; - } - } - } - public static function fromCentimeters(float $value): float { return $value / 2.54; diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/PageSetup.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/PageSetup.php index 22c99ff3b0b..72c8958c8b3 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/PageSetup.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/PageSetup.php @@ -885,19 +885,4 @@ class PageSetup return $this; } - - /** - * Implement PHP __clone to create a deep clone, not just a shallow copy. - */ - public function __clone() - { - $vars = get_object_vars($this); - foreach ($vars as $key => $value) { - if (is_object($value)) { - $this->$key = clone $value; - } else { - $this->$key = $value; - } - } - } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/SheetView.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/SheetView.php index 13464c9973c..697f11c2ae8 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/SheetView.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/SheetView.php @@ -175,19 +175,4 @@ class SheetView return $this; } - - /** - * Implement PHP __clone to create a deep clone, not just a shallow copy. - */ - public function __clone() - { - $vars = get_object_vars($this); - foreach ($vars as $key => $value) { - if (is_object($value)) { - $this->$key = clone $value; - } else { - $this->$key = $value; - } - } - } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table.php index dc2a4f8a521..1bc8dff45f5 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table.php @@ -180,7 +180,7 @@ class Table private function updateStructuredReferencesInCells(Worksheet $worksheet, string $newName): void { - $pattern = '/' . preg_quote($this->name) . '\[/mui'; + $pattern = '/' . preg_quote($this->name, '/') . '\[/mui'; foreach ($worksheet->getCoordinates(false) as $coordinate) { $cell = $worksheet->getCell($coordinate); @@ -196,7 +196,7 @@ class Table private function updateStructuredReferencesInNamedFormulae(Spreadsheet $spreadsheet, string $newName): void { - $pattern = '/' . preg_quote($this->name) . '\[/mui'; + $pattern = '/' . preg_quote($this->name, '/') . '\[/mui'; foreach ($spreadsheet->getNamedFormulae() as $namedFormula) { $formula = $namedFormula->getValue(); diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table/Column.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table/Column.php index 30630c0d463..32dd4c4f838 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table/Column.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Table/Column.php @@ -225,7 +225,7 @@ class Column private static function updateStructuredReferencesInCells(Worksheet $worksheet, string $oldTitle, string $newTitle): void { - $pattern = '/\[(@?)' . preg_quote($oldTitle) . '\]/mui'; + $pattern = '/\[(@?)' . preg_quote($oldTitle, '/') . '\]/mui'; foreach ($worksheet->getCoordinates(false) as $coordinate) { $cell = $worksheet->getCell($coordinate); @@ -241,7 +241,7 @@ class Column private static function updateStructuredReferencesInNamedFormulae(Spreadsheet $spreadsheet, string $oldTitle, string $newTitle): void { - $pattern = '/\[(@?)' . preg_quote($oldTitle) . '\]/mui'; + $pattern = '/\[(@?)' . preg_quote($oldTitle, '/') . '\]/mui'; foreach ($spreadsheet->getNamedFormulae() as $namedFormula) { $formula = $namedFormula->getValue(); diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Validations.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Validations.php index aab3aae4478..42ba566c6c0 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Validations.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Validations.php @@ -53,6 +53,9 @@ class Validations return self::validateCellRange($cellRange); } + private const SETMAXROW = '${1}1:${2}' . AddressRange::MAX_ROW; + private const SETMAXCOL = 'A${1}:' . AddressRange::MAX_COLUMN . '${2}'; + /** * Validate a cell range. * @@ -69,7 +72,7 @@ class Validations // or Row ranges like '1:3' to 'A1:XFD3' $addressRange = (string) preg_replace( ['/^([A-Z]+):([A-Z]+)$/i', '/^(\\d+):(\\d+)$/'], - ['${1}1:${2}1048576', 'A${1}:XFD${2}'], + [self::SETMAXROW, self::SETMAXCOL], $addressRange ); diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Worksheet.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Worksheet.php index cc0e05b6999..29221e9910d 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -543,9 +543,18 @@ class Worksheet implements IComparable */ public function getColumnDimensions() { + /** @var callable */ + $callable = [self::class, 'columnDimensionCompare']; + uasort($this->columnDimensions, $callable); + return $this->columnDimensions; } + private static function columnDimensionCompare(ColumnDimension $a, ColumnDimension $b): int + { + return $a->getColumnNumeric() - $b->getColumnNumeric(); + } + /** * Get default column dimension. * @@ -1806,9 +1815,15 @@ class Worksheet implements IComparable public function getBreaks() { $breaks = []; + /** @var callable */ + $compareFunction = [self::class, 'compareRowBreaks']; + uksort($this->rowBreaks, $compareFunction); foreach ($this->rowBreaks as $break) { $breaks[$break->getCoordinate()] = self::BREAK_ROW; } + /** @var callable */ + $compareFunction = [self::class, 'compareColumnBreaks']; + uksort($this->columnBreaks, $compareFunction); foreach ($this->columnBreaks as $break) { $breaks[$break->getCoordinate()] = self::BREAK_COLUMN; } @@ -1823,16 +1838,40 @@ class Worksheet implements IComparable */ public function getRowBreaks() { + /** @var callable */ + $compareFunction = [self::class, 'compareRowBreaks']; + uksort($this->rowBreaks, $compareFunction); + return $this->rowBreaks; } + protected static function compareRowBreaks(string $coordinate1, string $coordinate2): int + { + $row1 = Coordinate::indexesFromString($coordinate1)[1]; + $row2 = Coordinate::indexesFromString($coordinate2)[1]; + + return $row1 - $row2; + } + + protected static function compareColumnBreaks(string $coordinate1, string $coordinate2): int + { + $column1 = Coordinate::indexesFromString($coordinate1)[0]; + $column2 = Coordinate::indexesFromString($coordinate2)[0]; + + return $column1 - $column2; + } + /** - * Get row breaks. + * Get column breaks. * * @return PageBreak[] */ public function getColumnBreaks() { + /** @var callable */ + $compareFunction = [self::class, 'compareColumnBreaks']; + uksort($this->columnBreaks, $compareFunction); + return $this->columnBreaks; } @@ -2448,12 +2487,12 @@ class Worksheet implements IComparable /** * Insert a new row, updating all possible related data. * - * @param int $before Insert before this one - * @param int $numberOfRows Number of rows to insert + * @param int $before Insert before this row number + * @param int $numberOfRows Number of new rows to insert * * @return $this */ - public function insertNewRowBefore($before, $numberOfRows = 1) + public function insertNewRowBefore(int $before, int $numberOfRows = 1) { if ($before >= 1) { $objReferenceHelper = ReferenceHelper::getInstance(); @@ -2468,12 +2507,12 @@ class Worksheet implements IComparable /** * Insert a new column, updating all possible related data. * - * @param string $before Insert before this one, eg: 'A' - * @param int $numberOfColumns Number of columns to insert + * @param string $before Insert before this column Name, eg: 'A' + * @param int $numberOfColumns Number of new columns to insert * * @return $this */ - public function insertNewColumnBefore($before, $numberOfColumns = 1) + public function insertNewColumnBefore(string $before, int $numberOfColumns = 1) { if (!is_numeric($before)) { $objReferenceHelper = ReferenceHelper::getInstance(); @@ -2488,12 +2527,12 @@ class Worksheet implements IComparable /** * Insert a new column, updating all possible related data. * - * @param int $beforeColumnIndex Insert before this one (numeric column coordinate of the cell) - * @param int $numberOfColumns Number of columns to insert + * @param int $beforeColumnIndex Insert before this column ID (numeric column coordinate of the cell) + * @param int $numberOfColumns Number of new columns to insert * * @return $this */ - public function insertNewColumnBeforeByIndex($beforeColumnIndex, $numberOfColumns = 1) + public function insertNewColumnBeforeByIndex(int $beforeColumnIndex, int $numberOfColumns = 1) { if ($beforeColumnIndex >= 1) { return $this->insertNewColumnBefore(Coordinate::stringFromColumnIndex($beforeColumnIndex), $numberOfColumns); @@ -2505,12 +2544,12 @@ class Worksheet implements IComparable /** * Delete a row, updating all possible related data. * - * @param int $row Remove starting with this one + * @param int $row Remove rows, starting with this row number * @param int $numberOfRows Number of rows to remove * * @return $this */ - public function removeRow($row, $numberOfRows = 1) + public function removeRow(int $row, int $numberOfRows = 1) { if ($row < 1) { throw new Exception('Rows to be deleted should at least start from row 1.'); @@ -2561,12 +2600,12 @@ class Worksheet implements IComparable /** * Remove a column, updating all possible related data. * - * @param string $column Remove starting with this one, eg: 'A' + * @param string $column Remove columns starting with this column name, eg: 'A' * @param int $numberOfColumns Number of columns to remove * * @return $this */ - public function removeColumn($column, $numberOfColumns = 1) + public function removeColumn(string $column, int $numberOfColumns = 1) { if (is_numeric($column)) { throw new Exception('Column references should not be numeric.'); @@ -2623,12 +2662,12 @@ class Worksheet implements IComparable /** * Remove a column, updating all possible related data. * - * @param int $columnIndex Remove starting with this one (numeric column coordinate of the cell) + * @param int $columnIndex Remove starting with this column Index (numeric column coordinate) * @param int $numColumns Number of columns to remove * * @return $this */ - public function removeColumnByIndex($columnIndex, $numColumns = 1) + public function removeColumnByIndex(int $columnIndex, int $numColumns = 1) { if ($columnIndex >= 1) { return $this->removeColumn(Coordinate::stringFromColumnIndex($columnIndex), $numColumns); @@ -2988,21 +3027,58 @@ class Worksheet implements IComparable return $this; } + /** + * @param mixed $nullValue + * + * @throws Exception + * @throws \PhpOffice\PhpSpreadsheet\Calculation\Exception + * + * @return mixed + */ + protected function cellToArray(Cell $cell, bool $calculateFormulas, bool $formatData, $nullValue) + { + $returnValue = $nullValue; + + if ($cell->getValue() !== null) { + if ($cell->getValue() instanceof RichText) { + $returnValue = $cell->getValue()->getPlainText(); + } else { + $returnValue = ($calculateFormulas) ? $cell->getCalculatedValue() : $cell->getValue(); + } + + if ($formatData) { + $style = $this->getParentOrThrow()->getCellXfByIndex($cell->getXfIndex()); + $returnValue = NumberFormat::toFormattedString( + $returnValue, + $style->getNumberFormat()->getFormatCode() ?? NumberFormat::FORMAT_GENERAL + ); + } + } + + return $returnValue; + } + /** * Create array from a range of cells. * - * @param string $range Range of cells (i.e. "A1:B10"), or just one cell (i.e. "A1") * @param mixed $nullValue Value returned in the array entry if a cell doesn't exist * @param bool $calculateFormulas Should formulas be calculated? * @param bool $formatData Should formatting be applied to cell values? * @param bool $returnCellRef False - Return a simple array of rows and columns indexed by number counting from zero - * True - Return rows and columns indexed by their actual row and column IDs - * - * @return array + * True - Return rows and columns indexed by their actual row and column IDs + * @param bool $ignoreHidden False - Return values for rows/columns even if they are defined as hidden. + * True - Don't return values for rows/columns that are defined as hidden. */ - public function rangeToArray($range, $nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) - { - // Returnvalue + public function rangeToArray( + string $range, + $nullValue = null, + bool $calculateFormulas = true, + bool $formatData = true, + bool $returnCellRef = false, + bool $ignoreHidden = false + ): array { + $range = Validations::validateCellOrCellRange($range); + $returnValue = []; // Identify the range that we need to extract from the worksheet [$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($range); @@ -3015,42 +3091,23 @@ class Worksheet implements IComparable // Loop through rows $r = -1; for ($row = $minRow; $row <= $maxRow; ++$row) { - $rRef = $returnCellRef ? $row : ++$r; + if (($ignoreHidden === true) && ($this->getRowDimension($row)->getVisible() === false)) { + continue; + } + $rowRef = $returnCellRef ? $row : ++$r; $c = -1; // Loop through columns in the current row - for ($col = $minCol; $col != $maxCol; ++$col) { - $cRef = $returnCellRef ? $col : ++$c; + for ($col = $minCol; $col !== $maxCol; ++$col) { + if (($ignoreHidden === true) && ($this->getColumnDimension($col)->getVisible() === false)) { + continue; + } + $columnRef = $returnCellRef ? $col : ++$c; // Using getCell() will create a new cell if it doesn't already exist. We don't want that to happen // so we test and retrieve directly against cellCollection - $cell = $this->cellCollection->get($col . $row); - //if ($this->cellCollection->has($col . $row)) { + $cell = $this->cellCollection->get("{$col}{$row}"); + $returnValue[$rowRef][$columnRef] = $nullValue; if ($cell !== null) { - // Cell exists - if ($cell->getValue() !== null) { - if ($cell->getValue() instanceof RichText) { - $returnValue[$rRef][$cRef] = $cell->getValue()->getPlainText(); - } else { - if ($calculateFormulas) { - $returnValue[$rRef][$cRef] = $cell->getCalculatedValue(); - } else { - $returnValue[$rRef][$cRef] = $cell->getValue(); - } - } - - if ($formatData) { - $style = $this->getParentOrThrow()->getCellXfByIndex($cell->getXfIndex()); - $returnValue[$rRef][$cRef] = NumberFormat::toFormattedString( - $returnValue[$rRef][$cRef], - $style->getNumberFormat()->getFormatCode() ?? NumberFormat::FORMAT_GENERAL - ); - } - } else { - // Cell holds a NULL - $returnValue[$rRef][$cRef] = $nullValue; - } - } else { - // Cell doesn't exist - $returnValue[$rRef][$cRef] = $nullValue; + $returnValue[$rowRef][$columnRef] = $this->cellToArray($cell, $calculateFormulas, $formatData, $nullValue); } } } @@ -3102,12 +3159,18 @@ class Worksheet implements IComparable * @param bool $calculateFormulas Should formulas be calculated? * @param bool $formatData Should formatting be applied to cell values? * @param bool $returnCellRef False - Return a simple array of rows and columns indexed by number counting from zero - * True - Return rows and columns indexed by their actual row and column IDs - * - * @return array + * True - Return rows and columns indexed by their actual row and column IDs + * @param bool $ignoreHidden False - Return values for rows/columns even if they are defined as hidden. + * True - Don't return values for rows/columns that are defined as hidden. */ - public function namedRangeToArray(string $definedName, $nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) - { + public function namedRangeToArray( + string $definedName, + $nullValue = null, + bool $calculateFormulas = true, + bool $formatData = true, + bool $returnCellRef = false, + bool $ignoreHidden = false + ): array { $retVal = []; $namedRange = $this->validateNamedRange($definedName); if ($namedRange !== null) { @@ -3115,7 +3178,7 @@ class Worksheet implements IComparable $cellRange = str_replace('$', '', $cellRange); $workSheet = $namedRange->getWorksheet(); if ($workSheet !== null) { - $retVal = $workSheet->rangeToArray($cellRange, $nullValue, $calculateFormulas, $formatData, $returnCellRef); + $retVal = $workSheet->rangeToArray($cellRange, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden); } } @@ -3129,12 +3192,17 @@ class Worksheet implements IComparable * @param bool $calculateFormulas Should formulas be calculated? * @param bool $formatData Should formatting be applied to cell values? * @param bool $returnCellRef False - Return a simple array of rows and columns indexed by number counting from zero - * True - Return rows and columns indexed by their actual row and column IDs - * - * @return array + * True - Return rows and columns indexed by their actual row and column IDs + * @param bool $ignoreHidden False - Return values for rows/columns even if they are defined as hidden. + * True - Don't return values for rows/columns that are defined as hidden. */ - public function toArray($nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) - { + public function toArray( + $nullValue = null, + bool $calculateFormulas = true, + bool $formatData = true, + bool $returnCellRef = false, + bool $ignoreHidden = false + ): array { // Garbage collect... $this->garbageCollect(); @@ -3143,7 +3211,7 @@ class Worksheet implements IComparable $maxRow = $this->getHighestRow(); // Return - return $this->rangeToArray('A1:' . $maxCol . $maxRow, $nullValue, $calculateFormulas, $formatData, $returnCellRef); + return $this->rangeToArray("A1:{$maxCol}{$maxRow}", $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden); } /** diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Html.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Html.php index c30bb30acfe..842998f9eb5 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Html.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Html.php @@ -7,9 +7,11 @@ use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Chart\Chart; +use PhpOffice\PhpSpreadsheet\Document\Properties; use PhpOffice\PhpSpreadsheet\RichText\RichText; use PhpOffice\PhpSpreadsheet\RichText\Run; use PhpOffice\PhpSpreadsheet\Settings; +use PhpOffice\PhpSpreadsheet\Shared\Date; use PhpOffice\PhpSpreadsheet\Shared\Drawing as SharedDrawing; use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheet\Shared\Font as SharedFont; @@ -342,13 +344,21 @@ class Html extends BaseWriter private static function generateMeta(?string $val, string $desc): string { - return $val + return ($val || $val === '0') ? (' ' . PHP_EOL) : ''; } public const BODY_LINE = ' ' . PHP_EOL; + private const CUSTOM_TO_META = [ + Properties::PROPERTY_TYPE_BOOLEAN => 'bool', + Properties::PROPERTY_TYPE_DATE => 'date', + Properties::PROPERTY_TYPE_FLOAT => 'float', + Properties::PROPERTY_TYPE_INTEGER => 'int', + Properties::PROPERTY_TYPE_STRING => 'string', + ]; + /** * Generate HTML header. * @@ -374,6 +384,36 @@ class Html extends BaseWriter $html .= self::generateMeta($properties->getCategory(), 'category'); $html .= self::generateMeta($properties->getCompany(), 'company'); $html .= self::generateMeta($properties->getManager(), 'manager'); + $html .= self::generateMeta($properties->getLastModifiedBy(), 'lastModifiedBy'); + $date = Date::dateTimeFromTimestamp((string) $properties->getCreated()); + $date->setTimeZone(Date::getDefaultOrLocalTimeZone()); + $html .= self::generateMeta($date->format(DATE_W3C), 'created'); + $date = Date::dateTimeFromTimestamp((string) $properties->getModified()); + $date->setTimeZone(Date::getDefaultOrLocalTimeZone()); + $html .= self::generateMeta($date->format(DATE_W3C), 'modified'); + + $customProperties = $properties->getCustomProperties(); + foreach ($customProperties as $customProperty) { + $propertyValue = $properties->getCustomPropertyValue($customProperty); + $propertyType = $properties->getCustomPropertyType($customProperty); + $propertyQualifier = self::CUSTOM_TO_META[$propertyType] ?? null; + if ($propertyQualifier !== null) { + if ($propertyType === Properties::PROPERTY_TYPE_BOOLEAN) { + $propertyValue = $propertyValue ? '1' : '0'; + } elseif ($propertyType === Properties::PROPERTY_TYPE_DATE) { + $date = Date::dateTimeFromTimestamp((string) $propertyValue); + $date->setTimeZone(Date::getDefaultOrLocalTimeZone()); + $propertyValue = $date->format(DATE_W3C); + } else { + $propertyValue = (string) $propertyValue; + } + $html .= self::generateMeta($propertyValue, "custom.$propertyQualifier.$customProperty"); + } + } + + if (!empty($properties->getHyperlinkBase())) { + $html .= ' ' . PHP_EOL; + } $html .= $includeStyles ? $this->generateStyles(true) : $this->generatePageDeclarations(true); @@ -693,7 +733,8 @@ class Html extends BaseWriter // max-width: 100% ensures that image doesnt overflow containing cell // width: X sets width of supplied image. // As a result, images bigger than cell will be contained and images smaller will not get stretched - $html .= '' . $filedesc . ''; + $html .= '' . $filedesc . ''; } } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Ods.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Ods.php index 872be52dee8..c9e0ba839fc 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Ods.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Ods.php @@ -12,7 +12,6 @@ use PhpOffice\PhpSpreadsheet\Writer\Ods\Settings; use PhpOffice\PhpSpreadsheet\Writer\Ods\Styles; use PhpOffice\PhpSpreadsheet\Writer\Ods\Thumbnails; use ZipStream\Exception\OverflowException; -use ZipStream\Option\Archive; use ZipStream\ZipStream; class Ods extends BaseWriter @@ -158,11 +157,7 @@ class Ods extends BaseWriter } // Create new ZIP stream - $options = new Archive(); - $options->setEnableZip64(false); - $options->setOutputStream($this->fileHandle); - - return new ZipStream(null, $options); + return ZipStream0::newZipStream($this->fileHandle); } /** diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Ods/Content.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Ods/Content.php index e931421afd9..e0a729ab836 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Ods/Content.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Ods/Content.php @@ -126,7 +126,16 @@ class Content extends WriterPart $objWriter->writeAttribute('table:name', $spreadsheet->getSheet($sheetIndex)->getTitle()); $objWriter->writeAttribute('table:style-name', Style::TABLE_STYLE_PREFIX . (string) ($sheetIndex + 1)); $objWriter->writeElement('office:forms'); + $lastColumn = 0; foreach ($spreadsheet->getSheet($sheetIndex)->getColumnDimensions() as $columnDimension) { + $thisColumn = $columnDimension->getColumnNumeric(); + $emptyColumns = $thisColumn - $lastColumn - 1; + if ($emptyColumns > 0) { + $objWriter->startElement('table:table-column'); + $objWriter->writeAttribute('table:number-columns-repeated', (string) $emptyColumns); + $objWriter->endElement(); + } + $lastColumn = $thisColumn; $objWriter->startElement('table:table-column'); $objWriter->writeAttribute( 'table:style-name', diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx.php index 07b790440a3..6ed12d4aa19 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx.php @@ -31,7 +31,6 @@ use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Workbook; use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Worksheet; use ZipArchive; use ZipStream\Exception\OverflowException; -use ZipStream\Option\Archive; use ZipStream\ZipStream; class Xlsx extends BaseWriter @@ -377,7 +376,7 @@ class Xlsx extends BaseWriter } // Add theme to ZIP file - $zipContent['xl/theme/theme1.xml'] = $this->getWriterPartTheme()->writeTheme(); + $zipContent['xl/theme/theme1.xml'] = $this->getWriterPartTheme()->writeTheme($this->spreadSheet); // Add string table to ZIP file $zipContent['xl/sharedStrings.xml'] = $this->getWriterPartStringTable()->writeStringTable($this->stringTable); @@ -546,11 +545,7 @@ class Xlsx extends BaseWriter $this->openFileHandle($filename); - $options = new Archive(); - $options->setEnableZip64(false); - $options->setOutputStream($this->fileHandle); - - $this->zip = new ZipStream(null, $options); + $this->zip = ZipStream0::newZipStream($this->fileHandle); $this->addZipFiles($zipContent); diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Chart.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Chart.php index 6465904ee8c..6d302aac4a3 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Chart.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Chart.php @@ -14,6 +14,7 @@ use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\Chart\TrendLine; use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Namespaces; use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; +use PhpOffice\PhpSpreadsheet\Style\Font; use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException; class Chart extends WriterPart @@ -109,12 +110,20 @@ class Chart extends WriterPart $objWriter->endElement(); $objWriter->endElement(); // c:chart + + $objWriter->startElement('c:spPr'); if ($chart->getNoFill()) { - $objWriter->startElement('c:spPr'); $objWriter->startElement('a:noFill'); $objWriter->endElement(); // a:noFill - $objWriter->endElement(); // c:spPr } + $fillColor = $chart->getFillColor(); + if ($fillColor->isUsable()) { + $this->writeColor($objWriter, $fillColor); + } + $borderLines = $chart->getBorderLines(); + $this->writeLineStyles($objWriter, $borderLines); + $this->writeEffects($objWriter, $borderLines); + $objWriter->endElement(); // c:spPr $this->writePrintSettings($objWriter); @@ -201,6 +210,17 @@ class Chart extends WriterPart $objWriter->writeAttribute('val', ($legend->getOverlay()) ? '1' : '0'); $objWriter->endElement(); + $objWriter->startElement('c:spPr'); + $fillColor = $legend->getFillColor(); + if ($fillColor->isUsable()) { + $this->writeColor($objWriter, $fillColor); + } + $borderLines = $legend->getBorderLines(); + $this->writeLineStyles($objWriter, $borderLines); + $this->writeEffects($objWriter, $borderLines); + $objWriter->endElement(); // c:spPr + + $legendText = $legend->getLegendText(); $objWriter->startElement('c:txPr'); $objWriter->startElement('a:bodyPr'); $objWriter->endElement(); @@ -213,17 +233,21 @@ class Chart extends WriterPart $objWriter->writeAttribute('rtl', '0'); $objWriter->startElement('a:defRPr'); - $objWriter->endElement(); - $objWriter->endElement(); + if ($legendText !== null) { + $this->writeColor($objWriter, $legendText->getFillColorObject()); + $this->writeEffects($objWriter, $legendText); + } + $objWriter->endElement(); // a:defRpr + $objWriter->endElement(); // a:pPr $objWriter->startElement('a:endParaRPr'); $objWriter->writeAttribute('lang', 'en-US'); - $objWriter->endElement(); + $objWriter->endElement(); // a:endParaRPr - $objWriter->endElement(); - $objWriter->endElement(); + $objWriter->endElement(); // a:p + $objWriter->endElement(); // c:txPr - $objWriter->endElement(); + $objWriter->endElement(); // c:legend } /** @@ -307,19 +331,26 @@ class Chart extends WriterPart $objWriter->startElement('c:hiLowLines'); $objWriter->endElement(); - $objWriter->startElement('c:upDownBars'); - - $objWriter->startElement('c:gapWidth'); - $objWriter->writeAttribute('val', '300'); - $objWriter->endElement(); - - $objWriter->startElement('c:upBars'); - $objWriter->endElement(); - - $objWriter->startElement('c:downBars'); - $objWriter->endElement(); - - $objWriter->endElement(); + $gapWidth = $plotArea->getGapWidth(); + $upBars = $plotArea->getUseUpBars(); + $downBars = $plotArea->getUseDownBars(); + if ($gapWidth !== null || $upBars || $downBars) { + $objWriter->startElement('c:upDownBars'); + if ($gapWidth !== null) { + $objWriter->startElement('c:gapWidth'); + $objWriter->writeAttribute('val', "$gapWidth"); + $objWriter->endElement(); + } + if ($upBars) { + $objWriter->startElement('c:upBars'); + $objWriter->endElement(); + } + if ($downBars) { + $objWriter->startElement('c:downBars'); + $objWriter->endElement(); + } + $objWriter->endElement(); // c:upDownBars + } } // Generate 3 unique numbers to use for axId values @@ -428,8 +459,8 @@ class Chart extends WriterPart } $objWriter->endElement(); // c:spPr } - $fontColor = $chartLayout->getLabelFontColor(); - if ($fontColor && $fontColor->isUsable()) { + $labelFont = $chartLayout->getLabelFont(); + if ($labelFont !== null) { $objWriter->startElement('c:txPr'); $objWriter->startElement('a:bodyPr'); @@ -445,14 +476,7 @@ class Chart extends WriterPart $objWriter->startElement('a:lstStyle'); $objWriter->endElement(); // a:lstStyle - - $objWriter->startElement('a:p'); - $objWriter->startElement('a:pPr'); - $objWriter->startElement('a:defRPr'); - $this->writeColor($objWriter, $fontColor); - $objWriter->endElement(); // a:defRPr - $objWriter->endElement(); // a:pPr - $objWriter->endElement(); // a:p + $this->writeLabelFont($objWriter, $labelFont, $chartLayout->getLabelEffects()); $objWriter->endElement(); // c:txPr } @@ -608,25 +632,24 @@ class Chart extends WriterPart } $textRotation = $yAxis->getAxisOptionsProperty('textRotation'); - if (is_numeric($textRotation)) { + $axisText = $yAxis->getAxisText(); + + if ($axisText !== null || is_numeric($textRotation)) { $objWriter->startElement('c:txPr'); $objWriter->startElement('a:bodyPr'); - $objWriter->writeAttribute('rot', Properties::angleToXml((float) $textRotation)); + if (is_numeric($textRotation)) { + $objWriter->writeAttribute('rot', Properties::angleToXml((float) $textRotation)); + } $objWriter->endElement(); // a:bodyPr $objWriter->startElement('a:lstStyle'); $objWriter->endElement(); // a:lstStyle - $objWriter->startElement('a:p'); - $objWriter->startElement('a:pPr'); - $objWriter->startElement('a:defRPr'); - $objWriter->endElement(); // a:defRPr - $objWriter->endElement(); // a:pPr - $objWriter->endElement(); // a:p + $this->writeLabelFont($objWriter, ($axisText === null) ? null : $axisText->getFont(), $axisText); $objWriter->endElement(); // c:txPr } $objWriter->startElement('c:spPr'); $this->writeColor($objWriter, $yAxis->getFillColorObject()); - $this->writeLineStyles($objWriter, $yAxis); + $this->writeLineStyles($objWriter, $yAxis, $yAxis->getNoFill()); $this->writeEffects($objWriter, $yAxis); $objWriter->endElement(); // spPr @@ -826,25 +849,26 @@ class Chart extends WriterPart } $textRotation = $xAxis->getAxisOptionsProperty('textRotation'); - if (is_numeric($textRotation)) { + $axisText = $xAxis->getAxisText(); + + if ($axisText !== null || is_numeric($textRotation)) { $objWriter->startElement('c:txPr'); $objWriter->startElement('a:bodyPr'); - $objWriter->writeAttribute('rot', Properties::angleToXml((float) $textRotation)); + if (is_numeric($textRotation)) { + $objWriter->writeAttribute('rot', Properties::angleToXml((float) $textRotation)); + } $objWriter->endElement(); // a:bodyPr $objWriter->startElement('a:lstStyle'); $objWriter->endElement(); // a:lstStyle - $objWriter->startElement('a:p'); - $objWriter->startElement('a:pPr'); - $objWriter->startElement('a:defRPr'); - $objWriter->endElement(); // a:defRPr - $objWriter->endElement(); // a:pPr - $objWriter->endElement(); // a:p + + $this->writeLabelFont($objWriter, ($axisText === null) ? null : $axisText->getFont(), $axisText); + $objWriter->endElement(); // c:txPr } $objWriter->startElement('c:spPr'); $this->writeColor($objWriter, $xAxis->getFillColorObject()); - $this->writeLineStyles($objWriter, $xAxis); + $this->writeLineStyles($objWriter, $xAxis, $xAxis->getNoFill()); $this->writeEffects($objWriter, $xAxis); $objWriter->endElement(); //end spPr @@ -1055,14 +1079,6 @@ class Chart extends WriterPart $labelFill = $plotLabel->getFillColorObject(); $labelFill = ($labelFill instanceof ChartColor) ? $labelFill : null; } - if ($plotLabel && $groupType !== DataSeries::TYPE_LINECHART) { - $fillColor = $plotLabel->getFillColorObject(); - if ($fillColor !== null && !is_array($fillColor) && $fillColor->isUsable()) { - $objWriter->startElement('c:spPr'); - $this->writeColor($objWriter, $fillColor); - $objWriter->endElement(); // c:spPr - } - } // Values $plotSeriesValues = $plotGroup->getPlotValuesByIndex($plotSeriesIdx); @@ -1094,6 +1110,12 @@ class Chart extends WriterPart $plotSeriesValues !== false ) { $objWriter->startElement('c:spPr'); + if ($plotLabel && $groupType !== DataSeries::TYPE_LINECHART) { + $fillColor = $plotLabel->getFillColorObject(); + if ($fillColor !== null && !is_array($fillColor) && $fillColor->isUsable()) { + $this->writeColor($objWriter, $fillColor); + } + } $fillObject = $labelFill ?? $plotSeriesValues->getFillColorObject(); $callLineStyles = true; if ($fillObject instanceof ChartColor && $fillObject->isUsable()) { @@ -1398,7 +1420,7 @@ class Chart extends WriterPart $count = $plotSeriesValues->getPointCount(); $source = $plotSeriesValues->getDataSource(); $values = $plotSeriesValues->getDataValues(); - if ($count > 1 || ($count === 1 && "=$source" !== (string) $values[0])) { + if ($count > 1 || ($count === 1 && array_key_exists(0, $values) && "=$source" !== (string) $values[0])) { $objWriter->startElement('c:' . $dataType . 'Cache'); if (($groupType != DataSeries::TYPE_PIECHART) && ($groupType != DataSeries::TYPE_PIECHART_3D) && ($groupType != DataSeries::TYPE_DONUTCHART)) { @@ -1770,4 +1792,51 @@ class Chart extends WriterPart } } } + + private function writeLabelFont(XMLWriter $objWriter, ?Font $labelFont, ?Properties $axisText): void + { + $objWriter->startElement('a:p'); + $objWriter->startElement('a:pPr'); + $objWriter->startElement('a:defRPr'); + if ($labelFont !== null) { + $fontSize = $labelFont->getSize(); + if (is_numeric($fontSize)) { + $fontSize *= (($fontSize < 100) ? 100 : 1); + $objWriter->writeAttribute('sz', (string) $fontSize); + } + if ($labelFont->getBold() === true) { + $objWriter->writeAttribute('b', '1'); + } + if ($labelFont->getItalic() === true) { + $objWriter->writeAttribute('i', '1'); + } + $fontColor = $labelFont->getChartColor(); + if ($fontColor !== null) { + $this->writeColor($objWriter, $fontColor); + } + } + if ($axisText !== null) { + $this->writeEffects($objWriter, $axisText); + } + if ($labelFont !== null) { + if (!empty($labelFont->getLatin())) { + $objWriter->startElement('a:latin'); + $objWriter->writeAttribute('typeface', $labelFont->getLatin()); + $objWriter->endElement(); + } + if (!empty($labelFont->getEastAsian())) { + $objWriter->startElement('a:eastAsian'); + $objWriter->writeAttribute('typeface', $labelFont->getEastAsian()); + $objWriter->endElement(); + } + if (!empty($labelFont->getComplexScript())) { + $objWriter->startElement('a:complexScript'); + $objWriter->writeAttribute('typeface', $labelFont->getComplexScript()); + $objWriter->endElement(); + } + } + $objWriter->endElement(); // a:defRPr + $objWriter->endElement(); // a:pPr + $objWriter->endElement(); // a:p + } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/DocProps.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/DocProps.php index 8902826a19e..8c33f593266 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/DocProps.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/DocProps.php @@ -93,6 +93,9 @@ class DocProps extends WriterPart // SharedDoc $objWriter->writeElement('SharedDoc', 'false'); + // HyperlinkBase + $objWriter->writeElement('HyperlinkBase', $spreadsheet->getProperties()->getHyperlinkBase()); + // HyperlinksChanged $objWriter->writeElement('HyperlinksChanged', 'false'); diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/FunctionPrefix.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/FunctionPrefix.php index ecc247d8686..cf4f9069306 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/FunctionPrefix.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/FunctionPrefix.php @@ -4,7 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx; class FunctionPrefix { - const XLFNREGEXP = '/(?:_xlfn\.)?((?:_xlws\.)?(' + const XLFNREGEXP = '/(?:_xlfn\.)?((?:_xlws\.)?\b(' // functions added with Excel 2010 . 'beta[.]dist' . '|beta[.]inv' diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/StringTable.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/StringTable.php index 7f623933cb2..29e95eb2fea 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/StringTable.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/StringTable.php @@ -64,7 +64,7 @@ class StringTable extends WriterPart /** * Write string table to XML format. * - * @param (string|RichText)[] $stringTable + * @param (RichText|string)[] $stringTable * * @return string XML Output */ @@ -226,9 +226,10 @@ class StringTable extends WriterPart if ($element->getFont() !== null) { // rPr $objWriter->startElement($prefix . 'rPr'); - $size = $element->getFont()->getSize(); - if (is_numeric($size)) { - $objWriter->writeAttribute('sz', (string) (int) ($size * 100)); + $fontSize = $element->getFont()->getSize(); + if (is_numeric($fontSize)) { + $fontSize *= (($fontSize < 100) ? 100 : 1); + $objWriter->writeAttribute('sz', (string) $fontSize); } // Bold diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Style.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Style.php index 0261f22e56e..baafdc334d9 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Style.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Style.php @@ -112,8 +112,13 @@ class Style extends WriterPart $objWriter->writeAttribute('count', (string) count($spreadsheet->getCellXfCollection())); // xf + $alignment = new Alignment(); + $defaultAlignHash = $alignment->getHashCode(); + if ($defaultAlignHash !== $spreadsheet->getDefaultStyle()->getAlignment()->getHashCode()) { + $defaultAlignHash = ''; + } foreach ($spreadsheet->getCellXfCollection() as $cellXf) { - $this->writeCellStyleXf($objWriter, $cellXf, $spreadsheet); + $this->writeCellStyleXf($objWriter, $cellXf, $spreadsheet, $defaultAlignHash); } $objWriter->endElement(); @@ -354,6 +359,13 @@ class Style extends WriterPart $objWriter->endElement(); } + if (!empty($font->getScheme())) { + $this->startFont($objWriter, $fontStarted); + $objWriter->startElement('scheme'); + $objWriter->writeAttribute('val', $font->getScheme()); + $objWriter->endElement(); + } + if ($fontStarted) { $objWriter->endElement(); } @@ -400,7 +412,7 @@ class Style extends WriterPart /** * Write Cell Style Xf. */ - private function writeCellStyleXf(XMLWriter $objWriter, \PhpOffice\PhpSpreadsheet\Style\Style $style, Spreadsheet $spreadsheet): void + private function writeCellStyleXf(XMLWriter $objWriter, \PhpOffice\PhpSpreadsheet\Style\Style $style, Spreadsheet $spreadsheet, string $defaultAlignHash): void { // xf $objWriter->startElement('xf'); @@ -424,7 +436,11 @@ class Style extends WriterPart $objWriter->writeAttribute('applyNumberFormat', ($spreadsheet->getDefaultStyle()->getNumberFormat()->getHashCode() != $style->getNumberFormat()->getHashCode()) ? '1' : '0'); $objWriter->writeAttribute('applyFill', ($spreadsheet->getDefaultStyle()->getFill()->getHashCode() != $style->getFill()->getHashCode()) ? '1' : '0'); $objWriter->writeAttribute('applyBorder', ($spreadsheet->getDefaultStyle()->getBorders()->getHashCode() != $style->getBorders()->getHashCode()) ? '1' : '0'); - $applyAlignment = ($spreadsheet->getDefaultStyle()->getAlignment()->getHashCode() != $style->getAlignment()->getHashCode()) ? '1' : '0'; + if ($defaultAlignHash !== '' && $defaultAlignHash === $style->getAlignment()->getHashCode()) { + $applyAlignment = '0'; + } else { + $applyAlignment = '1'; + } $objWriter->writeAttribute('applyAlignment', $applyAlignment); if ($style->getProtection()->getLocked() != Protection::PROTECTION_INHERIT || $style->getProtection()->getHidden() != Protection::PROTECTION_INHERIT) { $objWriter->writeAttribute('applyProtection', 'true'); diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Theme.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Theme.php index 9ff29d45d79..1e8ef5b43a4 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Theme.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Theme.php @@ -4,109 +4,17 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx; use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Namespaces; use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; +use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PhpOffice\PhpSpreadsheet\Theme as SpreadsheetTheme; class Theme extends WriterPart { - /** - * Map of Major fonts to write. - * - * @var string[] - */ - private static $majorFonts = [ - 'Jpan' => 'MS Pゴシック', - 'Hang' => '맑은 고딕', - 'Hans' => '宋体', - 'Hant' => '新細明體', - 'Arab' => 'Times New Roman', - 'Hebr' => 'Times New Roman', - 'Thai' => 'Tahoma', - 'Ethi' => 'Nyala', - 'Beng' => 'Vrinda', - 'Gujr' => 'Shruti', - 'Khmr' => 'MoolBoran', - 'Knda' => 'Tunga', - 'Guru' => 'Raavi', - 'Cans' => 'Euphemia', - 'Cher' => 'Plantagenet Cherokee', - 'Yiii' => 'Microsoft Yi Baiti', - 'Tibt' => 'Microsoft Himalaya', - 'Thaa' => 'MV Boli', - 'Deva' => 'Mangal', - 'Telu' => 'Gautami', - 'Taml' => 'Latha', - 'Syrc' => 'Estrangelo Edessa', - 'Orya' => 'Kalinga', - 'Mlym' => 'Kartika', - 'Laoo' => 'DokChampa', - 'Sinh' => 'Iskoola Pota', - 'Mong' => 'Mongolian Baiti', - 'Viet' => 'Times New Roman', - 'Uigh' => 'Microsoft Uighur', - 'Geor' => 'Sylfaen', - ]; - - /** - * Map of Minor fonts to write. - * - * @var string[] - */ - private static $minorFonts = [ - 'Jpan' => 'MS Pゴシック', - 'Hang' => '맑은 고딕', - 'Hans' => '宋体', - 'Hant' => '新細明體', - 'Arab' => 'Arial', - 'Hebr' => 'Arial', - 'Thai' => 'Tahoma', - 'Ethi' => 'Nyala', - 'Beng' => 'Vrinda', - 'Gujr' => 'Shruti', - 'Khmr' => 'DaunPenh', - 'Knda' => 'Tunga', - 'Guru' => 'Raavi', - 'Cans' => 'Euphemia', - 'Cher' => 'Plantagenet Cherokee', - 'Yiii' => 'Microsoft Yi Baiti', - 'Tibt' => 'Microsoft Himalaya', - 'Thaa' => 'MV Boli', - 'Deva' => 'Mangal', - 'Telu' => 'Gautami', - 'Taml' => 'Latha', - 'Syrc' => 'Estrangelo Edessa', - 'Orya' => 'Kalinga', - 'Mlym' => 'Kartika', - 'Laoo' => 'DokChampa', - 'Sinh' => 'Iskoola Pota', - 'Mong' => 'Mongolian Baiti', - 'Viet' => 'Arial', - 'Uigh' => 'Microsoft Uighur', - 'Geor' => 'Sylfaen', - ]; - - /** - * Map of core colours. - * - * @var string[] - */ - private static $colourScheme = [ - 'dk2' => '1F497D', - 'lt2' => 'EEECE1', - 'accent1' => '4F81BD', - 'accent2' => 'C0504D', - 'accent3' => '9BBB59', - 'accent4' => '8064A2', - 'accent5' => '4BACC6', - 'accent6' => 'F79646', - 'hlink' => '0000FF', - 'folHlink' => '800080', - ]; - /** * Write theme to XML format. * * @return string XML Output */ - public function writeTheme() + public function writeTheme(Spreadsheet $spreadsheet) { // Create XML writer $objWriter = null; @@ -115,6 +23,7 @@ class Theme extends WriterPart } else { $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } + $theme = $spreadsheet->getTheme(); // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); @@ -129,50 +38,39 @@ class Theme extends WriterPart // a:clrScheme $objWriter->startElement('a:clrScheme'); - $objWriter->writeAttribute('name', 'Office'); + $objWriter->writeAttribute('name', $theme->getThemeColorName()); - // a:dk1 - $objWriter->startElement('a:dk1'); - - // a:sysClr - $objWriter->startElement('a:sysClr'); - $objWriter->writeAttribute('val', 'windowText'); - $objWriter->writeAttribute('lastClr', '000000'); - $objWriter->endElement(); - - $objWriter->endElement(); - - // a:lt1 - $objWriter->startElement('a:lt1'); - - // a:sysClr - $objWriter->startElement('a:sysClr'); - $objWriter->writeAttribute('val', 'window'); - $objWriter->writeAttribute('lastClr', 'FFFFFF'); - $objWriter->endElement(); - - $objWriter->endElement(); - - // a:dk2 - $this->writeColourScheme($objWriter); + $this->writeColourScheme($objWriter, $theme); $objWriter->endElement(); // a:fontScheme $objWriter->startElement('a:fontScheme'); - $objWriter->writeAttribute('name', 'Office'); + $objWriter->writeAttribute('name', $theme->getThemeFontName()); // a:majorFont $objWriter->startElement('a:majorFont'); - $this->writeFonts($objWriter, 'Cambria', self::$majorFonts); - $objWriter->endElement(); + $this->writeFonts( + $objWriter, + $theme->getMajorFontLatin(), + $theme->getMajorFontEastAsian(), + $theme->getMajorFontComplexScript(), + $theme->getMajorFontSubstitutions() + ); + $objWriter->endElement(); // a:majorFont // a:minorFont $objWriter->startElement('a:minorFont'); - $this->writeFonts($objWriter, 'Calibri', self::$minorFonts); - $objWriter->endElement(); + $this->writeFonts( + $objWriter, + $theme->getMinorFontLatin(), + $theme->getMinorFontEastAsian(), + $theme->getMinorFontComplexScript(), + $theme->getMinorFontSubstitutions() + ); + $objWriter->endElement(); // a:minorFont - $objWriter->endElement(); + $objWriter->endElement(); // a:fontScheme // a:fmtScheme $objWriter->startElement('a:fmtScheme'); @@ -786,7 +684,7 @@ class Theme extends WriterPart * * @param string[] $fontSet */ - private function writeFonts(XMLWriter $objWriter, string $latinFont, array $fontSet): void + private function writeFonts(XMLWriter $objWriter, string $latinFont, string $eastAsianFont, string $complexScriptFont, array $fontSet): void { // a:latin $objWriter->startElement('a:latin'); @@ -795,12 +693,12 @@ class Theme extends WriterPart // a:ea $objWriter->startElement('a:ea'); - $objWriter->writeAttribute('typeface', ''); + $objWriter->writeAttribute('typeface', $eastAsianFont); $objWriter->endElement(); // a:cs $objWriter->startElement('a:cs'); - $objWriter->writeAttribute('typeface', ''); + $objWriter->writeAttribute('typeface', $complexScriptFont); $objWriter->endElement(); foreach ($fontSet as $fontScript => $typeface) { @@ -814,16 +712,33 @@ class Theme extends WriterPart /** * Write colour scheme to XML format. */ - private function writeColourScheme(XMLWriter $objWriter): void + private function writeColourScheme(XMLWriter $objWriter, SpreadsheetTheme $theme): void { - foreach (self::$colourScheme as $colourName => $colourValue) { - $objWriter->startElement('a:' . $colourName); + $themeArray = $theme->getThemeColors(); + // a:dk1 + $objWriter->startElement('a:dk1'); + $objWriter->startElement('a:sysClr'); + $objWriter->writeAttribute('val', 'windowText'); + $objWriter->writeAttribute('lastClr', $themeArray['dk1'] ?? '000000'); + $objWriter->endElement(); // a:sysClr + $objWriter->endElement(); // a:dk1 - $objWriter->startElement('a:srgbClr'); - $objWriter->writeAttribute('val', $colourValue); - $objWriter->endElement(); + // a:lt1 + $objWriter->startElement('a:lt1'); + $objWriter->startElement('a:sysClr'); + $objWriter->writeAttribute('val', 'window'); + $objWriter->writeAttribute('lastClr', $themeArray['lt1'] ?? 'FFFFFF'); + $objWriter->endElement(); // a:sysClr + $objWriter->endElement(); // a:lt1 - $objWriter->endElement(); + foreach ($themeArray as $colourName => $colourValue) { + if ($colourName !== 'dk1' && $colourName !== 'lt1') { + $objWriter->startElement('a:' . $colourName); + $objWriter->startElement('a:srgbClr'); + $objWriter->writeAttribute('val', $colourValue); + $objWriter->endElement(); // a:srgbClr + $objWriter->endElement(); // a:$colourName + } } } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index 53c4512457a..5e453b3d86b 100644 --- a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -18,6 +18,18 @@ use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet as PhpspreadsheetWorksheet; class Worksheet extends WriterPart { + /** @var string */ + private $numberStoredAsText = ''; + + /** @var string */ + private $formula = ''; + + /** @var string */ + private $twoDigitTextYear = ''; + + /** @var string */ + private $evalError = ''; + /** * Write worksheet to XML format. * @@ -28,6 +40,10 @@ class Worksheet extends WriterPart */ public function writeWorksheet(PhpspreadsheetWorksheet $worksheet, $stringTable = [], $includeCharts = false) { + $this->numberStoredAsText = ''; + $this->formula = ''; + $this->twoDigitTextYear = ''; + $this->evalError = ''; // Create XML writer $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { @@ -118,6 +134,9 @@ class Worksheet extends WriterPart // AlternateContent $this->writeAlternateContent($objWriter, $worksheet); + // IgnoredErrors + $this->writeIgnoredErrors($objWriter); + // Table $this->writeTable($objWriter, $worksheet); @@ -131,6 +150,32 @@ class Worksheet extends WriterPart return $objWriter->getData(); } + private function writeIgnoredError(XMLWriter $objWriter, bool &$started, string $attr, string $cells): void + { + if ($cells !== '') { + if (!$started) { + $objWriter->startElement('ignoredErrors'); + $started = true; + } + $objWriter->startElement('ignoredError'); + $objWriter->writeAttribute('sqref', substr($cells, 1)); + $objWriter->writeAttribute($attr, '1'); + $objWriter->endElement(); + } + } + + private function writeIgnoredErrors(XMLWriter $objWriter): void + { + $started = false; + $this->writeIgnoredError($objWriter, $started, 'numberStoredAsText', $this->numberStoredAsText); + $this->writeIgnoredError($objWriter, $started, 'formula', $this->formula); + $this->writeIgnoredError($objWriter, $started, 'twoDigitTextYear', $this->twoDigitTextYear); + $this->writeIgnoredError($objWriter, $started, 'evalError', $this->evalError); + if ($started) { + $objWriter->endElement(); + } + } + /** * Write SheetPr. */ @@ -1134,7 +1179,20 @@ class Worksheet extends WriterPart array_pop($columnsInRow); foreach ($columnsInRow as $column) { // Write cell - $this->writeCell($objWriter, $worksheet, "{$column}{$currentRow}", $aFlippedStringTable); + $coord = "$column$currentRow"; + if ($worksheet->getCell($coord)->getIgnoredErrors()->getNumberStoredAsText()) { + $this->numberStoredAsText .= " $coord"; + } + if ($worksheet->getCell($coord)->getIgnoredErrors()->getFormula()) { + $this->formula .= " $coord"; + } + if ($worksheet->getCell($coord)->getIgnoredErrors()->getTwoDigitTextYear()) { + $this->twoDigitTextYear .= " $coord"; + } + if ($worksheet->getCell($coord)->getIgnoredErrors()->getEvalError()) { + $this->evalError .= " $coord"; + } + $this->writeCell($objWriter, $worksheet, $coord, $aFlippedStringTable); } } diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/ZipStream0.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/ZipStream0.php new file mode 100644 index 00000000000..886731ca9e2 --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/ZipStream0.php @@ -0,0 +1,17 @@ +setEnableZip64(false); + $options->setOutputStream($fileHandle); + + return new ZipStream(null, $options); + } +} diff --git a/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/ZipStream3.php b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/ZipStream3.php new file mode 100644 index 00000000000..d9c8d0b1664 --- /dev/null +++ b/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/ZipStream3.php @@ -0,0 +1,22 @@ +=7.0.0", - "psr/http-message": "^1.0" + "psr/http-message": "^1.0 || ^2.0" }, "autoload": { "psr-4": { diff --git a/lib/phpspreadsheet/vendor/psr/http-message/README.md b/lib/phpspreadsheet/vendor/psr/http-message/README.md index 28185338f72..2668be6c30b 100644 --- a/lib/phpspreadsheet/vendor/psr/http-message/README.md +++ b/lib/phpspreadsheet/vendor/psr/http-message/README.md @@ -10,4 +10,7 @@ interface that describes a HTTP message. See the specification for more details. Usage ----- -We'll certainly need some stuff in here. \ No newline at end of file +Before reading the usage guide we recommend reading the PSR-7 interfaces method list: + +* [`PSR-7 Interfaces Method List`](docs/PSR7-Interfaces.md) +* [`PSR-7 Usage Guide`](docs/PSR7-Usage.md) \ No newline at end of file diff --git a/lib/phpspreadsheet/vendor/psr/http-message/composer.json b/lib/phpspreadsheet/vendor/psr/http-message/composer.json index b0d2937a03a..c66e5aba40c 100644 --- a/lib/phpspreadsheet/vendor/psr/http-message/composer.json +++ b/lib/phpspreadsheet/vendor/psr/http-message/composer.json @@ -7,11 +7,11 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "require": { - "php": ">=5.3.0" + "php": "^7.2 || ^8.0" }, "autoload": { "psr-4": { @@ -20,7 +20,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } } } diff --git a/lib/phpspreadsheet/vendor/psr/http-message/docs/PSR7-Interfaces.md b/lib/phpspreadsheet/vendor/psr/http-message/docs/PSR7-Interfaces.md new file mode 100644 index 00000000000..3a7e7dda695 --- /dev/null +++ b/lib/phpspreadsheet/vendor/psr/http-message/docs/PSR7-Interfaces.md @@ -0,0 +1,130 @@ +# Interfaces + +The purpose of this list is to help in finding the methods when working with PSR-7. This can be considered as a cheatsheet for PSR-7 interfaces. + +The interfaces defined in PSR-7 are the following: + +| Class Name | Description | +|---|---| +| [Psr\Http\Message\MessageInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagemessageinterface) | Representation of a HTTP message | +| [Psr\Http\Message\RequestInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagerequestinterface) | Representation of an outgoing, client-side request. | +| [Psr\Http\Message\ServerRequestInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageserverrequestinterface) | Representation of an incoming, server-side HTTP request. | +| [Psr\Http\Message\ResponseInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageresponseinterface) | Representation of an outgoing, server-side response. | +| [Psr\Http\Message\StreamInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagestreaminterface) | Describes a data stream | +| [Psr\Http\Message\UriInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageuriinterface) | Value object representing a URI. | +| [Psr\Http\Message\UploadedFileInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageuploadedfileinterface) | Value object representing a file uploaded through an HTTP request. | + +## `Psr\Http\Message\MessageInterface` Methods + +| Method Name | Description | Notes | +|------------------------------------| ----------- | ----- | +| `getProtocolVersion()` | Retrieve HTTP protocol version | 1.0 or 1.1 | +| `withProtocolVersion($version)` | Returns new message instance with given HTTP protocol version | | +| `getHeaders()` | Retrieve all HTTP Headers | [Request Header List](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields), [Response Header List](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields) | +| `hasHeader($name)` | Checks if HTTP Header with given name exists | | +| `getHeader($name)` | Retrieves a array with the values for a single header | | +| `getHeaderLine($name)` | Retrieves a comma-separated string of the values for a single header | | +| `withHeader($name, $value)` | Returns new message instance with given HTTP Header | if the header existed in the original instance, replaces the header value from the original message with the value provided when creating the new instance. | +| `withAddedHeader($name, $value)` | Returns new message instance with appended value to given header | If header already exists value will be appended, if not a new header will be created | +| `withoutHeader($name)` | Removes HTTP Header with given name| | +| `getBody()` | Retrieves the HTTP Message Body | Returns object implementing `StreamInterface`| +| `withBody(StreamInterface $body)` | Returns new message instance with given HTTP Message Body | | + + +## `Psr\Http\Message\RequestInterface` Methods + +Same methods as `Psr\Http\Message\MessageInterface` + the following methods: + +| Method Name | Description | Notes | +|------------------------------------| ----------- | ----- | +| `getRequestTarget()` | Retrieves the message's request target | origin-form, absolute-form, authority-form, asterisk-form ([RFC7230](https://www.rfc-editor.org/rfc/rfc7230.txt)) | +| `withRequestTarget($requestTarget)` | Return a new message instance with the specific request-target | | +| `getMethod()` | Retrieves the HTTP method of the request. | GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE (defined in [RFC7231](https://tools.ietf.org/html/rfc7231)), PATCH (defined in [RFC5789](https://tools.ietf.org/html/rfc5789)) | +| `withMethod($method)` | Returns a new message instance with the provided HTTP method | | +| `getUri()` | Retrieves the URI instance | | +| `withUri(UriInterface $uri, $preserveHost = false)` | Returns a new message instance with the provided URI | | + + +## `Psr\Http\Message\ServerRequestInterface` Methods + +Same methods as `Psr\Http\Message\RequestInterface` + the following methods: + +| Method Name | Description | Notes | +|------------------------------------| ----------- | ----- | +| `getServerParams() ` | Retrieve server parameters | Typically derived from `$_SERVER` | +| `getCookieParams()` | Retrieves cookies sent by the client to the server. | Typically derived from `$_COOKIES` | +| `withCookieParams(array $cookies)` | Returns a new request instance with the specified cookies | | +| `withQueryParams(array $query)` | Returns a new request instance with the specified query string arguments | | +| `getUploadedFiles()` | Retrieve normalized file upload data | | +| `withUploadedFiles(array $uploadedFiles)` | Returns a new request instance with the specified uploaded files | | +| `getParsedBody()` | Retrieve any parameters provided in the request body | | +| `withParsedBody($data)` | Returns a new request instance with the specified body parameters | | +| `getAttributes()` | Retrieve attributes derived from the request | | +| `getAttribute($name, $default = null)` | Retrieve a single derived request attribute | | +| `withAttribute($name, $value)` | Returns a new request instance with the specified derived request attribute | | +| `withoutAttribute($name)` | Returns a new request instance that without the specified derived request attribute | | + +## `Psr\Http\Message\ResponseInterface` Methods: + +Same methods as `Psr\Http\Message\MessageInterface` + the following methods: + +| Method Name | Description | Notes | +|------------------------------------| ----------- | ----- | +| `getStatusCode()` | Gets the response status code. | | +| `withStatus($code, $reasonPhrase = '')` | Returns a new response instance with the specified status code and, optionally, reason phrase. | | +| `getReasonPhrase()` | Gets the response reason phrase associated with the status code. | | + +## `Psr\Http\Message\StreamInterface` Methods + +| Method Name | Description | Notes | +|------------------------------------| ----------- | ----- | +| `__toString()` | Reads all data from the stream into a string, from the beginning to end. | | +| `close()` | Closes the stream and any underlying resources. | | +| `detach()` | Separates any underlying resources from the stream. | | +| `getSize()` | Get the size of the stream if known. | | +| `eof()` | Returns true if the stream is at the end of the stream.| | +| `isSeekable()` | Returns whether or not the stream is seekable. | | +| `seek($offset, $whence = SEEK_SET)` | Seek to a position in the stream. | | +| `rewind()` | Seek to the beginning of the stream. | | +| `isWritable()` | Returns whether or not the stream is writable. | | +| `write($string)` | Write data to the stream. | | +| `isReadable()` | Returns whether or not the stream is readable. | | +| `read($length)` | Read data from the stream. | | +| `getContents()` | Returns the remaining contents in a string | | +| `getMetadata($key = null)()` | Get stream metadata as an associative array or retrieve a specific key. | | + +## `Psr\Http\Message\UriInterface` Methods + +| Method Name | Description | Notes | +|------------------------------------| ----------- | ----- | +| `getScheme()` | Retrieve the scheme component of the URI. | | +| `getAuthority()` | Retrieve the authority component of the URI. | | +| `getUserInfo()` | Retrieve the user information component of the URI. | | +| `getHost()` | Retrieve the host component of the URI. | | +| `getPort()` | Retrieve the port component of the URI. | | +| `getPath()` | Retrieve the path component of the URI. | | +| `getQuery()` | Retrieve the query string of the URI. | | +| `getFragment()` | Retrieve the fragment component of the URI. | | +| `withScheme($scheme)` | Return an instance with the specified scheme. | | +| `withUserInfo($user, $password = null)` | Return an instance with the specified user information. | | +| `withHost($host)` | Return an instance with the specified host. | | +| `withPort($port)` | Return an instance with the specified port. | | +| `withPath($path)` | Return an instance with the specified path. | | +| `withQuery($query)` | Return an instance with the specified query string. | | +| `withFragment($fragment)` | Return an instance with the specified URI fragment. | | +| `__toString()` | Return the string representation as a URI reference. | | + +## `Psr\Http\Message\UploadedFileInterface` Methods + +| Method Name | Description | Notes | +|------------------------------------| ----------- | ----- | +| `getStream()` | Retrieve a stream representing the uploaded file. | | +| `moveTo($targetPath)` | Move the uploaded file to a new location. | | +| `getSize()` | Retrieve the file size. | | +| `getError()` | Retrieve the error associated with the uploaded file. | | +| `getClientFilename()` | Retrieve the filename sent by the client. | | +| `getClientMediaType()` | Retrieve the media type sent by the client. | | + +> `RequestInterface`, `ServerRequestInterface`, `ResponseInterface` extend `MessageInterface` because the `Request` and the `Response` are `HTTP Messages`. +> When using `ServerRequestInterface`, both `RequestInterface` and `Psr\Http\Message\MessageInterface` methods are considered. + diff --git a/lib/phpspreadsheet/vendor/psr/http-message/docs/PSR7-Usage.md b/lib/phpspreadsheet/vendor/psr/http-message/docs/PSR7-Usage.md new file mode 100644 index 00000000000..b6d048a341e --- /dev/null +++ b/lib/phpspreadsheet/vendor/psr/http-message/docs/PSR7-Usage.md @@ -0,0 +1,159 @@ +### PSR-7 Usage + +All PSR-7 applications comply with these interfaces +They were created to establish a standard between middleware implementations. + +> `RequestInterface`, `ServerRequestInterface`, `ResponseInterface` extend `MessageInterface` because the `Request` and the `Response` are `HTTP Messages`. +> When using `ServerRequestInterface`, both `RequestInterface` and `Psr\Http\Message\MessageInterface` methods are considered. + + +The following examples will illustrate how basic operations are done in PSR-7. + +##### Examples + + +For this examples to work (at least) a PSR-7 implementation package is required. (eg: zendframework/zend-diactoros, guzzlehttp/psr7, slim/slim, etc) +All PSR-7 implementations should have the same behaviour. + +The following will be assumed: +`$request` is an object of `Psr\Http\Message\RequestInterface` and + +`$response` is an object implementing `Psr\Http\Message\RequestInterface` + + +### Working with HTTP Headers + +#### Adding headers to response: + +```php +$response->withHeader('My-Custom-Header', 'My Custom Message'); +``` + +#### Appending values to headers + +```php +$response->withAddedHeader('My-Custom-Header', 'The second message'); +``` + +#### Checking if header exists: + +```php +$request->hasHeader('My-Custom-Header'); // will return false +$response->hasHeader('My-Custom-Header'); // will return true +``` + +> Note: My-Custom-Header was only added in the Response + +#### Getting comma-separated values from a header (also applies to request) + +```php +// getting value from request headers +$request->getHeaderLine('Content-Type'); // will return: "text/html; charset=UTF-8" +// getting value from response headers +$response->getHeaderLine('My-Custom-Header'); // will return: "My Custom Message; The second message" +``` + +#### Getting array of value from a header (also applies to request) +```php +// getting value from request headers +$request->getHeader('Content-Type'); // will return: ["text/html", "charset=UTF-8"] +// getting value from response headers +$response->getHeader('My-Custom-Header'); // will return: ["My Custom Message", "The second message"] +``` + +#### Removing headers from HTTP Messages +```php +// removing a header from Request, removing deprecated "Content-MD5" header +$request->withoutHeader('Content-MD5'); + +// removing a header from Response +// effect: the browser won't know the size of the stream +// the browser will download the stream till it ends +$response->withoutHeader('Content-Length'); +``` + +### Working with HTTP Message Body + +When working with the PSR-7 there are two methods of implementation: +#### 1. Getting the body separately + +> This method makes the body handling easier to understand and is useful when repeatedly calling body methods. (You only call `getBody()` once). Using this method mistakes like `$response->write()` are also prevented. + +```php +$body = $response->getBody(); +// operations on body, eg. read, write, seek +// ... +// replacing the old body +$response->withBody($body); +// this last statement is optional as we working with objects +// in this case the "new" body is same with the "old" one +// the $body variable has the same value as the one in $request, only the reference is passed +``` + +#### 2. Working directly on response + +> This method is useful when only performing few operations as the `$request->getBody()` statement fragment is required + +```php +$response->getBody()->write('hello'); +``` + +### Getting the body contents + +The following snippet gets the contents of a stream contents. +> Note: Streams must be rewinded, if content was written into streams, it will be ignored when calling `getContents()` because the stream pointer is set to the last character, which is `\0` - meaning end of stream. +```php +$body = $response->getBody(); +$body->rewind(); // or $body->seek(0); +$bodyText = $body->getContents(); +``` +> Note: If `$body->seek(1)` is called before `$body->getContents()`, the first character will be ommited as the starting pointer is set to `1`, not `0`. This is why using `$body->rewind()` is recommended. + +### Append to body + +```php +$response->getBody()->write('Hello'); // writing directly +$body = $request->getBody(); // which is a `StreamInterface` +$body->write('xxxxx'); +``` + +### Prepend to body +Prepending is different when it comes to streams. The content must be copied before writing the content to be prepended. +The following example will explain the behaviour of streams. + +```php +// assuming our response is initially empty +$body = $repsonse->getBody(); +// writing the string "abcd" +$body->write('abcd'); + +// seeking to start of stream +$body->seek(0); +// writing 'ef' +$body->write('ef'); // at this point the stream contains "efcd" +``` + +#### Prepending by rewriting separately + +```php +// assuming our response body stream only contains: "abcd" +$body = $response->getBody(); +$body->rewind(); +$contents = $body->getContents(); // abcd +// seeking the stream to beginning +$body->rewind(); +$body->write('ef'); // stream contains "efcd" +$body->write($contents); // stream contains "efabcd" +``` + +> Note: `getContents()` seeks the stream while reading it, therefore if the second `rewind()` method call was not present the stream would have resulted in `abcdefabcd` because the `write()` method appends to stream if not preceeded by `rewind()` or `seek(0)`. + +#### Prepending by using contents as a string +```php +$body = $response->getBody(); +$body->rewind(); +$contents = $body->getContents(); // efabcd +$contents = 'ef'.$contents; +$body->rewind(); +$body->write($contents); +``` diff --git a/lib/phpspreadsheet/vendor/psr/http-message/src/MessageInterface.php b/lib/phpspreadsheet/vendor/psr/http-message/src/MessageInterface.php index dd46e5ec81e..a83c98518d5 100644 --- a/lib/phpspreadsheet/vendor/psr/http-message/src/MessageInterface.php +++ b/lib/phpspreadsheet/vendor/psr/http-message/src/MessageInterface.php @@ -23,7 +23,7 @@ interface MessageInterface * * @return string HTTP protocol version. */ - public function getProtocolVersion(); + public function getProtocolVersion(): string; /** * Return an instance with the specified HTTP protocol version. @@ -38,7 +38,7 @@ interface MessageInterface * @param string $version HTTP protocol version * @return static */ - public function withProtocolVersion($version); + public function withProtocolVersion(string $version): MessageInterface; /** * Retrieves all message header values. @@ -65,7 +65,7 @@ interface MessageInterface * key MUST be a header name, and each value MUST be an array of strings * for that header. */ - public function getHeaders(); + public function getHeaders(): array; /** * Checks if a header exists by the given case-insensitive name. @@ -75,7 +75,7 @@ interface MessageInterface * name using a case-insensitive string comparison. Returns false if * no matching header name is found in the message. */ - public function hasHeader($name); + public function hasHeader(string $name): bool; /** * Retrieves a message header value by the given case-insensitive name. @@ -91,7 +91,7 @@ interface MessageInterface * header. If the header does not appear in the message, this method MUST * return an empty array. */ - public function getHeader($name); + public function getHeader(string $name): array; /** * Retrieves a comma-separated string of the values for a single header. @@ -112,7 +112,7 @@ interface MessageInterface * concatenated together using a comma. If the header does not appear in * the message, this method MUST return an empty string. */ - public function getHeaderLine($name); + public function getHeaderLine(string $name): string; /** * Return an instance with the provided value replacing the specified header. @@ -129,7 +129,7 @@ interface MessageInterface * @return static * @throws \InvalidArgumentException for invalid header names or values. */ - public function withHeader($name, $value); + public function withHeader(string $name, $value): MessageInterface; /** * Return an instance with the specified header appended with the given value. @@ -147,7 +147,7 @@ interface MessageInterface * @return static * @throws \InvalidArgumentException for invalid header names or values. */ - public function withAddedHeader($name, $value); + public function withAddedHeader(string $name, $value): MessageInterface; /** * Return an instance without the specified header. @@ -161,14 +161,14 @@ interface MessageInterface * @param string $name Case-insensitive header field name to remove. * @return static */ - public function withoutHeader($name); + public function withoutHeader(string $name): MessageInterface; /** * Gets the body of the message. * * @return StreamInterface Returns the body as a stream. */ - public function getBody(); + public function getBody(): StreamInterface; /** * Return an instance with the specified message body. @@ -183,5 +183,5 @@ interface MessageInterface * @return static * @throws \InvalidArgumentException When the body is not valid. */ - public function withBody(StreamInterface $body); + public function withBody(StreamInterface $body): MessageInterface; } diff --git a/lib/phpspreadsheet/vendor/psr/http-message/src/RequestInterface.php b/lib/phpspreadsheet/vendor/psr/http-message/src/RequestInterface.php index a96d4fd6366..33f85e559d0 100644 --- a/lib/phpspreadsheet/vendor/psr/http-message/src/RequestInterface.php +++ b/lib/phpspreadsheet/vendor/psr/http-message/src/RequestInterface.php @@ -39,7 +39,7 @@ interface RequestInterface extends MessageInterface * * @return string */ - public function getRequestTarget(); + public function getRequestTarget(): string; /** * Return an instance with the specific request-target. @@ -55,17 +55,18 @@ interface RequestInterface extends MessageInterface * * @link http://tools.ietf.org/html/rfc7230#section-5.3 (for the various * request-target forms allowed in request messages) - * @param mixed $requestTarget + * @param string $requestTarget * @return static */ - public function withRequestTarget($requestTarget); + public function withRequestTarget(string $requestTarget): RequestInterface; + /** * Retrieves the HTTP method of the request. * * @return string Returns the request method. */ - public function getMethod(); + public function getMethod(): string; /** * Return an instance with the provided HTTP method. @@ -82,7 +83,7 @@ interface RequestInterface extends MessageInterface * @return static * @throws \InvalidArgumentException for invalid HTTP methods. */ - public function withMethod($method); + public function withMethod(string $method): RequestInterface; /** * Retrieves the URI instance. @@ -93,7 +94,7 @@ interface RequestInterface extends MessageInterface * @return UriInterface Returns a UriInterface instance * representing the URI of the request. */ - public function getUri(); + public function getUri(): UriInterface; /** * Returns an instance with the provided URI. @@ -125,5 +126,5 @@ interface RequestInterface extends MessageInterface * @param bool $preserveHost Preserve the original state of the Host header. * @return static */ - public function withUri(UriInterface $uri, $preserveHost = false); + public function withUri(UriInterface $uri, bool $preserveHost = false): RequestInterface; } diff --git a/lib/phpspreadsheet/vendor/psr/http-message/src/ResponseInterface.php b/lib/phpspreadsheet/vendor/psr/http-message/src/ResponseInterface.php index c306514e6bb..e9299a91443 100644 --- a/lib/phpspreadsheet/vendor/psr/http-message/src/ResponseInterface.php +++ b/lib/phpspreadsheet/vendor/psr/http-message/src/ResponseInterface.php @@ -27,7 +27,7 @@ interface ResponseInterface extends MessageInterface * * @return int Status code. */ - public function getStatusCode(); + public function getStatusCode(): int; /** * Return an instance with the specified status code and, optionally, reason phrase. @@ -49,7 +49,7 @@ interface ResponseInterface extends MessageInterface * @return static * @throws \InvalidArgumentException For invalid status code arguments. */ - public function withStatus($code, $reasonPhrase = ''); + public function withStatus(int $code, string $reasonPhrase = ''): ResponseInterface; /** * Gets the response reason phrase associated with the status code. @@ -64,5 +64,5 @@ interface ResponseInterface extends MessageInterface * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml * @return string Reason phrase; must return an empty string if none present. */ - public function getReasonPhrase(); + public function getReasonPhrase(): string; } diff --git a/lib/phpspreadsheet/vendor/psr/http-message/src/ServerRequestInterface.php b/lib/phpspreadsheet/vendor/psr/http-message/src/ServerRequestInterface.php index 02512340ad8..8625d0e100d 100644 --- a/lib/phpspreadsheet/vendor/psr/http-message/src/ServerRequestInterface.php +++ b/lib/phpspreadsheet/vendor/psr/http-message/src/ServerRequestInterface.php @@ -51,7 +51,7 @@ interface ServerRequestInterface extends RequestInterface * * @return array */ - public function getServerParams(); + public function getServerParams(): array; /** * Retrieve cookies. @@ -63,7 +63,7 @@ interface ServerRequestInterface extends RequestInterface * * @return array */ - public function getCookieParams(); + public function getCookieParams(): array; /** * Return an instance with the specified cookies. @@ -82,7 +82,7 @@ interface ServerRequestInterface extends RequestInterface * @param array $cookies Array of key/value pairs representing cookies. * @return static */ - public function withCookieParams(array $cookies); + public function withCookieParams(array $cookies): ServerRequestInterface; /** * Retrieve query string arguments. @@ -96,7 +96,7 @@ interface ServerRequestInterface extends RequestInterface * * @return array */ - public function getQueryParams(); + public function getQueryParams(): array; /** * Return an instance with the specified query string arguments. @@ -120,7 +120,7 @@ interface ServerRequestInterface extends RequestInterface * $_GET. * @return static */ - public function withQueryParams(array $query); + public function withQueryParams(array $query): ServerRequestInterface; /** * Retrieve normalized file upload data. @@ -134,7 +134,7 @@ interface ServerRequestInterface extends RequestInterface * @return array An array tree of UploadedFileInterface instances; an empty * array MUST be returned if no data is present. */ - public function getUploadedFiles(); + public function getUploadedFiles(): array; /** * Create a new instance with the specified uploaded files. @@ -147,7 +147,7 @@ interface ServerRequestInterface extends RequestInterface * @return static * @throws \InvalidArgumentException if an invalid structure is provided. */ - public function withUploadedFiles(array $uploadedFiles); + public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface; /** * Retrieve any parameters provided in the request body. @@ -194,7 +194,7 @@ interface ServerRequestInterface extends RequestInterface * @throws \InvalidArgumentException if an unsupported argument type is * provided. */ - public function withParsedBody($data); + public function withParsedBody($data): ServerRequestInterface; /** * Retrieve attributes derived from the request. @@ -207,7 +207,7 @@ interface ServerRequestInterface extends RequestInterface * * @return array Attributes derived from the request. */ - public function getAttributes(); + public function getAttributes(): array; /** * Retrieve a single derived request attribute. @@ -224,7 +224,7 @@ interface ServerRequestInterface extends RequestInterface * @param mixed $default Default value to return if the attribute does not exist. * @return mixed */ - public function getAttribute($name, $default = null); + public function getAttribute(string $name, $default = null); /** * Return an instance with the specified derived request attribute. @@ -241,7 +241,7 @@ interface ServerRequestInterface extends RequestInterface * @param mixed $value The value of the attribute. * @return static */ - public function withAttribute($name, $value); + public function withAttribute(string $name, $value): ServerRequestInterface; /** * Return an instance that removes the specified derived request attribute. @@ -257,5 +257,5 @@ interface ServerRequestInterface extends RequestInterface * @param string $name The attribute name. * @return static */ - public function withoutAttribute($name); + public function withoutAttribute(string $name): ServerRequestInterface; } diff --git a/lib/phpspreadsheet/vendor/psr/http-message/src/StreamInterface.php b/lib/phpspreadsheet/vendor/psr/http-message/src/StreamInterface.php index f68f391269b..a62aabb8288 100644 --- a/lib/phpspreadsheet/vendor/psr/http-message/src/StreamInterface.php +++ b/lib/phpspreadsheet/vendor/psr/http-message/src/StreamInterface.php @@ -25,14 +25,14 @@ interface StreamInterface * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring * @return string */ - public function __toString(); + public function __toString(): string; /** * Closes the stream and any underlying resources. * * @return void */ - public function close(); + public function close(): void; /** * Separates any underlying resources from the stream. @@ -48,7 +48,7 @@ interface StreamInterface * * @return int|null Returns the size in bytes if known, or null if unknown. */ - public function getSize(); + public function getSize(): ?int; /** * Returns the current position of the file read/write pointer @@ -56,21 +56,21 @@ interface StreamInterface * @return int Position of the file pointer * @throws \RuntimeException on error. */ - public function tell(); + public function tell(): int; /** * Returns true if the stream is at the end of the stream. * * @return bool */ - public function eof(); + public function eof(): bool; /** * Returns whether or not the stream is seekable. * * @return bool */ - public function isSeekable(); + public function isSeekable(): bool; /** * Seek to a position in the stream. @@ -84,7 +84,7 @@ interface StreamInterface * SEEK_END: Set position to end-of-stream plus offset. * @throws \RuntimeException on failure. */ - public function seek($offset, $whence = SEEK_SET); + public function seek(int $offset, int $whence = SEEK_SET): void; /** * Seek to the beginning of the stream. @@ -96,14 +96,14 @@ interface StreamInterface * @link http://www.php.net/manual/en/function.fseek.php * @throws \RuntimeException on failure. */ - public function rewind(); + public function rewind(): void; /** * Returns whether or not the stream is writable. * * @return bool */ - public function isWritable(); + public function isWritable(): bool; /** * Write data to the stream. @@ -112,14 +112,14 @@ interface StreamInterface * @return int Returns the number of bytes written to the stream. * @throws \RuntimeException on failure. */ - public function write($string); + public function write(string $string): int; /** * Returns whether or not the stream is readable. * * @return bool */ - public function isReadable(); + public function isReadable(): bool; /** * Read data from the stream. @@ -131,7 +131,7 @@ interface StreamInterface * if no bytes are available. * @throws \RuntimeException if an error occurs. */ - public function read($length); + public function read(int $length): string; /** * Returns the remaining contents in a string @@ -140,7 +140,7 @@ interface StreamInterface * @throws \RuntimeException if unable to read or an error occurs while * reading. */ - public function getContents(); + public function getContents(): string; /** * Get stream metadata as an associative array or retrieve a specific key. @@ -149,10 +149,10 @@ interface StreamInterface * stream_get_meta_data() function. * * @link http://php.net/manual/en/function.stream-get-meta-data.php - * @param string $key Specific metadata to retrieve. + * @param string|null $key Specific metadata to retrieve. * @return array|mixed|null Returns an associative array if no key is * provided. Returns a specific key value if a key is provided and the * value is found, or null if the key is not found. */ - public function getMetadata($key = null); + public function getMetadata(?string $key = null); } diff --git a/lib/phpspreadsheet/vendor/psr/http-message/src/UploadedFileInterface.php b/lib/phpspreadsheet/vendor/psr/http-message/src/UploadedFileInterface.php index f8a6901e014..dd19d653819 100644 --- a/lib/phpspreadsheet/vendor/psr/http-message/src/UploadedFileInterface.php +++ b/lib/phpspreadsheet/vendor/psr/http-message/src/UploadedFileInterface.php @@ -28,7 +28,7 @@ interface UploadedFileInterface * @throws \RuntimeException in cases when no stream is available or can be * created. */ - public function getStream(); + public function getStream(): StreamInterface; /** * Move the uploaded file to a new location. @@ -62,7 +62,7 @@ interface UploadedFileInterface * @throws \RuntimeException on any error during the move operation, or on * the second or subsequent call to the method. */ - public function moveTo($targetPath); + public function moveTo(string $targetPath): void; /** * Retrieve the file size. @@ -73,7 +73,7 @@ interface UploadedFileInterface * * @return int|null The file size in bytes or null if unknown. */ - public function getSize(); + public function getSize(): ?int; /** * Retrieve the error associated with the uploaded file. @@ -89,7 +89,7 @@ interface UploadedFileInterface * @see http://php.net/manual/en/features.file-upload.errors.php * @return int One of PHP's UPLOAD_ERR_XXX constants. */ - public function getError(); + public function getError(): int; /** * Retrieve the filename sent by the client. @@ -104,7 +104,7 @@ interface UploadedFileInterface * @return string|null The filename sent by the client or null if none * was provided. */ - public function getClientFilename(); + public function getClientFilename(): ?string; /** * Retrieve the media type sent by the client. @@ -119,5 +119,5 @@ interface UploadedFileInterface * @return string|null The media type sent by the client or null if none * was provided. */ - public function getClientMediaType(); + public function getClientMediaType(): ?string; } diff --git a/lib/phpspreadsheet/vendor/psr/http-message/src/UriInterface.php b/lib/phpspreadsheet/vendor/psr/http-message/src/UriInterface.php index 9d7ab9eae8f..15e2cf28628 100644 --- a/lib/phpspreadsheet/vendor/psr/http-message/src/UriInterface.php +++ b/lib/phpspreadsheet/vendor/psr/http-message/src/UriInterface.php @@ -1,4 +1,5 @@