From 9dae820fe7502a878545c0064f25cc89432e5ab7 Mon Sep 17 00:00:00 2001 From: Paul copperhead Date: Mon, 4 Jul 2022 15:57:13 +1000 Subject: [PATCH 1/3] Make xls spreadsheet included via composer xls.php - include vendor/autoload.php xls.php - left align plot xls.php - add test if imdbID field is blank to stop corrupt xls file amend config.sample.php --- composer.json | 4 +- config.sample.php | 16 +- core/xls.php | 11 +- vendor/composer/ClassLoader.php | 161 +- vendor/composer/InstalledVersions.php | 350 + vendor/composer/autoload_classmap.php | 10 + vendor/composer/autoload_files.php | 6 + vendor/composer/autoload_namespaces.php | 4 + vendor/composer/autoload_psr4.php | 4 + vendor/composer/autoload_real.php | 22 +- vendor/composer/autoload_static.php | 69 + vendor/composer/include_paths.php | 14 + vendor/composer/installed.json | 1457 ++++- vendor/composer/installed.php | 179 + vendor/composer/platform_check.php | 26 + vendor/guzzlehttp/guzzle/.php_cs | 23 + vendor/guzzlehttp/guzzle/CHANGELOG.md | 65 + vendor/guzzlehttp/guzzle/Dockerfile | 18 + vendor/guzzlehttp/guzzle/LICENSE | 10 +- vendor/guzzlehttp/guzzle/README.md | 60 +- vendor/guzzlehttp/guzzle/composer.json | 76 +- vendor/guzzlehttp/guzzle/src/Client.php | 99 +- .../guzzlehttp/guzzle/src/ClientInterface.php | 7 +- .../guzzle/src/Cookie/CookieJar.php | 13 +- .../guzzle/src/Cookie/CookieJarInterface.php | 6 +- .../guzzle/src/Cookie/FileCookieJar.php | 3 +- .../guzzle/src/Cookie/SessionCookieJar.php | 1 + .../guzzle/src/Cookie/SetCookie.php | 15 +- .../guzzle/src/Exception/ClientException.php | 4 +- .../guzzle/src/Exception/GuzzleException.php | 30 +- .../Exception/InvalidArgumentException.php | 7 + .../guzzle/src/Exception/RequestException.php | 35 +- .../guzzle/src/Exception/ServerException.php | 4 +- .../Exception/TooManyRedirectsException.php | 4 +- .../src/Exception/TransferException.php | 4 +- .../guzzle/src/Handler/CurlFactory.php | 44 +- .../guzzle/src/Handler/CurlMultiHandler.php | 34 +- .../guzzle/src/Handler/MockHandler.php | 10 +- .../guzzle/src/Handler/StreamHandler.php | 25 +- vendor/guzzlehttp/guzzle/src/HandlerStack.php | 14 +- .../guzzle/src/MessageFormatter.php | 5 + vendor/guzzlehttp/guzzle/src/Middleware.php | 7 +- vendor/guzzlehttp/guzzle/src/Pool.php | 15 +- .../guzzle/src/PrepareBodyMiddleware.php | 5 + .../guzzle/src/RedirectMiddleware.php | 45 +- .../guzzlehttp/guzzle/src/RequestOptions.php | 10 +- .../guzzlehttp/guzzle/src/RetryMiddleware.php | 22 +- .../guzzlehttp/guzzle/src/TransferStats.php | 12 +- vendor/guzzlehttp/guzzle/src/Utils.php | 92 + vendor/guzzlehttp/guzzle/src/functions.php | 15 +- vendor/guzzlehttp/promises/CHANGELOG.md | 38 + vendor/guzzlehttp/promises/LICENSE | 7 +- vendor/guzzlehttp/promises/README.md | 57 +- vendor/guzzlehttp/promises/composer.json | 34 +- .../promises/src/AggregateException.php | 1 + .../promises/src/CancellationException.php | 1 + vendor/guzzlehttp/promises/src/Coroutine.php | 28 +- vendor/guzzlehttp/promises/src/Create.php | 84 + vendor/guzzlehttp/promises/src/Each.php | 90 + .../guzzlehttp/promises/src/EachPromise.php | 68 +- .../promises/src/FulfilledPromise.php | 10 +- vendor/guzzlehttp/promises/src/Is.php | 46 + vendor/guzzlehttp/promises/src/Promise.php | 68 +- .../promises/src/PromiseInterface.php | 4 + .../promises/src/PromisorInterface.php | 1 + .../promises/src/RejectedPromise.php | 14 +- .../promises/src/RejectionException.php | 3 +- vendor/guzzlehttp/promises/src/TaskQueue.php | 5 +- .../promises/src/TaskQueueInterface.php | 3 +- vendor/guzzlehttp/promises/src/Utils.php | 276 + vendor/guzzlehttp/promises/src/functions.php | 254 +- vendor/guzzlehttp/psr7/.github/FUNDING.yml | 2 + vendor/guzzlehttp/psr7/.github/stale.yml | 14 + .../guzzlehttp/psr7/.github/workflows/ci.yml | 34 + .../psr7/.github/workflows/integration.yml | 37 + .../psr7/.github/workflows/static.yml | 29 + vendor/guzzlehttp/psr7/.php_cs.dist | 56 + vendor/guzzlehttp/psr7/CHANGELOG.md | 324 +- vendor/guzzlehttp/psr7/LICENSE | 9 +- vendor/guzzlehttp/psr7/README.md | 367 +- vendor/guzzlehttp/psr7/composer.json | 47 +- vendor/guzzlehttp/psr7/src/AppendStream.php | 23 +- vendor/guzzlehttp/psr7/src/BufferStream.php | 5 + vendor/guzzlehttp/psr7/src/CachingStream.php | 17 +- vendor/guzzlehttp/psr7/src/DroppingStream.php | 3 + vendor/guzzlehttp/psr7/src/FnStream.php | 14 + vendor/guzzlehttp/psr7/src/Header.php | 71 + vendor/guzzlehttp/psr7/src/InflateStream.php | 6 +- vendor/guzzlehttp/psr7/src/LazyOpenStream.php | 7 +- vendor/guzzlehttp/psr7/src/LimitStream.php | 8 +- vendor/guzzlehttp/psr7/src/Message.php | 252 + vendor/guzzlehttp/psr7/src/MessageTrait.php | 127 +- vendor/guzzlehttp/psr7/src/MimeType.php | 140 + .../guzzlehttp/psr7/src/MultipartStream.php | 19 +- vendor/guzzlehttp/psr7/src/NoSeekStream.php | 5 +- vendor/guzzlehttp/psr7/src/PumpStream.php | 23 +- vendor/guzzlehttp/psr7/src/Query.php | 113 + vendor/guzzlehttp/psr7/src/Request.php | 20 +- vendor/guzzlehttp/psr7/src/Response.php | 33 +- vendor/guzzlehttp/psr7/src/Rfc7230.php | 19 + vendor/guzzlehttp/psr7/src/ServerRequest.php | 47 +- vendor/guzzlehttp/psr7/src/Stream.php | 75 +- .../psr7/src/StreamDecoratorTrait.php | 5 +- vendor/guzzlehttp/psr7/src/StreamWrapper.php | 50 +- vendor/guzzlehttp/psr7/src/UploadedFile.php | 40 +- vendor/guzzlehttp/psr7/src/Uri.php | 182 +- vendor/guzzlehttp/psr7/src/UriComparator.php | 55 + vendor/guzzlehttp/psr7/src/UriNormalizer.php | 3 + vendor/guzzlehttp/psr7/src/UriResolver.php | 3 + vendor/guzzlehttp/psr7/src/Utils.php | 428 ++ vendor/guzzlehttp/psr7/src/functions.php | 710 +- vendor/paragonie/random_compat/LICENSE | 22 + vendor/paragonie/random_compat/composer.json | 38 + .../dist/random_compat.phar.pubkey | 5 + .../dist/random_compat.phar.pubkey.asc | 11 + .../random_compat/lib/byte_safe_strings.php | 195 + .../random_compat/lib/cast_to_int.php | 77 + .../random_compat/lib/error_polyfill.php | 49 + vendor/paragonie/random_compat/lib/random.php | 226 + .../lib/random_bytes_com_dotnet.php | 91 + .../lib/random_bytes_dev_urandom.php | 190 + .../lib/random_bytes_libsodium.php | 91 + .../lib/random_bytes_libsodium_legacy.php | 93 + .../random_compat/lib/random_bytes_mcrypt.php | 79 + .../random_compat/lib/random_int.php | 204 + vendor/pear/console_getopt/.gitignore | 6 + vendor/pear/console_getopt/.travis.yml | 9 + vendor/pear/console_getopt/Console/Getopt.php | 365 ++ vendor/pear/console_getopt/LICENSE | 25 + vendor/pear/console_getopt/README.rst | 26 + vendor/pear/console_getopt/composer.json | 35 + vendor/pear/console_getopt/package.xml | 302 + .../pear/console_getopt/tests/001-getopt.phpt | 63 + .../pear/console_getopt/tests/bug10557.phpt | 22 + .../pear/console_getopt/tests/bug11068.phpt | 44 + .../pear/console_getopt/tests/bug13140.phpt | 75 + vendor/pear/ole/.gitattributes | 3 + vendor/pear/ole/.github/workflows/ci.yaml | 60 + vendor/pear/ole/.github/workflows/cs.yaml | 38 + vendor/pear/ole/.gitignore | 4 + vendor/pear/ole/.php_cs.dist | 11 + vendor/pear/ole/.travis.yml | 43 + vendor/pear/ole/OLE.php | 616 ++ vendor/pear/ole/OLE/ChainedBlockStream.php | 246 + vendor/pear/ole/OLE/PPS.php | 244 + vendor/pear/ole/OLE/PPS/File.php | 130 + vendor/pear/ole/OLE/PPS/Root.php | 724 +++ vendor/pear/ole/README.md | 25 + vendor/pear/ole/composer.json | 45 + vendor/pear/ole/package.xml | 212 + vendor/pear/ole/phpunit.xml.dist | 22 + vendor/pear/pear-core-minimal/README.rst | 26 + vendor/pear/pear-core-minimal/composer.json | 32 + .../pear/pear-core-minimal/src/OS/Guess.php | 395 ++ vendor/pear/pear-core-minimal/src/PEAR.php | 1135 ++++ .../pear/pear-core-minimal/src/PEAR/Error.php | 14 + .../pear-core-minimal/src/PEAR/ErrorStack.php | 979 +++ vendor/pear/pear-core-minimal/src/System.php | 630 ++ vendor/pear/pear_exception/LICENSE | 27 + vendor/pear/pear_exception/PEAR/Exception.php | 456 ++ vendor/pear/pear_exception/composer.json | 41 + .../.github/workflows/ci.yaml | 60 + .../.github/workflows/cs.yaml | 38 + .../pear/spreadsheet_excel_writer/.gitignore | 7 + .../spreadsheet_excel_writer/.php_cs.dist | 11 + .../pear/spreadsheet_excel_writer/.travis.yml | 25 + .../pear/spreadsheet_excel_writer/README.md | 166 + .../Spreadsheet/Excel/Writer.php | 105 + .../Spreadsheet/Excel/Writer/BIFFwriter.php | 268 + .../Spreadsheet/Excel/Writer/Format.php | 1110 ++++ .../Spreadsheet/Excel/Writer/Parser.php | 1704 +++++ .../Spreadsheet/Excel/Writer/Validator.php | 228 + .../Spreadsheet/Excel/Writer/Workbook.php | 1629 +++++ .../Spreadsheet/Excel/Writer/Worksheet.php | 3609 ++++++++++ .../spreadsheet_excel_writer/composer.json | 63 + .../pear/spreadsheet_excel_writer/package.xml | 357 + .../spreadsheet_excel_writer/phpunit.xml.dist | 28 + .../Spreadsheet/Excel/Writer/WorkbookTest.php | 81 + .../Test/Spreadsheet/Excel/WriterTestCase.php | 55 + .../test/fixture/example.xls | Bin 0 -> 3584 bytes .../test/fixture/example2.xls | Bin 0 -> 5120 bytes .../test/fixture/with_format.xls | Bin 0 -> 3584 bytes vendor/ralouphie/getallheaders/LICENSE | 21 + vendor/ralouphie/getallheaders/README.md | 27 + vendor/ralouphie/getallheaders/composer.json | 26 + .../getallheaders/src/getallheaders.php | 46 + .../smarty/{change_log.txt => CHANGELOG.md} | 194 +- vendor/smarty/smarty/LICENSE | 2 +- vendor/smarty/smarty/README.md | 8 +- vendor/smarty/smarty/SECURITY.md | 19 + vendor/smarty/smarty/composer.json | 3 +- .../demo/plugins/cacheresource.memcache.php | 22 +- vendor/smarty/smarty/error_reporting.ini | 1 - .../smarty_internal_configfilelexer.plex | 318 + .../lexer/smarty_internal_configfileparser.y | 346 + .../lexer/smarty_internal_templatelexer.plex | 696 ++ .../lexer/smarty_internal_templateparser.y | 1280 ++++ vendor/smarty/smarty/libs/Smarty.class.php | 7 +- vendor/smarty/smarty/libs/SmartyBC.class.php | 2 +- .../smarty/libs/plugins/function.mailto.php | 11 +- .../smarty/libs/plugins/function.math.php | 32 +- .../smarty/libs/plugins/modifier.escape.php | 7 +- .../libs/plugins/modifiercompiler.escape.php | 3 +- .../smarty_internal_compile_assign.php | 2 +- .../smarty_internal_compile_block.php | 4 +- .../smarty_internal_compile_foreach.php | 10 +- .../smarty_internal_compile_function.php | 13 +- .../smarty_internal_compile_include.php | 4 +- ...ernal_compile_private_special_variable.php | 8 +- .../smarty_internal_config_file_compiler.php | 14 +- .../smarty_internal_errorhandler.php | 2 +- .../smarty_internal_method_registerplugin.php | 2 + .../smarty_internal_parsetree_template.php | 116 +- .../smarty_internal_parsetree_text.php | 29 +- .../smarty_internal_runtime_codeframe.php | 9 +- .../smarty_internal_templatebase.php | 4 +- .../smarty_internal_templatecompilerbase.php | 150 +- .../smarty_internal_templatelexer.php | 12 +- .../smarty_internal_templateparser.php | 15 +- vendor/symfony/polyfill-intl-idn/Idn.php | 923 +++ vendor/symfony/polyfill-intl-idn/Info.php | 23 + vendor/symfony/polyfill-intl-idn/LICENSE | 19 + vendor/symfony/polyfill-intl-idn/README.md | 12 + .../Resources/unidata/DisallowedRanges.php | 375 ++ .../Resources/unidata/Regex.php | 24 + .../Resources/unidata/deviation.php | 8 + .../Resources/unidata/disallowed.php | 2638 ++++++++ .../unidata/disallowed_STD3_mapped.php | 308 + .../unidata/disallowed_STD3_valid.php | 71 + .../Resources/unidata/ignored.php | 273 + .../Resources/unidata/mapped.php | 5778 +++++++++++++++++ .../Resources/unidata/virama.php | 65 + .../symfony/polyfill-intl-idn/bootstrap.php | 141 + .../symfony/polyfill-intl-idn/composer.json | 45 + .../symfony/polyfill-intl-normalizer/LICENSE | 19 + .../polyfill-intl-normalizer/Normalizer.php | 308 + .../polyfill-intl-normalizer/README.md | 14 + .../Resources/stubs/Normalizer.php | 17 + .../unidata/canonicalComposition.php | 945 +++ .../unidata/canonicalDecomposition.php | 2065 ++++++ .../Resources/unidata/combiningClass.php | 876 +++ .../unidata/compatibilityDecomposition.php | 3695 +++++++++++ .../polyfill-intl-normalizer/bootstrap.php | 19 + .../polyfill-intl-normalizer/composer.json | 39 + vendor/symfony/polyfill-php70/LICENSE | 19 + vendor/symfony/polyfill-php70/Php70.php | 74 + vendor/symfony/polyfill-php70/README.md | 28 + .../Resources/stubs/ArithmeticError.php | 5 + .../Resources/stubs/AssertionError.php | 5 + .../Resources/stubs/DivisionByZeroError.php | 5 + .../polyfill-php70/Resources/stubs/Error.php | 5 + .../Resources/stubs/ParseError.php | 5 + ...SessionUpdateTimestampHandlerInterface.php | 23 + .../Resources/stubs/TypeError.php | 5 + vendor/symfony/polyfill-php70/bootstrap.php | 30 + vendor/symfony/polyfill-php70/composer.json | 37 + vendor/symfony/polyfill-php72/LICENSE | 19 + vendor/symfony/polyfill-php72/Php72.php | 217 + vendor/symfony/polyfill-php72/README.md | 28 + vendor/symfony/polyfill-php72/bootstrap.php | 57 + vendor/symfony/polyfill-php72/composer.json | 35 + 261 files changed, 46585 insertions(+), 1908 deletions(-) create mode 100644 vendor/composer/InstalledVersions.php create mode 100644 vendor/composer/include_paths.php create mode 100644 vendor/composer/installed.php create mode 100644 vendor/composer/platform_check.php create mode 100644 vendor/guzzlehttp/guzzle/.php_cs create mode 100644 vendor/guzzlehttp/guzzle/Dockerfile create mode 100644 vendor/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php create mode 100644 vendor/guzzlehttp/guzzle/src/Utils.php create mode 100644 vendor/guzzlehttp/promises/src/Create.php create mode 100644 vendor/guzzlehttp/promises/src/Each.php create mode 100644 vendor/guzzlehttp/promises/src/Is.php create mode 100644 vendor/guzzlehttp/promises/src/Utils.php create mode 100644 vendor/guzzlehttp/psr7/.github/FUNDING.yml create mode 100644 vendor/guzzlehttp/psr7/.github/stale.yml create mode 100644 vendor/guzzlehttp/psr7/.github/workflows/ci.yml create mode 100644 vendor/guzzlehttp/psr7/.github/workflows/integration.yml create mode 100644 vendor/guzzlehttp/psr7/.github/workflows/static.yml create mode 100644 vendor/guzzlehttp/psr7/.php_cs.dist create mode 100644 vendor/guzzlehttp/psr7/src/Header.php create mode 100644 vendor/guzzlehttp/psr7/src/Message.php create mode 100644 vendor/guzzlehttp/psr7/src/MimeType.php create mode 100644 vendor/guzzlehttp/psr7/src/Query.php create mode 100644 vendor/guzzlehttp/psr7/src/Rfc7230.php create mode 100644 vendor/guzzlehttp/psr7/src/UriComparator.php create mode 100644 vendor/guzzlehttp/psr7/src/Utils.php create mode 100644 vendor/paragonie/random_compat/LICENSE create mode 100644 vendor/paragonie/random_compat/composer.json create mode 100644 vendor/paragonie/random_compat/dist/random_compat.phar.pubkey create mode 100644 vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc create mode 100644 vendor/paragonie/random_compat/lib/byte_safe_strings.php create mode 100644 vendor/paragonie/random_compat/lib/cast_to_int.php create mode 100644 vendor/paragonie/random_compat/lib/error_polyfill.php create mode 100644 vendor/paragonie/random_compat/lib/random.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_libsodium.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php create mode 100644 vendor/paragonie/random_compat/lib/random_int.php create mode 100644 vendor/pear/console_getopt/.gitignore create mode 100644 vendor/pear/console_getopt/.travis.yml create mode 100644 vendor/pear/console_getopt/Console/Getopt.php create mode 100644 vendor/pear/console_getopt/LICENSE create mode 100644 vendor/pear/console_getopt/README.rst create mode 100644 vendor/pear/console_getopt/composer.json create mode 100644 vendor/pear/console_getopt/package.xml create mode 100644 vendor/pear/console_getopt/tests/001-getopt.phpt create mode 100644 vendor/pear/console_getopt/tests/bug10557.phpt create mode 100644 vendor/pear/console_getopt/tests/bug11068.phpt create mode 100644 vendor/pear/console_getopt/tests/bug13140.phpt create mode 100644 vendor/pear/ole/.gitattributes create mode 100644 vendor/pear/ole/.github/workflows/ci.yaml create mode 100644 vendor/pear/ole/.github/workflows/cs.yaml create mode 100644 vendor/pear/ole/.gitignore create mode 100644 vendor/pear/ole/.php_cs.dist create mode 100644 vendor/pear/ole/.travis.yml create mode 100644 vendor/pear/ole/OLE.php create mode 100644 vendor/pear/ole/OLE/ChainedBlockStream.php create mode 100644 vendor/pear/ole/OLE/PPS.php create mode 100644 vendor/pear/ole/OLE/PPS/File.php create mode 100644 vendor/pear/ole/OLE/PPS/Root.php create mode 100644 vendor/pear/ole/README.md create mode 100644 vendor/pear/ole/composer.json create mode 100644 vendor/pear/ole/package.xml create mode 100644 vendor/pear/ole/phpunit.xml.dist create mode 100644 vendor/pear/pear-core-minimal/README.rst create mode 100644 vendor/pear/pear-core-minimal/composer.json create mode 100644 vendor/pear/pear-core-minimal/src/OS/Guess.php create mode 100644 vendor/pear/pear-core-minimal/src/PEAR.php create mode 100644 vendor/pear/pear-core-minimal/src/PEAR/Error.php create mode 100644 vendor/pear/pear-core-minimal/src/PEAR/ErrorStack.php create mode 100644 vendor/pear/pear-core-minimal/src/System.php create mode 100644 vendor/pear/pear_exception/LICENSE create mode 100644 vendor/pear/pear_exception/PEAR/Exception.php create mode 100644 vendor/pear/pear_exception/composer.json create mode 100644 vendor/pear/spreadsheet_excel_writer/.github/workflows/ci.yaml create mode 100644 vendor/pear/spreadsheet_excel_writer/.github/workflows/cs.yaml create mode 100644 vendor/pear/spreadsheet_excel_writer/.gitignore create mode 100644 vendor/pear/spreadsheet_excel_writer/.php_cs.dist create mode 100644 vendor/pear/spreadsheet_excel_writer/.travis.yml create mode 100644 vendor/pear/spreadsheet_excel_writer/README.md create mode 100644 vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer.php create mode 100644 vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/BIFFwriter.php create mode 100644 vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Format.php create mode 100644 vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Parser.php create mode 100644 vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Validator.php create mode 100644 vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Workbook.php create mode 100644 vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Worksheet.php create mode 100644 vendor/pear/spreadsheet_excel_writer/composer.json create mode 100644 vendor/pear/spreadsheet_excel_writer/package.xml create mode 100644 vendor/pear/spreadsheet_excel_writer/phpunit.xml.dist create mode 100644 vendor/pear/spreadsheet_excel_writer/test/Test/Spreadsheet/Excel/Writer/WorkbookTest.php create mode 100644 vendor/pear/spreadsheet_excel_writer/test/Test/Spreadsheet/Excel/WriterTestCase.php create mode 100644 vendor/pear/spreadsheet_excel_writer/test/fixture/example.xls create mode 100644 vendor/pear/spreadsheet_excel_writer/test/fixture/example2.xls create mode 100644 vendor/pear/spreadsheet_excel_writer/test/fixture/with_format.xls create mode 100644 vendor/ralouphie/getallheaders/LICENSE create mode 100644 vendor/ralouphie/getallheaders/README.md create mode 100644 vendor/ralouphie/getallheaders/composer.json create mode 100644 vendor/ralouphie/getallheaders/src/getallheaders.php rename vendor/smarty/smarty/{change_log.txt => CHANGELOG.md} (96%) create mode 100644 vendor/smarty/smarty/SECURITY.md delete mode 100644 vendor/smarty/smarty/error_reporting.ini create mode 100644 vendor/smarty/smarty/lexer/smarty_internal_configfilelexer.plex create mode 100644 vendor/smarty/smarty/lexer/smarty_internal_configfileparser.y create mode 100644 vendor/smarty/smarty/lexer/smarty_internal_templatelexer.plex create mode 100644 vendor/smarty/smarty/lexer/smarty_internal_templateparser.y create mode 100644 vendor/symfony/polyfill-intl-idn/Idn.php create mode 100644 vendor/symfony/polyfill-intl-idn/Info.php create mode 100644 vendor/symfony/polyfill-intl-idn/LICENSE create mode 100644 vendor/symfony/polyfill-intl-idn/README.md create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/deviation.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.php create mode 100644 vendor/symfony/polyfill-intl-idn/bootstrap.php create mode 100644 vendor/symfony/polyfill-intl-idn/composer.json create mode 100644 vendor/symfony/polyfill-intl-normalizer/LICENSE create mode 100644 vendor/symfony/polyfill-intl-normalizer/Normalizer.php create mode 100644 vendor/symfony/polyfill-intl-normalizer/README.md create mode 100644 vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php create mode 100644 vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php create mode 100644 vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php create mode 100644 vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php create mode 100644 vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php create mode 100644 vendor/symfony/polyfill-intl-normalizer/bootstrap.php create mode 100644 vendor/symfony/polyfill-intl-normalizer/composer.json create mode 100644 vendor/symfony/polyfill-php70/LICENSE create mode 100644 vendor/symfony/polyfill-php70/Php70.php create mode 100644 vendor/symfony/polyfill-php70/README.md create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/AssertionError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/Error.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/ParseError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/TypeError.php create mode 100644 vendor/symfony/polyfill-php70/bootstrap.php create mode 100644 vendor/symfony/polyfill-php70/composer.json create mode 100644 vendor/symfony/polyfill-php72/LICENSE create mode 100644 vendor/symfony/polyfill-php72/Php72.php create mode 100644 vendor/symfony/polyfill-php72/README.md create mode 100644 vendor/symfony/polyfill-php72/bootstrap.php create mode 100644 vendor/symfony/polyfill-php72/composer.json diff --git a/composer.json b/composer.json index 03719e30..6c02f3ff 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,9 @@ "type": "project", "require": { "guzzlehttp/guzzle": "^6.3", - "smarty/smarty": "^3.1" + "smarty/smarty": "^3.1", + "pear/ole": "^v1.0.0RC8", + "pear/spreadsheet_excel_writer": "^v0.9.7" }, "authors": [ { diff --git a/config.sample.php b/config.sample.php index 66f18e82..577b3b98 100644 --- a/config.sample.php +++ b/config.sample.php @@ -73,19 +73,11 @@ require_once 'pdf.inc.php'; /* - * To enable XLS export you can uncomment the following line and edit - * the settings in xls.inc.php. This option requires the additional installation - * of "Spreadsheet OLE" and "Spreadsheet Excel Writer". They have to be accessible - * from the "include_path" which is set inside "php.ini". - * - * In the Apache Distribution XAMPP it is included by default. - * On gentoo linux systems you can easily add it by typing - * emerge dev-php/PEAR-Spreadsheet_Excel_Writer - * - * Official Website: - * http://pear.php.net/package/Spreadsheet_Excel_Writer/ + * To enable XLS export you can uncomment the following line. + * The required libraries are now included via composer in folders + * vendor/pear/ole and Vendor/pear/spreadsheet_excel_writer */ -// require_once 'xls.inc.php'; +require_once 'xls.inc.php'; /* * To get access to FSK18 rated movies in the german dvdb engine you diff --git a/core/xls.php b/core/xls.php index ee48bb6d..30a8ff0f 100644 --- a/core/xls.php +++ b/core/xls.php @@ -8,7 +8,7 @@ * @package Core * @link http://pear.php.net/package/Spreadsheet_Excel_Writer * @author Chinamann - * @author Andreas G๖tz + * @author Andreas G๏ฟฝtz * @version $Id: xls.php,v 1.8 2008/01/05 13:50:29 andig2 Exp $ */ @@ -17,7 +17,7 @@ require_once './engines/engines.php'; #error_reporting(E_ALL^E_NOTICE); -require_once 'Spreadsheet/Excel/Writer.php'; +require_once 'vendor/autoload.php'; /** * Export PDF document @@ -70,9 +70,9 @@ function xlsexport($WHERE) $titleFormatLent =& $workbook->addFormat(array('Bold' => 1, 'Pattern' => 1)); $titleFormatLent -> setFgColor(14); - $plotFormatNormal =& $workbook->addFormat(); + $plotFormatNormal =& $workbook->addFormat(array('Align' => 'top')); $plotFormatNormal -> setTextWrap(); - $plotFormatLent =& $workbook->addFormat(array('Pattern' => 1)); + $plotFormatLent =& $workbook->addFormat(array('Align' => 'top','Pattern' => 1)); $plotFormatLent -> setTextWrap(); $plotFormatLent -> setFgColor(14); @@ -147,7 +147,8 @@ function xlsexport($WHERE) if ($rowindex == 1) $worksheet->setColumn($columnindex, $columnindex, 50); $imdb = $row['imdbID']; $link = ($imdb) ? engineGetContentUrl($imdb, engineGetEngine($imdb)) : ''; - $worksheet->writeUrl($rowindex, $columnindex, $link, html_entity_decode($title), $format); + if($link <> '') $worksheet->writeUrl($rowindex, $columnindex, $link, html_entity_decode($title), $format); + else $worksheet->writeString($rowindex, $columnindex, leftString(html_entity_decode($row['title']),$text_length), $format); } $columnindex++; } diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php index dc02dfb1..afef3fa2 100644 --- a/vendor/composer/ClassLoader.php +++ b/vendor/composer/ClassLoader.php @@ -37,57 +37,130 @@ * * @author Fabien Potencier * @author Jordi Boggiano - * @see http://www.php-fig.org/psr/psr-0/ - * @see http://www.php-fig.org/psr/psr-4/ + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ */ class ClassLoader { + /** @var ?string */ + private $vendorDir; + // PSR-4 + /** + * @var array[] + * @psalm-var array> + */ private $prefixLengthsPsr4 = array(); + /** + * @var array[] + * @psalm-var array> + */ private $prefixDirsPsr4 = array(); + /** + * @var array[] + * @psalm-var array + */ private $fallbackDirsPsr4 = array(); // PSR-0 + /** + * @var array[] + * @psalm-var array> + */ private $prefixesPsr0 = array(); + /** + * @var array[] + * @psalm-var array + */ private $fallbackDirsPsr0 = array(); + /** @var bool */ private $useIncludePath = false; + + /** + * @var string[] + * @psalm-var array + */ private $classMap = array(); + + /** @var bool */ private $classMapAuthoritative = false; + + /** + * @var bool[] + * @psalm-var array + */ private $missingClasses = array(); + + /** @var ?string */ private $apcuPrefix; + /** + * @var self[] + */ + private static $registeredLoaders = array(); + + /** + * @param ?string $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + } + + /** + * @return string[] + */ public function getPrefixes() { if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', $this->prefixesPsr0); + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); } return array(); } + /** + * @return array[] + * @psalm-return array> + */ public function getPrefixesPsr4() { return $this->prefixDirsPsr4; } + /** + * @return array[] + * @psalm-return array + */ public function getFallbackDirs() { return $this->fallbackDirsPsr0; } + /** + * @return array[] + * @psalm-return array + */ public function getFallbackDirsPsr4() { return $this->fallbackDirsPsr4; } + /** + * @return string[] Array of classname => path + * @psalm-return array + */ public function getClassMap() { return $this->classMap; } /** - * @param array $classMap Class to filename map + * @param string[] $classMap Class to filename map + * @psalm-param array $classMap + * + * @return void */ public function addClassMap(array $classMap) { @@ -102,9 +175,11 @@ public function addClassMap(array $classMap) * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void */ public function add($prefix, $paths, $prepend = false) { @@ -147,11 +222,13 @@ public function add($prefix, $paths, $prepend = false) * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException + * + * @return void */ public function addPsr4($prefix, $paths, $prepend = false) { @@ -195,8 +272,10 @@ public function addPsr4($prefix, $paths, $prepend = false) * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 base directories + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 base directories + * + * @return void */ public function set($prefix, $paths) { @@ -211,10 +290,12 @@ public function set($prefix, $paths) * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException + * + * @return void */ public function setPsr4($prefix, $paths) { @@ -234,6 +315,8 @@ public function setPsr4($prefix, $paths) * Turns on searching the include path for class files. * * @param bool $useIncludePath + * + * @return void */ public function setUseIncludePath($useIncludePath) { @@ -256,6 +339,8 @@ public function getUseIncludePath() * that have not been registered with the class map. * * @param bool $classMapAuthoritative + * + * @return void */ public function setClassMapAuthoritative($classMapAuthoritative) { @@ -276,10 +361,12 @@ public function isClassMapAuthoritative() * APCu prefix to use to cache found/not-found classes, if the extension is enabled. * * @param string|null $apcuPrefix + * + * @return void */ public function setApcuPrefix($apcuPrefix) { - $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; } /** @@ -296,25 +383,44 @@ public function getApcuPrefix() * Registers this instance as an autoloader. * * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void */ public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } } /** * Unregisters this instance as an autoloader. + * + * @return void */ public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } } /** * Loads the given class or interface. * * @param string $class The name of the class - * @return bool|null True if loaded, null otherwise + * @return true|null True if loaded, null otherwise */ public function loadClass($class) { @@ -323,6 +429,8 @@ public function loadClass($class) return true; } + + return null; } /** @@ -367,6 +475,21 @@ public function findFile($class) return $file; } + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ private function findFileWithExtension($class, $ext) { // PSR-4 lookup @@ -377,7 +500,7 @@ private function findFileWithExtension($class, $ext) $subPath = $class; while (false !== $lastPos = strrpos($subPath, '\\')) { $subPath = substr($subPath, 0, $lastPos); - $search = $subPath.'\\'; + $search = $subPath . '\\'; if (isset($this->prefixDirsPsr4[$search])) { $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); foreach ($this->prefixDirsPsr4[$search] as $dir) { @@ -438,6 +561,10 @@ private function findFileWithExtension($class, $ext) * Scope isolated include. * * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + * @private */ function includeFile($file) { diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100644 index 00000000..d50e0c9f --- /dev/null +++ b/vendor/composer/InstalledVersions.php @@ -0,0 +1,350 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array}|array{}|null + */ + private static $installed; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints($constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // 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 = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + 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'; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // 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'; + } else { + self::$installed = array(); + } + } + $installed[] = self::$installed; + + return $installed; + } +} diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index df1b4ab9..bd8d6624 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -6,6 +6,15 @@ $baseDir = dirname($vendorDir); return array( + 'ArithmeticError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php', + 'AssertionError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php', + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', + 'DivisionByZeroError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php', + 'Error' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/Error.php', + 'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + 'PEAR_Exception' => $vendorDir . '/pear/pear_exception/PEAR/Exception.php', + 'ParseError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ParseError.php', + 'SessionUpdateTimestampHandlerInterface' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php', 'Smarty' => $vendorDir . '/smarty/smarty/libs/Smarty.class.php', 'SmartyBC' => $vendorDir . '/smarty/smarty/libs/SmartyBC.class.php', 'SmartyCompilerException' => $vendorDir . '/smarty/smarty/libs/sysplugins/smartycompilerexception.php', @@ -179,4 +188,5 @@ 'Smarty_Variable' => $vendorDir . '/smarty/smarty/libs/sysplugins/smarty_variable.php', 'TPC_yyStackEntry' => $vendorDir . '/smarty/smarty/libs/sysplugins/smarty_internal_configfileparser.php', 'TP_yyStackEntry' => $vendorDir . '/smarty/smarty/libs/sysplugins/smarty_internal_templateparser.php', + 'TypeError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/TypeError.php', ); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index dd37d858..2aada686 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -6,7 +6,13 @@ $baseDir = dirname($vendorDir); return array( + '5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php', + '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', + 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', + '023d27dca8066ef29e6739335ea73bad' => $vendorDir . '/symfony/polyfill-php70/bootstrap.php', + '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php', + 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', ); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php index b7fc0125..c8b4f520 100644 --- a/vendor/composer/autoload_namespaces.php +++ b/vendor/composer/autoload_namespaces.php @@ -6,4 +6,8 @@ $baseDir = dirname($vendorDir); return array( + 'Spreadsheet' => array($vendorDir . '/pear/spreadsheet_excel_writer'), + 'OLE' => array($vendorDir . '/pear/ole'), + 'Console' => array($vendorDir . '/pear/console_getopt'), + '' => array($vendorDir . '/pear/pear-core-minimal/src'), ); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 3c4508cb..1e17d6c9 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -6,6 +6,10 @@ $baseDir = dirname($vendorDir); return array( + 'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'), + 'Symfony\\Polyfill\\Php70\\' => array($vendorDir . '/symfony/polyfill-php70'), + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'), + 'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'), 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'), 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'), diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index c75c2d92..bce17e3a 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -13,19 +13,28 @@ public static function loadClassLoader($class) } } + /** + * @return \Composer\Autoload\ClassLoader + */ public static function getLoader() { if (null !== self::$loader) { return self::$loader; } + require __DIR__ . '/platform_check.php'; + spl_autoload_register(array('ComposerAutoloaderInite567bd5ff0cb1a3c97b67d63eae535f2', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); spl_autoload_unregister(array('ComposerAutoloaderInite567bd5ff0cb1a3c97b67d63eae535f2', 'loadClassLoader')); + $includePaths = require __DIR__ . '/include_paths.php'; + $includePaths[] = get_include_path(); + set_include_path(implode(PATH_SEPARATOR, $includePaths)); + $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { - require_once __DIR__ . '/autoload_static.php'; + require __DIR__ . '/autoload_static.php'; call_user_func(\Composer\Autoload\ComposerStaticInite567bd5ff0cb1a3c97b67d63eae535f2::getInitializer($loader)); } else { @@ -60,11 +69,16 @@ public static function getLoader() } } +/** + * @param string $fileIdentifier + * @param string $file + * @return void + */ function composerRequiree567bd5ff0cb1a3c97b67d63eae535f2($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - require $file; - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; } } diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 2be98a0b..e80d6d89 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -7,12 +7,25 @@ class ComposerStaticInite567bd5ff0cb1a3c97b67d63eae535f2 { public static $files = array ( + '5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php', + '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', + 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', + '023d27dca8066ef29e6739335ea73bad' => __DIR__ . '/..' . '/symfony/polyfill-php70/bootstrap.php', + '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php', 'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php', + 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', ); public static $prefixLengthsPsr4 = array ( + 'S' => + array ( + 'Symfony\\Polyfill\\Php72\\' => 23, + 'Symfony\\Polyfill\\Php70\\' => 23, + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33, + 'Symfony\\Polyfill\\Intl\\Idn\\' => 26, + ), 'P' => array ( 'Psr\\Http\\Message\\' => 17, @@ -26,6 +39,22 @@ class ComposerStaticInite567bd5ff0cb1a3c97b67d63eae535f2 ); public static $prefixDirsPsr4 = array ( + 'Symfony\\Polyfill\\Php72\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php72', + ), + 'Symfony\\Polyfill\\Php70\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php70', + ), + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer', + ), + 'Symfony\\Polyfill\\Intl\\Idn\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn', + ), 'Psr\\Http\\Message\\' => array ( 0 => __DIR__ . '/..' . '/psr/http-message/src', @@ -44,7 +73,44 @@ class ComposerStaticInite567bd5ff0cb1a3c97b67d63eae535f2 ), ); + public static $prefixesPsr0 = array ( + 'S' => + array ( + 'Spreadsheet' => + array ( + 0 => __DIR__ . '/..' . '/pear/spreadsheet_excel_writer', + ), + ), + 'O' => + array ( + 'OLE' => + array ( + 0 => __DIR__ . '/..' . '/pear/ole', + ), + ), + 'C' => + array ( + 'Console' => + array ( + 0 => __DIR__ . '/..' . '/pear/console_getopt', + ), + ), + ); + + public static $fallbackDirsPsr0 = array ( + 0 => __DIR__ . '/..' . '/pear/pear-core-minimal/src', + ); + public static $classMap = array ( + 'ArithmeticError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php', + 'AssertionError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php', + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'DivisionByZeroError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php', + 'Error' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/Error.php', + 'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + 'PEAR_Exception' => __DIR__ . '/..' . '/pear/pear_exception/PEAR/Exception.php', + 'ParseError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ParseError.php', + 'SessionUpdateTimestampHandlerInterface' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php', 'Smarty' => __DIR__ . '/..' . '/smarty/smarty/libs/Smarty.class.php', 'SmartyBC' => __DIR__ . '/..' . '/smarty/smarty/libs/SmartyBC.class.php', 'SmartyCompilerException' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smartycompilerexception.php', @@ -218,6 +284,7 @@ class ComposerStaticInite567bd5ff0cb1a3c97b67d63eae535f2 'Smarty_Variable' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smarty_variable.php', 'TPC_yyStackEntry' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smarty_internal_configfileparser.php', 'TP_yyStackEntry' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smarty_internal_templateparser.php', + 'TypeError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/TypeError.php', ); public static function getInitializer(ClassLoader $loader) @@ -225,6 +292,8 @@ public static function getInitializer(ClassLoader $loader) return \Closure::bind(function () use ($loader) { $loader->prefixLengthsPsr4 = ComposerStaticInite567bd5ff0cb1a3c97b67d63eae535f2::$prefixLengthsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInite567bd5ff0cb1a3c97b67d63eae535f2::$prefixDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInite567bd5ff0cb1a3c97b67d63eae535f2::$prefixesPsr0; + $loader->fallbackDirsPsr0 = ComposerStaticInite567bd5ff0cb1a3c97b67d63eae535f2::$fallbackDirsPsr0; $loader->classMap = ComposerStaticInite567bd5ff0cb1a3c97b67d63eae535f2::$classMap; }, null, ClassLoader::class); diff --git a/vendor/composer/include_paths.php b/vendor/composer/include_paths.php new file mode 100644 index 00000000..0f92da9d --- /dev/null +++ b/vendor/composer/include_paths.php @@ -0,0 +1,14 @@ +=5.5" - }, - "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.0" - }, - "suggest": { - "psr/log": "Required for using the Log middleware" - }, - "time": "2018-04-22T15:46:56+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.3-dev" - } - }, - "installation-source": "dist", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "GuzzleHttp\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle is a PHP HTTP client library", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "rest", - "web service" - ] - }, - { - "name": "guzzlehttp/promises", - "version": "v1.3.1", - "version_normalized": "1.3.1.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "shasum": "" - }, - "require": { - "php": ">=5.5.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0" - }, - "time": "2016-12-20T10:07:11+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle promises library", - "keywords": [ - "promise" - ] - }, - { - "name": "guzzlehttp/psr7", - "version": "1.4.2", - "version_normalized": "1.4.2.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", - "shasum": "" - }, - "require": { - "php": ">=5.4.0", - "psr/http-message": "~1.0" - }, - "provide": { - "psr/http-message-implementation": "1.0" +{ + "packages": [ + { + "name": "guzzlehttp/guzzle", + "version": "6.5.8", + "version_normalized": "6.5.8.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.9", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.17" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.1" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "time": "2022-06-20T22:16:07+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.5-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Mรกrk Sรกgi-Kazรกr", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5.8" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/guzzle" }, - "require-dev": { - "phpunit/phpunit": "~4.0" + { + "name": "guzzlehttp/promises", + "version": "1.5.1", + "version_normalized": "1.5.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "time": "2021-10-22T20:56:57+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/promises" }, - "time": "2017-03-20T17:10:46+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } + { + "name": "guzzlehttp/psr7", + "version": "1.9.0", + "version_normalized": "1.9.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "time": "2022-06-20T21:43:03+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Mรกrk Sรกgi-Kazรกr", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.9.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/psr7" }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] + { + "name": "paragonie/random_compat", + "version": "v2.0.21", + "version_normalized": "2.0.21.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "96c132c7f2f7bc3230723b66e89f8f150b29d5ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/96c132c7f2f7bc3230723b66e89f8f150b29d5ae", + "reference": "96c132c7f2f7bc3230723b66e89f8f150b29d5ae", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "time": "2022-02-16T17:07:03+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "install-path": "../paragonie/random_compat" }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Tobias Schultze", - "homepage": "https://github.com/Tobion" - } - ], - "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": [ - "http", - "message", - "request", - "response", - "stream", - "uri", - "url" - ] - }, - { - "name": "psr/http-message", - "version": "1.0.1", - "version_normalized": "1.0.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + { + "name": "pear/console_getopt", + "version": "v1.4.3", + "version_normalized": "1.4.3.0", + "source": { + "type": "git", + "url": "https://github.com/pear/Console_Getopt.git", + "reference": "a41f8d3e668987609178c7c4a9fe48fecac53fa0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pear/Console_Getopt/zipball/a41f8d3e668987609178c7c4a9fe48fecac53fa0", + "reference": "a41f8d3e668987609178c7c4a9fe48fecac53fa0", + "shasum": "" + }, + "time": "2019-11-20T18:27:48+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Console": "./" + } + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "./" + ], + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Andrei Zmievski", + "email": "andrei@php.net", + "role": "Lead" + }, + { + "name": "Stig Bakken", + "email": "stig@php.net", + "role": "Developer" + }, + { + "name": "Greg Beaver", + "email": "cellog@php.net", + "role": "Helper" + } + ], + "description": "More info available on: http://pear.php.net/package/Console_Getopt", + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=Console_Getopt", + "source": "https://github.com/pear/Console_Getopt" + }, + "install-path": "../pear/console_getopt" }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", - "shasum": "" + { + "name": "pear/ole", + "version": "v1.0.0RC8", + "version_normalized": "1.0.0.0-RC8", + "source": { + "type": "git", + "url": "https://github.com/pear/OLE.git", + "reference": "1ee17e4ac71d6e39ff98f78c4674e8a748d16db3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pear/OLE/zipball/1ee17e4ac71d6e39ff98f78c4674e8a748d16db3", + "reference": "1ee17e4ac71d6e39ff98f78c4674e8a748d16db3", + "shasum": "" + }, + "require": { + "pear/pear_exception": "^1.0", + "php": ">=5.6" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2", + "pear/pear-core-minimal": "^1.10", + "phpunit/phpunit": ">=5 <10", + "sanmai/phpunit-legacy-adapter": "^6 || ^8" + }, + "time": "2021-02-22T12:41:39+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "OLE": "./" + } + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "./" + ], + "license": [ + "PHP-3.01" + ], + "authors": [ + { + "name": "Christian Schmidt", + "email": "schmidt@php.net", + "role": "Lead" + }, + { + "name": "Xavier Noguer", + "email": "xnoguer@php.net", + "role": "Lead" + } + ], + "description": "This package allows reading and writing of OLE (Object Linking and Embedding) compound documents. This format is used as container for Excel (.xls), Word (.doc) and other Microsoft file formats.", + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=OLE", + "source": "https://github.com/pear/OLE" + }, + "install-path": "../pear/ole" }, - "require": { - "php": ">=5.3.0" + { + "name": "pear/pear-core-minimal", + "version": "v1.10.11", + "version_normalized": "1.10.11.0", + "source": { + "type": "git", + "url": "https://github.com/pear/pear-core-minimal.git", + "reference": "68d0d32ada737153b7e93b8d3c710ebe70ac867d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pear/pear-core-minimal/zipball/68d0d32ada737153b7e93b8d3c710ebe70ac867d", + "reference": "68d0d32ada737153b7e93b8d3c710ebe70ac867d", + "shasum": "" + }, + "require": { + "pear/console_getopt": "~1.4", + "pear/pear_exception": "~1.0" + }, + "replace": { + "rsky/pear-core-min": "self.version" + }, + "time": "2021-08-10T22:31:03+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "src/" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Christian Weiske", + "email": "cweiske@php.net", + "role": "Lead" + } + ], + "description": "Minimal set of PEAR core files to be used as composer dependency", + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=PEAR", + "source": "https://github.com/pear/pear-core-minimal" + }, + "install-path": "../pear/pear-core-minimal" }, - "time": "2016-08-06T14:39:51+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } + { + "name": "pear/pear_exception", + "version": "v1.0.2", + "version_normalized": "1.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/pear/PEAR_Exception.git", + "reference": "b14fbe2ddb0b9f94f5b24cf08783d599f776fff0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pear/PEAR_Exception/zipball/b14fbe2ddb0b9f94f5b24cf08783d599f776fff0", + "reference": "b14fbe2ddb0b9f94f5b24cf08783d599f776fff0", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "<9" + }, + "time": "2021-03-21T15:43:46+00:00", + "type": "class", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "classmap": [ + "PEAR/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "." + ], + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Helgi Thormar", + "email": "dufuz@php.net" + }, + { + "name": "Greg Beaver", + "email": "cellog@php.net" + } + ], + "description": "The PEAR Exception base class.", + "homepage": "https://github.com/pear/PEAR_Exception", + "keywords": [ + "exception" + ], + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=PEAR_Exception", + "source": "https://github.com/pear/PEAR_Exception" + }, + "install-path": "../pear/pear_exception" }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } + { + "name": "pear/spreadsheet_excel_writer", + "version": "v0.9.7", + "version_normalized": "0.9.7.0", + "source": { + "type": "git", + "url": "https://github.com/pear/Spreadsheet_Excel_Writer.git", + "reference": "f6e1821bf20cbcd8202b21dc5104b0e5688386c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pear/Spreadsheet_Excel_Writer/zipball/f6e1821bf20cbcd8202b21dc5104b0e5688386c5", + "reference": "f6e1821bf20cbcd8202b21dc5104b0e5688386c5", + "shasum": "" + }, + "require": { + "pear/ole": ">=1.0.0RC4", + "pear/pear-core-minimal": "^1.10", + "php": ">=5.6" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2", + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": ">=5 <10", + "sanmai/phpunit-legacy-adapter": "^6 || ^8" + }, + "time": "2021-01-01T11:29:43+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Spreadsheet": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "./" + ], + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Carsten Schmitz", + "email": "cschmitz@limesurvey.org", + "role": "Lead" + }, + { + "name": "Xavier Noguer", + "email": "xnoguer@php.net", + "role": "Lead" + }, + { + "name": "Franck Lefevre", + "email": "progi1984@gmail.com", + "role": "Developer" + }, + { + "name": "Mika Tuupola", + "email": "tuupola@appelsiini.net", + "role": "Developer" + }, + { + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com", + "role": "Lead" + } + ], + "description": "Allows writing of Excel spreadsheets without the need for COM objects. Supports formulas, images (BMP) and all kinds of formatting for text and cells.", + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=Spreadsheet_Excel_Writer", + "source": "https://github.com/pear/Spreadsheet_Excel_Writer" + }, + "install-path": "../pear/spreadsheet_excel_writer" }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ] - }, - { - "name": "smarty/smarty", - "version": "v3.1.34", - "version_normalized": "3.1.34.0", - "source": { - "type": "git", - "url": "https://github.com/smarty-php/smarty.git", - "reference": "c9f0de05f41b9e52798b268ab1e625fac3b8578c" + { + "name": "psr/http-message", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2016-08-06T14:39:51+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "install-path": "../psr/http-message" }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/smarty-php/smarty/zipball/c9f0de05f41b9e52798b268ab1e625fac3b8578c", - "reference": "c9f0de05f41b9e52798b268ab1e625fac3b8578c", - "shasum": "" + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "version_normalized": "3.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "time": "2019-03-08T08:55:37+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "install-path": "../ralouphie/getallheaders" }, - "require": { - "php": ">=5.2" + { + "name": "smarty/smarty", + "version": "v3.1.45", + "version_normalized": "3.1.45.0", + "source": { + "type": "git", + "url": "https://github.com/smarty-php/smarty.git", + "reference": "a2713ab89e6d773bc4819f11857af7f6b2e353a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/smarty-php/smarty/zipball/a2713ab89e6d773bc4819f11857af7f6b2e353a9", + "reference": "a2713ab89e6d773bc4819f11857af7f6b2e353a9", + "shasum": "" + }, + "require": { + "php": ">=5.2" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^6.5 || ^5.7 || ^4.8", + "smarty/smarty-lexer": "^3.1" + }, + "time": "2022-05-17T12:57:52+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "classmap": [ + "libs/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0" + ], + "authors": [ + { + "name": "Monte Ohrt", + "email": "monte@ohrt.com" + }, + { + "name": "Uwe Tews", + "email": "uwe.tews@googlemail.com" + }, + { + "name": "Rodney Rehm", + "email": "rodney.rehm@medialize.de" + } + ], + "description": "Smarty - the compiling PHP template engine", + "homepage": "http://www.smarty.net", + "keywords": [ + "templating" + ], + "support": { + "forum": "http://www.smarty.net/forums/", + "irc": "irc://irc.freenode.org/smarty", + "issues": "https://github.com/smarty-php/smarty/issues", + "source": "https://github.com/smarty-php/smarty/tree/v3.1.45" + }, + "install-path": "../smarty/smarty" }, - "require-dev": { - "phpunit/phpunit": "6.4.1" + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.19.0", + "version_normalized": "1.19.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "4ad5115c0f5d5172a9fe8147675ec6de266d8826" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/4ad5115c0f5d5172a9fe8147675ec6de266d8826", + "reference": "4ad5115c0f5d5172a9fe8147675ec6de266d8826", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php70": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2020-10-21T09:57:48+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.19.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-intl-idn" }, - "time": "2019-02-28T06:42:20+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1.x-dev" - } + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.19.0", + "version_normalized": "1.19.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "8db0ae7936b42feb370840cf24de1a144fb0ef27" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8db0ae7936b42feb370840cf24de1a144fb0ef27", + "reference": "8db0ae7936b42feb370840cf24de1a144fb0ef27", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2020-10-23T09:01:57+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.19.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-intl-normalizer" }, - "installation-source": "dist", - "autoload": { - "classmap": [ - "libs/" - ] + { + "name": "symfony/polyfill-php70", + "version": "v1.19.0", + "version_normalized": "1.19.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php70.git", + "reference": "3fe414077251a81a1b15b1c709faf5c2fbae3d4e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/3fe414077251a81a1b15b1c709faf5c2fbae3d4e", + "reference": "3fe414077251a81a1b15b1c709faf5c2fbae3d4e", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "~1.0|~2.0|~9.99", + "php": ">=5.3.3" + }, + "time": "2020-10-23T09:01:57+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php70\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php70/tree/v1.19.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php70" }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0" - ], - "authors": [ - { - "name": "Monte Ohrt", - "email": "monte@ohrt.com" - }, - { - "name": "Uwe Tews", - "email": "uwe.tews@googlemail.com" - }, - { - "name": "Rodney Rehm", - "email": "rodney.rehm@medialize.de" - } - ], - "description": "Smarty - the compiling PHP template engine", - "homepage": "http://www.smarty.net", - "keywords": [ - "templating" - ] - } -] + { + "name": "symfony/polyfill-php72", + "version": "v1.19.0", + "version_normalized": "1.19.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "beecef6b463b06954638f02378f52496cb84bacc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/beecef6b463b06954638f02378f52496cb84bacc", + "reference": "beecef6b463b06954638f02378f52496cb84bacc", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2020-10-23T09:01:57+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.19.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php72" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100644 index 00000000..2938615a --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,179 @@ + array( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => NULL, + 'name' => 'andig/videodb', + 'dev' => true, + ), + 'versions' => array( + 'andig/videodb' => array( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => NULL, + 'dev_requirement' => false, + ), + 'guzzlehttp/guzzle' => array( + 'pretty_version' => '6.5.8', + 'version' => '6.5.8.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/guzzle', + 'aliases' => array(), + 'reference' => 'a52f0440530b54fa079ce76e8c5d196a42cad981', + 'dev_requirement' => false, + ), + 'guzzlehttp/promises' => array( + 'pretty_version' => '1.5.1', + 'version' => '1.5.1.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/promises', + 'aliases' => array(), + 'reference' => 'fe752aedc9fd8fcca3fe7ad05d419d32998a06da', + 'dev_requirement' => false, + ), + 'guzzlehttp/psr7' => array( + 'pretty_version' => '1.9.0', + 'version' => '1.9.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/psr7', + 'aliases' => array(), + 'reference' => 'e98e3e6d4f86621a9b75f623996e6bbdeb4b9318', + 'dev_requirement' => false, + ), + 'paragonie/random_compat' => array( + 'pretty_version' => 'v2.0.21', + 'version' => '2.0.21.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../paragonie/random_compat', + 'aliases' => array(), + 'reference' => '96c132c7f2f7bc3230723b66e89f8f150b29d5ae', + 'dev_requirement' => false, + ), + 'pear/console_getopt' => array( + 'pretty_version' => 'v1.4.3', + 'version' => '1.4.3.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../pear/console_getopt', + 'aliases' => array(), + 'reference' => 'a41f8d3e668987609178c7c4a9fe48fecac53fa0', + 'dev_requirement' => false, + ), + 'pear/ole' => array( + 'pretty_version' => 'v1.0.0RC8', + 'version' => '1.0.0.0-RC8', + 'type' => 'library', + 'install_path' => __DIR__ . '/../pear/ole', + 'aliases' => array(), + 'reference' => '1ee17e4ac71d6e39ff98f78c4674e8a748d16db3', + 'dev_requirement' => false, + ), + 'pear/pear-core-minimal' => array( + 'pretty_version' => 'v1.10.11', + 'version' => '1.10.11.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../pear/pear-core-minimal', + 'aliases' => array(), + 'reference' => '68d0d32ada737153b7e93b8d3c710ebe70ac867d', + 'dev_requirement' => false, + ), + 'pear/pear_exception' => array( + 'pretty_version' => 'v1.0.2', + 'version' => '1.0.2.0', + 'type' => 'class', + 'install_path' => __DIR__ . '/../pear/pear_exception', + 'aliases' => array(), + 'reference' => 'b14fbe2ddb0b9f94f5b24cf08783d599f776fff0', + 'dev_requirement' => false, + ), + 'pear/spreadsheet_excel_writer' => array( + 'pretty_version' => 'v0.9.7', + 'version' => '0.9.7.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../pear/spreadsheet_excel_writer', + 'aliases' => array(), + 'reference' => 'f6e1821bf20cbcd8202b21dc5104b0e5688386c5', + 'dev_requirement' => false, + ), + 'psr/http-message' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-message', + 'aliases' => array(), + 'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363', + 'dev_requirement' => false, + ), + 'psr/http-message-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'ralouphie/getallheaders' => array( + 'pretty_version' => '3.0.3', + 'version' => '3.0.3.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ralouphie/getallheaders', + 'aliases' => array(), + 'reference' => '120b605dfeb996808c31b6477290a714d356e822', + 'dev_requirement' => false, + ), + 'rsky/pear-core-min' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v1.10.11', + ), + ), + 'smarty/smarty' => array( + 'pretty_version' => 'v3.1.45', + 'version' => '3.1.45.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../smarty/smarty', + 'aliases' => array(), + 'reference' => 'a2713ab89e6d773bc4819f11857af7f6b2e353a9', + 'dev_requirement' => false, + ), + 'symfony/polyfill-intl-idn' => array( + 'pretty_version' => 'v1.19.0', + 'version' => '1.19.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn', + 'aliases' => array(), + 'reference' => '4ad5115c0f5d5172a9fe8147675ec6de266d8826', + 'dev_requirement' => false, + ), + 'symfony/polyfill-intl-normalizer' => array( + 'pretty_version' => 'v1.19.0', + 'version' => '1.19.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', + 'aliases' => array(), + 'reference' => '8db0ae7936b42feb370840cf24de1a144fb0ef27', + 'dev_requirement' => false, + ), + 'symfony/polyfill-php70' => array( + 'pretty_version' => 'v1.19.0', + 'version' => '1.19.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php70', + 'aliases' => array(), + 'reference' => '3fe414077251a81a1b15b1c709faf5c2fbae3d4e', + 'dev_requirement' => false, + ), + 'symfony/polyfill-php72' => array( + 'pretty_version' => 'v1.19.0', + 'version' => '1.19.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php72', + 'aliases' => array(), + 'reference' => 'beecef6b463b06954638f02378f52496cb84bacc', + 'dev_requirement' => false, + ), + ), +); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php new file mode 100644 index 00000000..8b379f44 --- /dev/null +++ b/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 50600)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 5.6.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/vendor/guzzlehttp/guzzle/.php_cs b/vendor/guzzlehttp/guzzle/.php_cs new file mode 100644 index 00000000..2dd5036c --- /dev/null +++ b/vendor/guzzlehttp/guzzle/.php_cs @@ -0,0 +1,23 @@ +setRiskyAllowed(true) + ->setRules([ + '@PSR2' => true, + 'array_syntax' => ['syntax' => 'short'], + 'declare_strict_types' => false, + 'concat_space' => ['spacing'=>'one'], + 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'], + 'ordered_imports' => true, + // 'phpdoc_align' => ['align'=>'vertical'], + // 'native_function_invocation' => true, + ]) + ->setFinder( + PhpCsFixer\Finder::create() + ->in(__DIR__.'/src') + ->in(__DIR__.'/tests') + ->name('*.php') + ) +; + +return $config; diff --git a/vendor/guzzlehttp/guzzle/CHANGELOG.md b/vendor/guzzlehttp/guzzle/CHANGELOG.md index 17badd75..b053017a 100644 --- a/vendor/guzzlehttp/guzzle/CHANGELOG.md +++ b/vendor/guzzlehttp/guzzle/CHANGELOG.md @@ -1,5 +1,70 @@ # Change Log +## 6.5.8 - 2022-06-20 + +* Fix change in port should be considered a change in origin +* Fix `CURLOPT_HTTPAUTH` option not cleared on change of origin + +## 6.5.7 - 2022-06-09 + +* Fix failure to strip Authorization header on HTTP downgrade +* Fix failure to strip the Cookie header on change in host or HTTP downgrade + +## 6.5.6 - 2022-05-25 + +* Fix cross-domain cookie leakage + +## 6.5.5 - 2020-06-16 + +* Unpin version constraint for `symfony/polyfill-intl-idn` [#2678](https://github.com/guzzle/guzzle/pull/2678) + +## 6.5.4 - 2020-05-25 + +* Fix various intl icu issues [#2626](https://github.com/guzzle/guzzle/pull/2626) + +## 6.5.3 - 2020-04-18 + +* Use Symfony intl-idn polyfill [#2550](https://github.com/guzzle/guzzle/pull/2550) +* Remove use of internal functions [#2548](https://github.com/guzzle/guzzle/pull/2548) + +## 6.5.2 - 2019-12-23 + +* idn_to_ascii() fix for old PHP versions [#2489](https://github.com/guzzle/guzzle/pull/2489) + +## 6.5.1 - 2019-12-21 + +* Better defaults for PHP installations with old ICU lib [#2454](https://github.com/guzzle/guzzle/pull/2454) +* IDN support for redirects [#2424](https://github.com/guzzle/guzzle/pull/2424) + +## 6.5.0 - 2019-12-07 + +* Improvement: Added support for reset internal queue in MockHandler. [#2143](https://github.com/guzzle/guzzle/pull/2143) +* Improvement: Added support to pass arbitrary options to `curl_multi_init`. [#2287](https://github.com/guzzle/guzzle/pull/2287) +* Fix: Gracefully handle passing `null` to the `header` option. [#2132](https://github.com/guzzle/guzzle/pull/2132) +* Fix: `RetryMiddleware` did not do exponential delay between retries due unit mismatch. [#2132](https://github.com/guzzle/guzzle/pull/2132) + Previously, `RetryMiddleware` would sleep for 1 millisecond, then 2 milliseconds, then 4 milliseconds. + **After this change, `RetryMiddleware` will sleep for 1 second, then 2 seconds, then 4 seconds.** + `Middleware::retry()` accepts a second callback parameter to override the default timeouts if needed. +* Fix: Prevent undefined offset when using array for ssl_key options. [#2348](https://github.com/guzzle/guzzle/pull/2348) +* Deprecated `ClientInterface::VERSION` + +## 6.4.1 - 2019-10-23 + +* No `guzzle.phar` was created in 6.4.0 due expired API token. This release will fix that +* Added `parent::__construct()` to `FileCookieJar` and `SessionCookieJar` + +## 6.4.0 - 2019-10-23 + +* Improvement: Improved error messages when using curl < 7.21.2 [#2108](https://github.com/guzzle/guzzle/pull/2108) +* Fix: Test if response is readable before returning a summary in `RequestException::getResponseBodySummary()` [#2081](https://github.com/guzzle/guzzle/pull/2081) +* Fix: Add support for GUZZLE_CURL_SELECT_TIMEOUT environment variable [#2161](https://github.com/guzzle/guzzle/pull/2161) +* Improvement: Added `GuzzleHttp\Exception\InvalidArgumentException` [#2163](https://github.com/guzzle/guzzle/pull/2163) +* Improvement: Added `GuzzleHttp\_current_time()` to use `hrtime()` if that function exists. [#2242](https://github.com/guzzle/guzzle/pull/2242) +* Improvement: Added curl's `appconnect_time` in `TransferStats` [#2284](https://github.com/guzzle/guzzle/pull/2284) +* Improvement: Make GuzzleException extend Throwable wherever it's available [#2273](https://github.com/guzzle/guzzle/pull/2273) +* Fix: Prevent concurrent writes to file when saving `CookieJar` [#2335](https://github.com/guzzle/guzzle/pull/2335) +* Improvement: Update `MockHandler` so we can test transfer time [#2362](https://github.com/guzzle/guzzle/pull/2362) + ## 6.3.3 - 2018-04-22 * Fix: Default headers when decode_content is specified diff --git a/vendor/guzzlehttp/guzzle/Dockerfile b/vendor/guzzlehttp/guzzle/Dockerfile new file mode 100644 index 00000000..f6a09523 --- /dev/null +++ b/vendor/guzzlehttp/guzzle/Dockerfile @@ -0,0 +1,18 @@ +FROM composer:latest as setup + +RUN mkdir /guzzle + +WORKDIR /guzzle + +RUN set -xe \ + && composer init --name=guzzlehttp/test --description="Simple project for testing Guzzle scripts" --author="Mรกrk Sรกgi-Kazรกr " --no-interaction \ + && composer require guzzlehttp/guzzle + + +FROM php:7.3 + +RUN mkdir /guzzle + +WORKDIR /guzzle + +COPY --from=setup /guzzle /guzzle diff --git a/vendor/guzzlehttp/guzzle/LICENSE b/vendor/guzzlehttp/guzzle/LICENSE index 50a177b0..fd2375d8 100644 --- a/vendor/guzzlehttp/guzzle/LICENSE +++ b/vendor/guzzlehttp/guzzle/LICENSE @@ -1,4 +1,12 @@ -Copyright (c) 2011-2018 Michael Dowling, https://github.com/mtdowling +The MIT License (MIT) + +Copyright (c) 2011 Michael Dowling +Copyright (c) 2012 Jeremy Lindblom +Copyright (c) 2014 Graham Campbell +Copyright (c) 2015 Mรกrk Sรกgi-Kazรกr +Copyright (c) 2015 Tobias Schultze +Copyright (c) 2016 Tobias Nyholm +Copyright (c) 2016 George Mponos Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/guzzlehttp/guzzle/README.md b/vendor/guzzlehttp/guzzle/README.md index bcd18b8e..bc98e1a1 100644 --- a/vendor/guzzlehttp/guzzle/README.md +++ b/vendor/guzzlehttp/guzzle/README.md @@ -1,8 +1,9 @@ -Guzzle, PHP HTTP client -======================= +![Guzzle](.github/logo.png?raw=true) + +# Guzzle, PHP HTTP client [![Latest Version](https://img.shields.io/github/release/guzzle/guzzle.svg?style=flat-square)](https://github.com/guzzle/guzzle/releases) -[![Build Status](https://img.shields.io/travis/guzzle/guzzle.svg?style=flat-square)](https://travis-ci.org/guzzle/guzzle) +[![Build Status](https://img.shields.io/github/workflow/status/guzzle/guzzle/CI?label=ci%20build&style=flat-square)](https://github.com/guzzle/guzzle/actions?query=workflow%3ACI) [![Total Downloads](https://img.shields.io/packagist/dt/guzzlehttp/guzzle.svg?style=flat-square)](https://packagist.org/packages/guzzlehttp/guzzle) Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and @@ -21,33 +22,35 @@ trivial to integrate with web services. ```php $client = new \GuzzleHttp\Client(); -$res = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle'); -echo $res->getStatusCode(); -// 200 -echo $res->getHeaderLine('content-type'); -// 'application/json; charset=utf8' -echo $res->getBody(); -// '{"id": 1420053, "name": "guzzle", ...}' - -// Send an asynchronous request. +$response = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle'); + +echo $response->getStatusCode(); # 200 +echo $response->getHeaderLine('content-type'); # 'application/json; charset=utf8' +echo $response->getBody(); # '{"id": 1420053, "name": "guzzle", ...}' + +# Send an asynchronous request. $request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org'); $promise = $client->sendAsync($request)->then(function ($response) { echo 'I completed! ' . $response->getBody(); }); + $promise->wait(); ``` ## Help and docs -- [Documentation](http://guzzlephp.org/) -- [Stack Overflow](http://stackoverflow.com/questions/tagged/guzzle) +We use GitHub issues only to discuss bugs and new features. For support please refer to: + +- [Documentation](https://docs.guzzlephp.org) +- [Stack Overflow](https://stackoverflow.com/questions/tagged/guzzle) +- [#guzzle](https://app.slack.com/client/T0D2S9JCT/CE6UAAKL4) channel on [PHP-HTTP Slack](https://slack.httplug.io/) - [Gitter](https://gitter.im/guzzle/guzzle) ## Installing Guzzle The recommended way to install Guzzle is through -[Composer](http://getcomposer.org). +[Composer](https://getcomposer.org/). ```bash # Install Composer @@ -57,7 +60,7 @@ curl -sS https://getcomposer.org/installer | php Next, run the Composer command to install the latest stable version of Guzzle: ```bash -php composer.phar require guzzlehttp/guzzle +composer require guzzlehttp/guzzle ``` After installing, you need to require Composer's autoloader: @@ -69,23 +72,26 @@ require 'vendor/autoload.php'; You can then later update Guzzle using composer: ```bash -composer.phar update +composer update ``` ## Version Guidance -| Version | Status | Packagist | Namespace | Repo | Docs | PSR-7 | PHP Version | -|---------|------------|---------------------|--------------|---------------------|---------------------|-------|-------------| -| 3.x | EOL | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No | >= 5.3.3 | -| 4.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A | No | >= 5.4 | -| 5.x | Maintained | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >= 5.4 | -| 6.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes | >= 5.5 | +| Version | Status | Packagist | Namespace | Repo | Docs | PSR-7 | PHP Version | +|---------|----------------|---------------------|--------------|---------------------|---------------------|-------|--------------| +| 3.x | EOL | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No | >=5.3.3,<7.0 | +| 4.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A | No | >=5.4,<7.0 | +| 5.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >=5.4,<7.4 | +| 6.x | Security fixes | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes | >=5.5,<8.0 | +| 7.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes | >=7.2.5,<8.2 | [guzzle-3-repo]: https://github.com/guzzle/guzzle3 [guzzle-4-repo]: https://github.com/guzzle/guzzle/tree/4.x [guzzle-5-repo]: https://github.com/guzzle/guzzle/tree/5.3 -[guzzle-6-repo]: https://github.com/guzzle/guzzle -[guzzle-3-docs]: http://guzzle3.readthedocs.org/en/latest/ -[guzzle-5-docs]: http://guzzle.readthedocs.org/en/5.3/ -[guzzle-6-docs]: http://guzzle.readthedocs.org/en/latest/ +[guzzle-6-repo]: https://github.com/guzzle/guzzle/tree/6.5 +[guzzle-7-repo]: https://github.com/guzzle/guzzle +[guzzle-3-docs]: https://guzzle3.readthedocs.io/ +[guzzle-5-docs]: https://docs.guzzlephp.org/en/5.3/ +[guzzle-6-docs]: https://docs.guzzlephp.org/en/6.5/ +[guzzle-7-docs]: https://docs.guzzlephp.org/en/latest/ diff --git a/vendor/guzzlehttp/guzzle/composer.json b/vendor/guzzlehttp/guzzle/composer.json index 1f328e30..a57d78f6 100644 --- a/vendor/guzzlehttp/guzzle/composer.json +++ b/vendor/guzzlehttp/guzzle/composer.json @@ -2,43 +2,91 @@ "name": "guzzlehttp/guzzle", "type": "library", "description": "Guzzle is a PHP HTTP client library", - "keywords": ["framework", "http", "rest", "web service", "curl", "client", "HTTP client"], + "keywords": [ + "framework", + "http", + "rest", + "web service", + "curl", + "client", + "HTTP client" + ], "homepage": "http://guzzlephp.org/", "license": "MIT", "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Mรกrk Sรกgi-Kazรกr", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], "require": { "php": ">=5.5", - "guzzlehttp/psr7": "^1.4", - "guzzlehttp/promises": "^1.0" + "ext-json": "*", + "symfony/polyfill-intl-idn": "^1.17", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.9" }, "require-dev": { "ext-curl": "*", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.0" + "psr/log": "^1.1" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "config": { + "sort-packages": true, + "allow-plugins": { + "bamarni/composer-bin-plugin": true + } + }, + "extra": { + "branch-alias": { + "dev-master": "6.5-dev" + } }, "autoload": { - "files": ["src/functions_include.php"], "psr-4": { "GuzzleHttp\\": "src/" - } + }, + "files": [ + "src/functions_include.php" + ] }, "autoload-dev": { "psr-4": { "GuzzleHttp\\Tests\\": "tests/" } - }, - "suggest": { - "psr/log": "Required for using the Log middleware" - }, - "extra": { - "branch-alias": { - "dev-master": "6.3-dev" - } } } diff --git a/vendor/guzzlehttp/guzzle/src/Client.php b/vendor/guzzlehttp/guzzle/src/Client.php index 80417918..315a022c 100644 --- a/vendor/guzzlehttp/guzzle/src/Client.php +++ b/vendor/guzzlehttp/guzzle/src/Client.php @@ -2,11 +2,12 @@ namespace GuzzleHttp; use GuzzleHttp\Cookie\CookieJar; +use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Promise; use GuzzleHttp\Psr7; -use Psr\Http\Message\UriInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\UriInterface; /** * @method ResponseInterface get(string|UriInterface $uri, array $options = []) @@ -46,9 +47,8 @@ class Client implements ClientInterface * wire. The function is called with a Psr7\Http\Message\RequestInterface * and array of transfer options, and must return a * GuzzleHttp\Promise\PromiseInterface that is fulfilled with a - * Psr7\Http\Message\ResponseInterface on success. "handler" is a - * constructor only option that cannot be overridden in per/request - * options. If no handler is provided, a default handler will be created + * Psr7\Http\Message\ResponseInterface on success. + * If no handler is provided, a default handler will be created * that enables all of the request options below by attaching all of the * default middleware to the handler. * - base_uri: (string|UriInterface) Base URI of the client that is merged @@ -75,6 +75,12 @@ public function __construct(array $config = []) $this->configureDefaults($config); } + /** + * @param string $method + * @param array $args + * + * @return Promise\PromiseInterface + */ public function __call($method, $args) { if (count($args) < 1) { @@ -89,6 +95,14 @@ public function __call($method, $args) : $this->request($method, $uri, $opts); } + /** + * Asynchronously send an HTTP request. + * + * @param array $options Request options to apply to the given + * request and to the transfer. See \GuzzleHttp\RequestOptions. + * + * @return Promise\PromiseInterface + */ public function sendAsync(RequestInterface $request, array $options = []) { // Merge the base URI into the request URI if needed. @@ -100,12 +114,35 @@ public function sendAsync(RequestInterface $request, array $options = []) ); } + /** + * Send an HTTP request. + * + * @param array $options Request options to apply to the given + * request and to the transfer. See \GuzzleHttp\RequestOptions. + * + * @return ResponseInterface + * @throws GuzzleException + */ public function send(RequestInterface $request, array $options = []) { $options[RequestOptions::SYNCHRONOUS] = true; return $this->sendAsync($request, $options)->wait(); } + /** + * Create and send an asynchronous HTTP request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. Use an array to provide a URL + * template and additional variables to use in the URL template expansion. + * + * @param string $method HTTP method + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. See \GuzzleHttp\RequestOptions. + * + * @return Promise\PromiseInterface + */ public function requestAsync($method, $uri = '', array $options = []) { $options = $this->prepareDefaults($options); @@ -125,12 +162,37 @@ public function requestAsync($method, $uri = '', array $options = []) return $this->transfer($request, $options); } + /** + * Create and send an HTTP request. + * + * Use an absolute path to override the base path of the client, or a + * relative path to append to the base path of the client. The URL can + * contain the query string as well. + * + * @param string $method HTTP method. + * @param string|UriInterface $uri URI object or string. + * @param array $options Request options to apply. See \GuzzleHttp\RequestOptions. + * + * @return ResponseInterface + * @throws GuzzleException + */ public function request($method, $uri = '', array $options = []) { $options[RequestOptions::SYNCHRONOUS] = true; return $this->requestAsync($method, $uri, $options)->wait(); } + /** + * Get a client configuration option. + * + * These options include default request options of the client, a "handler" + * (if utilized by the concrete client), and a "base_uri" if utilized by + * the concrete client. + * + * @param string|null $option The config option to retrieve. + * + * @return mixed + */ public function getConfig($option = null) { return $option === null @@ -138,6 +200,11 @@ public function getConfig($option = null) : (isset($this->config[$option]) ? $this->config[$option] : null); } + /** + * @param string|null $uri + * + * @return UriInterface + */ private function buildUri($uri, array $config) { // for BC we accept null which would otherwise fail in uri_for @@ -147,6 +214,11 @@ private function buildUri($uri, array $config) $uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri); } + if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) { + $idnOptions = ($config['idn_conversion'] === true) ? IDNA_DEFAULT : $config['idn_conversion']; + $uri = Utils::idnUriConvert($uri, $idnOptions); + } + return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri; } @@ -154,6 +226,7 @@ private function buildUri($uri, array $config) * Configures the default options for a client. * * @param array $config + * @return void */ private function configureDefaults(array $config) { @@ -162,7 +235,8 @@ private function configureDefaults(array $config) 'http_errors' => true, 'decode_content' => true, 'verify' => true, - 'cookies' => false + 'cookies' => false, + 'idn_conversion' => true, ]; // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set. @@ -170,7 +244,7 @@ private function configureDefaults(array $config) // We can only trust the HTTP_PROXY environment variable in a CLI // process due to the fact that PHP has no reliable mechanism to // get environment variables that start with "HTTP_". - if (php_sapi_name() == 'cli' && getenv('HTTP_PROXY')) { + if (php_sapi_name() === 'cli' && getenv('HTTP_PROXY')) { $defaults['proxy']['http'] = getenv('HTTP_PROXY'); } @@ -210,7 +284,7 @@ private function configureDefaults(array $config) * * @return array */ - private function prepareDefaults($options) + private function prepareDefaults(array $options) { $defaults = $this->config; @@ -225,7 +299,7 @@ private function prepareDefaults($options) if (array_key_exists('headers', $options)) { // Allows default headers to be unset. if ($options['headers'] === null) { - $defaults['_conditional'] = null; + $defaults['_conditional'] = []; unset($options['headers']); } elseif (!is_array($options['headers'])) { throw new \InvalidArgumentException('headers must be an array'); @@ -251,8 +325,7 @@ private function prepareDefaults($options) * The URI of the request is not modified and the request options are used * as-is without merging in default options. * - * @param RequestInterface $request - * @param array $options + * @param array $options See \GuzzleHttp\RequestOptions. * * @return Promise\PromiseInterface */ @@ -271,6 +344,7 @@ private function transfer(RequestInterface $request, array $options) } $request = $this->applyOptions($request, $options); + /** @var HandlerStack $handler */ $handler = $options['handler']; try { @@ -411,6 +485,11 @@ private function applyOptions(RequestInterface $request, array &$options) return $request; } + /** + * Throw Exception with pre-set message. + * @return void + * @throws \InvalidArgumentException Invalid body. + */ private function invalidBody() { throw new \InvalidArgumentException('Passing in the "body" request ' diff --git a/vendor/guzzlehttp/guzzle/src/ClientInterface.php b/vendor/guzzlehttp/guzzle/src/ClientInterface.php index 2dbcffa4..638b75dc 100644 --- a/vendor/guzzlehttp/guzzle/src/ClientInterface.php +++ b/vendor/guzzlehttp/guzzle/src/ClientInterface.php @@ -1,8 +1,8 @@ cookies as $cookie) { @@ -103,6 +103,8 @@ public function getCookieByName($name) return $cookie; } } + + return null; } public function toArray() @@ -120,7 +122,7 @@ public function clear($domain = null, $path = null, $name = null) } elseif (!$path) { $this->cookies = array_filter( $this->cookies, - function (SetCookie $cookie) use ($path, $domain) { + function (SetCookie $cookie) use ($domain) { return !$cookie->matchesDomain($domain); } ); @@ -238,6 +240,11 @@ public function extractCookies( if (0 !== strpos($sc->getPath(), '/')) { $sc->setPath($this->getCookiePathFromRequest($request)); } + if (!$sc->matchesDomain($request->getUri()->getHost())) { + continue; + } + // Note: At this point `$sc->getDomain()` being a public suffix should + // be rejected, but we don't want to pull in the full PSL dependency. $this->setCookie($sc); } } diff --git a/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php b/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php index 2cf298a8..6ee11885 100644 --- a/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php +++ b/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php @@ -58,9 +58,9 @@ public function setCookie(SetCookie $cookie); * arguments, then the cookie with the specified name, path and domain is * removed. * - * @param string $domain Clears cookies matching a domain - * @param string $path Clears cookies matching a domain and path - * @param string $name Clears cookies matching a domain, path, and name + * @param string|null $domain Clears cookies matching a domain + * @param string|null $path Clears cookies matching a domain and path + * @param string|null $name Clears cookies matching a domain, path, and name * * @return CookieJarInterface */ diff --git a/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php b/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php index 9887c1d5..3fb8600e 100644 --- a/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php +++ b/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php @@ -23,6 +23,7 @@ class FileCookieJar extends CookieJar */ public function __construct($cookieFile, $storeSessionCookies = false) { + parent::__construct(); $this->filename = $cookieFile; $this->storeSessionCookies = $storeSessionCookies; @@ -56,7 +57,7 @@ public function save($filename) } $jsonStr = \GuzzleHttp\json_encode($json); - if (false === file_put_contents($filename, $jsonStr)) { + if (false === file_put_contents($filename, $jsonStr, LOCK_EX)) { throw new \RuntimeException("Unable to save file {$filename}"); } } diff --git a/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php b/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php index 4497bcf0..0224a244 100644 --- a/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php +++ b/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php @@ -22,6 +22,7 @@ class SessionCookieJar extends CookieJar */ public function __construct($sessionKey, $storeSessionCookies = false) { + parent::__construct(); $this->sessionKey = $sessionKey; $this->storeSessionCookies = $storeSessionCookies; $this->load(); diff --git a/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php b/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php index f6993943..55f6901a 100644 --- a/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php +++ b/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php @@ -227,7 +227,7 @@ public function setExpires($timestamp) /** * Get whether or not this is a secure cookie * - * @return null|bool + * @return bool|null */ public function getSecure() { @@ -247,7 +247,7 @@ public function setSecure($secure) /** * Get whether or not this is a session cookie * - * @return null|bool + * @return bool|null */ public function getDiscard() { @@ -333,12 +333,19 @@ public function matchesPath($requestPath) */ public function matchesDomain($domain) { + $cookieDomain = $this->getDomain(); + if (null === $cookieDomain) { + return true; + } + // Remove the leading '.' as per spec in RFC 6265. // http://tools.ietf.org/html/rfc6265#section-5.2.3 - $cookieDomain = ltrim($this->getDomain(), '.'); + $cookieDomain = ltrim(strtolower($cookieDomain), '.'); + + $domain = strtolower($domain); // Domain not set or exact match. - if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) { + if ('' === $cookieDomain || $domain === $cookieDomain) { return true; } diff --git a/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php b/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php index f95c09f2..4cfd393c 100644 --- a/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php +++ b/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php @@ -4,4 +4,6 @@ /** * Exception when a client error is encountered (4xx codes) */ -class ClientException extends BadResponseException {} +class ClientException extends BadResponseException +{ +} diff --git a/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php b/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php index 510778f6..27b2722b 100644 --- a/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php +++ b/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php @@ -1,13 +1,23 @@ getBody(); - - if (!$body->isSeekable()) { - return null; - } - - $size = $body->getSize(); - - if ($size === 0) { - return null; - } - - $summary = $body->read(120); - $body->rewind(); - - if ($size > 120) { - $summary .= ' (truncated...)'; - } - - // Matches any printable character, including unicode characters: - // letters, marks, numbers, punctuation, spacing, and separators. - if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) { - return null; - } - - return $summary; + return \GuzzleHttp\Psr7\get_message_body_summary($response); } /** - * Obfuscates URI if there is an username and a password present + * Obfuscates URI if there is a username and a password present * * @param UriInterface $uri * * @return UriInterface */ - private static function obfuscateUri($uri) + private static function obfuscateUri(UriInterface $uri) { $userInfo = $uri->getUserInfo(); diff --git a/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php b/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php index 7cdd3408..127094c1 100644 --- a/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php +++ b/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php @@ -4,4 +4,6 @@ /** * Exception when a server error is encountered (5xx codes) */ -class ServerException extends BadResponseException {} +class ServerException extends BadResponseException +{ +} diff --git a/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php b/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php index b60a9678..fff05251 100644 --- a/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php +++ b/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php @@ -1,4 +1,6 @@ handle); + $curlStats['appconnect_time'] = curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME); $stats = new TransferStats( $easy->request, $easy->response, @@ -136,7 +140,9 @@ private static function finishError( $ctx = [ 'errno' => $easy->errno, 'error' => curl_error($easy->handle), + 'appconnect_time' => curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME), ] + curl_getinfo($easy->handle); + $ctx[self::CURL_VERSION_STR] = curl_version()['version']; $factory->release($easy); // Retry when nothing is present or when curl failed to rewind. @@ -172,13 +178,22 @@ private static function createRejection(EasyHandle $easy, array $ctx) ) ); } - - $message = sprintf( - 'cURL error %s: %s (%s)', - $ctx['errno'], - $ctx['error'], - 'see http://curl.haxx.se/libcurl/c/libcurl-errors.html' - ); + if (version_compare($ctx[self::CURL_VERSION_STR], self::LOW_CURL_VERSION_NUMBER)) { + $message = sprintf( + 'cURL error %s: %s (%s)', + $ctx['errno'], + $ctx['error'], + 'see https://curl.haxx.se/libcurl/c/libcurl-errors.html' + ); + } else { + $message = sprintf( + 'cURL error %s: %s (%s) for %s', + $ctx['errno'], + $ctx['error'], + 'see https://curl.haxx.se/libcurl/c/libcurl-errors.html', + $easy->request->getUri() + ); + } // Create a connection exception if it was a specific error code. $error = isset($connectionErrors[$easy->errno]) @@ -439,11 +454,16 @@ private function applyHandlerOptions(EasyHandle $easy, array &$conf) } if (isset($options['ssl_key'])) { - $sslKey = $options['ssl_key']; - if (is_array($sslKey)) { - $conf[CURLOPT_SSLKEYPASSWD] = $sslKey[1]; - $sslKey = $sslKey[0]; + if (is_array($options['ssl_key'])) { + if (count($options['ssl_key']) === 2) { + list($sslKey, $conf[CURLOPT_SSLKEYPASSWD]) = $options['ssl_key']; + } else { + list($sslKey) = $options['ssl_key']; + } } + + $sslKey = isset($sslKey) ? $sslKey: $options['ssl_key']; + if (!file_exists($sslKey)) { throw new \InvalidArgumentException( "SSL private key not found: {$sslKey}" diff --git a/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php b/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php index 2754d8e4..564c95f4 100644 --- a/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php +++ b/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php @@ -3,7 +3,7 @@ use GuzzleHttp\Promise as P; use GuzzleHttp\Promise\Promise; -use GuzzleHttp\Psr7; +use GuzzleHttp\Utils; use Psr\Http\Message\RequestInterface; /** @@ -23,6 +23,7 @@ class CurlMultiHandler private $active; private $handles = []; private $delays = []; + private $options = []; /** * This handler accepts the following options: @@ -30,6 +31,8 @@ class CurlMultiHandler * - handle_factory: An optional factory used to create curl handles * - select_timeout: Optional timeout (in seconds) to block before timing * out while selecting curl handles. Defaults to 1 second. + * - options: An associative array of CURLMOPT_* options and + * corresponding values for curl_multi_setopt() * * @param array $options */ @@ -37,14 +40,31 @@ public function __construct(array $options = []) { $this->factory = isset($options['handle_factory']) ? $options['handle_factory'] : new CurlFactory(50); - $this->selectTimeout = isset($options['select_timeout']) - ? $options['select_timeout'] : 1; + + if (isset($options['select_timeout'])) { + $this->selectTimeout = $options['select_timeout']; + } elseif ($selectTimeout = getenv('GUZZLE_CURL_SELECT_TIMEOUT')) { + $this->selectTimeout = $selectTimeout; + } else { + $this->selectTimeout = 1; + } + + $this->options = isset($options['options']) ? $options['options'] : []; } public function __get($name) { if ($name === '_mh') { - return $this->_mh = curl_multi_init(); + $this->_mh = curl_multi_init(); + + foreach ($this->options as $option => $value) { + // A warning is raised in case of a wrong option. + curl_multi_setopt($this->_mh, $option, $value); + } + + // Further calls to _mh will return the value directly, without entering the + // __get() method at all. + return $this->_mh; } throw new \BadMethodCallException(); @@ -82,7 +102,7 @@ public function tick() { // Add any delayed handles if needed. if ($this->delays) { - $currentTime = microtime(true); + $currentTime = Utils::currentTime(); foreach ($this->delays as $id => $delay) { if ($currentTime >= $delay) { unset($this->delays[$id]); @@ -134,7 +154,7 @@ private function addRequest(array $entry) if (empty($easy->options['delay'])) { curl_multi_add_handle($this->_mh, $easy->handle); } else { - $this->delays[$id] = microtime(true) + ($easy->options['delay'] / 1000); + $this->delays[$id] = Utils::currentTime() + ($easy->options['delay'] / 1000); } } @@ -186,7 +206,7 @@ private function processMessages() private function timeToNext() { - $currentTime = microtime(true); + $currentTime = Utils::currentTime(); $nextTime = PHP_INT_MAX; foreach ($this->delays as $time) { if ($time < $nextTime) { diff --git a/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php b/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php index d892061c..5b312bc0 100644 --- a/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php +++ b/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php @@ -66,7 +66,7 @@ public function __invoke(RequestInterface $request, array $options) throw new \OutOfBoundsException('Mock queue is empty'); } - if (isset($options['delay'])) { + if (isset($options['delay']) && is_numeric($options['delay'])) { usleep($options['delay'] * 1000); } @@ -175,6 +175,11 @@ public function count() return count($this->queue); } + public function reset() + { + $this->queue = []; + } + private function invokeStats( RequestInterface $request, array $options, @@ -182,7 +187,8 @@ private function invokeStats( $reason = null ) { if (isset($options['on_stats'])) { - $stats = new TransferStats($request, $response, 0, $reason); + $transferTime = isset($options['transfer_time']) ? $options['transfer_time'] : 0; + $stats = new TransferStats($request, $response, $transferTime, $reason); call_user_func($options['on_stats'], $stats); } } diff --git a/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php b/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php index b686545e..a15734a4 100644 --- a/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php +++ b/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php @@ -1,12 +1,13 @@ getBody()->getSize()) { - $request = $request->withHeader('Content-Length', 0); + $request = $request->withHeader('Content-Length', '0'); } return $this->createResponse( @@ -82,7 +83,7 @@ private function invokeStats( $stats = new TransferStats( $request, $response, - microtime(true) - $startTime, + Utils::currentTime() - $startTime, $error, [] ); @@ -343,13 +344,25 @@ private function resolveHost(RequestInterface $request, array $options) if ('v4' === $options['force_ip_resolve']) { $records = dns_get_record($uri->getHost(), DNS_A); if (!isset($records[0]['ip'])) { - throw new ConnectException(sprintf("Could not resolve IPv4 address for host '%s'", $uri->getHost()), $request); + throw new ConnectException( + sprintf( + "Could not resolve IPv4 address for host '%s'", + $uri->getHost() + ), + $request + ); } $uri = $uri->withHost($records[0]['ip']); } elseif ('v6' === $options['force_ip_resolve']) { $records = dns_get_record($uri->getHost(), DNS_AAAA); if (!isset($records[0]['ipv6'])) { - throw new ConnectException(sprintf("Could not resolve IPv6 address for host '%s'", $uri->getHost()), $request); + throw new ConnectException( + sprintf( + "Could not resolve IPv6 address for host '%s'", + $uri->getHost() + ), + $request + ); } $uri = $uri->withHost('[' . $records[0]['ipv6'] . ']'); } diff --git a/vendor/guzzlehttp/guzzle/src/HandlerStack.php b/vendor/guzzlehttp/guzzle/src/HandlerStack.php index 24c46fd9..6a49cc06 100644 --- a/vendor/guzzlehttp/guzzle/src/HandlerStack.php +++ b/vendor/guzzlehttp/guzzle/src/HandlerStack.php @@ -1,7 +1,9 @@ extractCookies($request, $response); return $response; } - ); + ); }; }; } @@ -58,7 +57,7 @@ public static function httpErrors() return $handler($request, $options); } return $handler($request, $options)->then( - function (ResponseInterface $response) use ($request, $handler) { + function (ResponseInterface $response) use ($request) { $code = $response->getStatusCode(); if ($code < 400) { return $response; @@ -183,7 +182,7 @@ public static function retry(callable $decider, callable $delay = null) * * @return callable Returns a function that accepts the next handler. */ - public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = LogLevel::INFO) + public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = 'info' /* \Psr\Log\LogLevel::INFO */) { return function (callable $handler) use ($logger, $formatter, $logLevel) { return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) { diff --git a/vendor/guzzlehttp/guzzle/src/Pool.php b/vendor/guzzlehttp/guzzle/src/Pool.php index 8f1be33c..5838db4f 100644 --- a/vendor/guzzlehttp/guzzle/src/Pool.php +++ b/vendor/guzzlehttp/guzzle/src/Pool.php @@ -1,12 +1,13 @@ each = new EachPromise($requests(), $config); } + /** + * Get promise + * + * @return PromiseInterface + */ public function promise() { return $this->each->promise(); @@ -106,6 +112,11 @@ public static function batch( return $res; } + /** + * Execute callback(s) + * + * @return void + */ private static function cmpCallback(array &$options, $name, array &$results) { if (!isset($options[$name])) { diff --git a/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php b/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php index 2eb95f9b..568a1e90 100644 --- a/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php +++ b/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php @@ -66,6 +66,11 @@ public function __invoke(RequestInterface $request, array $options) return $fn(Psr7\modify_request($request, $modify), $options); } + /** + * Add expect header + * + * @return void + */ private function addExpectHeader( RequestInterface $request, array $options, diff --git a/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php b/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php index 131b7717..008a29b8 100644 --- a/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php +++ b/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php @@ -13,7 +13,7 @@ * Request redirect middleware. * * Apply this middleware like other middleware using - * {@see GuzzleHttp\Middleware::redirect()}. + * {@see \GuzzleHttp\Middleware::redirect()}. */ class RedirectMiddleware { @@ -76,7 +76,7 @@ public function __invoke(RequestInterface $request, array $options) /** * @param RequestInterface $request * @param array $options - * @param ResponseInterface|PromiseInterface $response + * @param ResponseInterface $response * * @return ResponseInterface|PromiseInterface */ @@ -94,6 +94,14 @@ public function checkRedirect( $this->guardMax($request, $options); $nextRequest = $this->modifyRequest($request, $options, $response); + // If authorization is handled by curl, unset it if URI is cross-origin. + if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $nextRequest->getUri()) && defined('\CURLOPT_HTTPAUTH')) { + unset( + $options['curl'][\CURLOPT_HTTPAUTH], + $options['curl'][\CURLOPT_USERPWD] + ); + } + if (isset($options['allow_redirects']['on_redirect'])) { call_user_func( $options['allow_redirects']['on_redirect'], @@ -118,6 +126,11 @@ public function checkRedirect( return $promise; } + /** + * Enable tracking on promise. + * + * @return PromiseInterface + */ private function withTracking(PromiseInterface $promise, $uri, $statusCode) { return $promise->then( @@ -135,6 +148,13 @@ function (ResponseInterface $response) use ($uri, $statusCode) { ); } + /** + * Check for too many redirects. + * + * @return void + * + * @throws TooManyRedirectsException Too many redirects. + */ private function guardMax(RequestInterface $request, array &$options) { $current = isset($options['__redirect_count']) @@ -172,13 +192,19 @@ public function modifyRequest( // would do. $statusCode = $response->getStatusCode(); if ($statusCode == 303 || - ($statusCode <= 302 && $request->getBody() && !$options['allow_redirects']['strict']) + ($statusCode <= 302 && !$options['allow_redirects']['strict']) ) { $modify['method'] = 'GET'; $modify['body'] = ''; } - $modify['uri'] = $this->redirectUri($request, $response, $protocols); + $uri = self::redirectUri($request, $response, $protocols); + if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) { + $idnOptions = ($options['idn_conversion'] === true) ? IDNA_DEFAULT : $options['idn_conversion']; + $uri = Utils::idnUriConvert($uri, $idnOptions); + } + + $modify['uri'] = $uri; Psr7\rewind_body($request); // Add the Referer header if it is told to do so and only @@ -186,22 +212,23 @@ public function modifyRequest( if ($options['allow_redirects']['referer'] && $modify['uri']->getScheme() === $request->getUri()->getScheme() ) { - $uri = $request->getUri()->withUserInfo('', ''); + $uri = $request->getUri()->withUserInfo(''); $modify['set_headers']['Referer'] = (string) $uri; } else { $modify['remove_headers'][] = 'Referer'; } - // Remove Authorization header if host is different. - if ($request->getUri()->getHost() !== $modify['uri']->getHost()) { + // Remove Authorization and Cookie headers if URI is cross-origin. + if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $modify['uri'])) { $modify['remove_headers'][] = 'Authorization'; + $modify['remove_headers'][] = 'Cookie'; } return Psr7\modify_request($request, $modify); } /** - * Set the appropriate URL on the request based on the location header + * Set the appropriate URL on the request based on the location header. * * @param RequestInterface $request * @param ResponseInterface $response @@ -209,7 +236,7 @@ public function modifyRequest( * * @return UriInterface */ - private function redirectUri( + private static function redirectUri( RequestInterface $request, ResponseInterface $response, array $protocols diff --git a/vendor/guzzlehttp/guzzle/src/RequestOptions.php b/vendor/guzzlehttp/guzzle/src/RequestOptions.php index c6aacfb1..355f658f 100644 --- a/vendor/guzzlehttp/guzzle/src/RequestOptions.php +++ b/vendor/guzzlehttp/guzzle/src/RequestOptions.php @@ -22,7 +22,7 @@ final class RequestOptions * - strict: (bool, default=false) Set to true to use strict redirects * meaning redirect POST requests with POST requests vs. doing what most * browsers do which is redirect POST requests with GET requests - * - referer: (bool, default=true) Set to false to disable the Referer + * - referer: (bool, default=false) Set to true to enable the Referer * header. * - protocols: (array, default=['http', 'https']) Allowed redirect * protocols. @@ -132,6 +132,14 @@ final class RequestOptions */ const HTTP_ERRORS = 'http_errors'; + /** + * idn: (bool|int, default=true) A combination of IDNA_* constants for + * idn_to_ascii() PHP's function (see "options" parameter). Set to false to + * disable IDN support completely, or to true to use the default + * configuration (IDNA_DEFAULT constant). + */ + const IDN_CONVERSION = 'idn_conversion'; + /** * json: (mixed) Adds JSON data to a request. The provided value is JSON * encoded and a Content-Type header of application/json will be added to diff --git a/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php b/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php index f27090fd..5acc8c5c 100644 --- a/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php +++ b/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php @@ -19,6 +19,9 @@ class RetryMiddleware /** @var callable */ private $decider; + /** @var callable */ + private $delay; + /** * @param callable $decider Function that accepts the number of retries, * a request, [response], and [exception] and @@ -42,13 +45,13 @@ public function __construct( /** * Default exponential backoff delay function. * - * @param $retries + * @param int $retries * - * @return int + * @return int milliseconds. */ public static function exponentialDelay($retries) { - return (int) pow(2, $retries - 1); + return (int) pow(2, $retries - 1) * 1000; } /** @@ -71,6 +74,11 @@ public function __invoke(RequestInterface $request, array $options) ); } + /** + * Execute fulfilled closure + * + * @return mixed + */ private function onFulfilled(RequestInterface $req, array $options) { return function ($value) use ($req, $options) { @@ -87,6 +95,11 @@ private function onFulfilled(RequestInterface $req, array $options) }; } + /** + * Execute rejected closure + * + * @return callable + */ private function onRejected(RequestInterface $req, array $options) { return function ($reason) use ($req, $options) { @@ -103,6 +116,9 @@ private function onRejected(RequestInterface $req, array $options) }; } + /** + * @return self + */ private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null) { $options['delay'] = call_user_func($this->delay, ++$options['retries'], $response); diff --git a/vendor/guzzlehttp/guzzle/src/TransferStats.php b/vendor/guzzlehttp/guzzle/src/TransferStats.php index 15f717e1..87fb3c00 100644 --- a/vendor/guzzlehttp/guzzle/src/TransferStats.php +++ b/vendor/guzzlehttp/guzzle/src/TransferStats.php @@ -18,11 +18,11 @@ final class TransferStats private $handlerErrorData; /** - * @param RequestInterface $request Request that was sent. - * @param ResponseInterface $response Response received (if any) - * @param null $transferTime Total handler transfer time. - * @param mixed $handlerErrorData Handler error data. - * @param array $handlerStats Handler specific stats. + * @param RequestInterface $request Request that was sent. + * @param ResponseInterface|null $response Response received (if any) + * @param float|null $transferTime Total handler transfer time. + * @param mixed $handlerErrorData Handler error data. + * @param array $handlerStats Handler specific stats. */ public function __construct( RequestInterface $request, @@ -93,7 +93,7 @@ public function getEffectiveUri() /** * Get the estimated time the request was being transferred by the handler. * - * @return float Time in seconds. + * @return float|null Time in seconds. */ public function getTransferTime() { diff --git a/vendor/guzzlehttp/guzzle/src/Utils.php b/vendor/guzzlehttp/guzzle/src/Utils.php new file mode 100644 index 00000000..c698acbf --- /dev/null +++ b/vendor/guzzlehttp/guzzle/src/Utils.php @@ -0,0 +1,92 @@ +getHost()) { + $asciiHost = self::idnToAsci($uri->getHost(), $options, $info); + if ($asciiHost === false) { + $errorBitSet = isset($info['errors']) ? $info['errors'] : 0; + + $errorConstants = array_filter(array_keys(get_defined_constants()), function ($name) { + return substr($name, 0, 11) === 'IDNA_ERROR_'; + }); + + $errors = []; + foreach ($errorConstants as $errorConstant) { + if ($errorBitSet & constant($errorConstant)) { + $errors[] = $errorConstant; + } + } + + $errorMessage = 'IDN conversion failed'; + if ($errors) { + $errorMessage .= ' (errors: ' . implode(', ', $errors) . ')'; + } + + throw new InvalidArgumentException($errorMessage); + } else { + if ($uri->getHost() !== $asciiHost) { + // Replace URI only if the ASCII version is different + $uri = $uri->withHost($asciiHost); + } + } + } + + return $uri; + } + + /** + * @param string $domain + * @param int $options + * @param array $info + * + * @return string|false + */ + private static function idnToAsci($domain, $options, &$info = []) + { + if (\preg_match('%^[ -~]+$%', $domain) === 1) { + return $domain; + } + + if (\extension_loaded('intl') && defined('INTL_IDNA_VARIANT_UTS46')) { + return \idn_to_ascii($domain, $options, INTL_IDNA_VARIANT_UTS46, $info); + } + + /* + * The Idn class is marked as @internal. Verify that class and method exists. + */ + if (method_exists(Idn::class, 'idn_to_ascii')) { + return Idn::idn_to_ascii($domain, $options, Idn::INTL_IDNA_VARIANT_UTS46, $info); + } + + throw new \RuntimeException('ext-intl or symfony/polyfill-intl-idn not loaded or too old'); + } +} diff --git a/vendor/guzzlehttp/guzzle/src/functions.php b/vendor/guzzlehttp/guzzle/src/functions.php index a3ac450d..c2afd8c7 100644 --- a/vendor/guzzlehttp/guzzle/src/functions.php +++ b/vendor/guzzlehttp/guzzle/src/functions.php @@ -56,7 +56,7 @@ function describe_type($input) /** * Parses an array of header lines into an associative array of headers. * - * @param array $lines Header lines array of strings in the following + * @param iterable $lines Header lines array of strings in the following * format: "Name: Value" * @return array */ @@ -97,8 +97,8 @@ function debug_resource($value = null) * * The returned handler is not wrapped by any default middlewares. * - * @throws \RuntimeException if no viable Handler is available. * @return callable Returns the best handler for the given system. + * @throws \RuntimeException if no viable Handler is available. */ function choose_handler() { @@ -196,7 +196,8 @@ function default_ca_bundle() } } - throw new \RuntimeException(<<< EOT + throw new \RuntimeException( + <<< EOT No system CA bundle could be found in any of the the common system locations. PHP versions earlier than 5.6 are not properly configured to use the system's CA bundle by default. In order to verify peer certificates, you will need to @@ -294,14 +295,14 @@ function is_host_in_noproxy($host, array $noProxyArray) * @param int $options Bitmask of JSON decode options. * * @return mixed - * @throws \InvalidArgumentException if the JSON cannot be decoded. + * @throws Exception\InvalidArgumentException if the JSON cannot be decoded. * @link http://www.php.net/manual/en/function.json-decode.php */ function json_decode($json, $assoc = false, $depth = 512, $options = 0) { $data = \json_decode($json, $assoc, $depth, $options); if (JSON_ERROR_NONE !== json_last_error()) { - throw new \InvalidArgumentException( + throw new Exception\InvalidArgumentException( 'json_decode error: ' . json_last_error_msg() ); } @@ -317,14 +318,14 @@ function json_decode($json, $assoc = false, $depth = 512, $options = 0) * @param int $depth Set the maximum depth. Must be greater than zero. * * @return string - * @throws \InvalidArgumentException if the JSON cannot be encoded. + * @throws Exception\InvalidArgumentException if the JSON cannot be encoded. * @link http://www.php.net/manual/en/function.json-encode.php */ function json_encode($value, $options = 0, $depth = 512) { $json = \json_encode($value, $options, $depth); if (JSON_ERROR_NONE !== json_last_error()) { - throw new \InvalidArgumentException( + throw new Exception\InvalidArgumentException( 'json_encode error: ' . json_last_error_msg() ); } diff --git a/vendor/guzzlehttp/promises/CHANGELOG.md b/vendor/guzzlehttp/promises/CHANGELOG.md index 551929f6..235e13bc 100644 --- a/vendor/guzzlehttp/promises/CHANGELOG.md +++ b/vendor/guzzlehttp/promises/CHANGELOG.md @@ -1,5 +1,43 @@ # CHANGELOG +## 1.5.1 - 2021-10-22 + +### Fixed + +- Revert "Call handler when waiting on fulfilled/rejected Promise" +- Fix pool memory leak when empty array of promises provided + +## 1.5.0 - 2021-10-07 + +### Changed + +- Call handler when waiting on fulfilled/rejected Promise + +### Fixed + +- Fix manually settle promises generated with Utils::task + +## 1.4.1 - 2021-02-18 + +### Fixed + +- Fixed `each_limit` skipping promises and failing + +## 1.4.0 - 2020-09-30 + +### Added + +- Support for PHP 8 +- Optional `$recursive` flag to `all` +- Replaced functions by static methods + +### Fixed + +- Fix empty `each` processing +- Fix promise handling for Iterators of non-unique keys +- Fixed `method_exists` crashes on PHP 8 +- Memory leak on exceptions + ## 1.3.1 - 2016-12-20 diff --git a/vendor/guzzlehttp/promises/LICENSE b/vendor/guzzlehttp/promises/LICENSE index 67f91a14..9f0f943b 100644 --- a/vendor/guzzlehttp/promises/LICENSE +++ b/vendor/guzzlehttp/promises/LICENSE @@ -1,4 +1,9 @@ -Copyright (c) 2015-2016 Michael Dowling, https://github.com/mtdowling +The MIT License (MIT) + +Copyright (c) 2015 Michael Dowling +Copyright (c) 2015 Graham Campbell +Copyright (c) 2017 Tobias Schultze +Copyright (c) 2020 Tobias Nyholm Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/guzzlehttp/promises/README.md b/vendor/guzzlehttp/promises/README.md index 7b607e28..c175fec7 100644 --- a/vendor/guzzlehttp/promises/README.md +++ b/vendor/guzzlehttp/promises/README.md @@ -26,7 +26,7 @@ for a general introduction to promises. - Promises can be cancelled. - Works with any object that has a `then` function. - C# style async/await coroutine promises using - `GuzzleHttp\Promise\coroutine()`. + `GuzzleHttp\Promise\Coroutine::of()`. # Quick start @@ -88,7 +88,7 @@ $promise }); // Resolving the promise triggers the $onFulfilled callbacks and outputs -// "Hello, reader". +// "Hello, reader." $promise->resolve('reader.'); ``` @@ -150,7 +150,7 @@ use GuzzleHttp\Promise\Promise; $promise = new Promise(); $promise->then(null, function ($reason) { - throw new \Exception($reason); + throw new Exception($reason); })->then(null, function ($reason) { assert($reason->getMessage() === 'Error!'); }); @@ -182,7 +182,6 @@ invoked using the value returned from the `$onRejected` callback. ```php use GuzzleHttp\Promise\Promise; -use GuzzleHttp\Promise\RejectedPromise; $promise = new Promise(); $promise @@ -220,7 +219,7 @@ the promise is rejected with the exception and the exception is thrown. ```php $promise = new Promise(function () use (&$promise) { - throw new \Exception('foo'); + throw new Exception('foo'); }); $promise->wait(); // throws the exception. @@ -397,7 +396,7 @@ $deferred = new React\Promise\Deferred(); $reactPromise = $deferred->promise(); // Create a Guzzle promise that is fulfilled with a React promise. -$guzzlePromise = new \GuzzleHttp\Promise\Promise(); +$guzzlePromise = new GuzzleHttp\Promise\Promise(); $guzzlePromise->then(function ($value) use ($reactPromise) { // Do something something with the value... // Return the React promise @@ -424,7 +423,7 @@ instance. ```php // Get the global task queue -$queue = \GuzzleHttp\Promise\queue(); +$queue = GuzzleHttp\Promise\Utils::queue(); $queue->run(); ``` @@ -502,3 +501,47 @@ $promise->then(function ($value) { echo $value; }); $promise->resolve('foo'); // prints "foo" ``` + + +## Upgrading from Function API + +A static API was first introduced in 1.4.0, in order to mitigate problems with functions conflicting between global and local copies of the package. The function API will be removed in 2.0.0. A migration table has been provided here for your convenience: + +| Original Function | Replacement Method | +|----------------|----------------| +| `queue` | `Utils::queue` | +| `task` | `Utils::task` | +| `promise_for` | `Create::promiseFor` | +| `rejection_for` | `Create::rejectionFor` | +| `exception_for` | `Create::exceptionFor` | +| `iter_for` | `Create::iterFor` | +| `inspect` | `Utils::inspect` | +| `inspect_all` | `Utils::inspectAll` | +| `unwrap` | `Utils::unwrap` | +| `all` | `Utils::all` | +| `some` | `Utils::some` | +| `any` | `Utils::any` | +| `settle` | `Utils::settle` | +| `each` | `Each::of` | +| `each_limit` | `Each::ofLimit` | +| `each_limit_all` | `Each::ofLimitAll` | +| `!is_fulfilled` | `Is::pending` | +| `is_fulfilled` | `Is::fulfilled` | +| `is_rejected` | `Is::rejected` | +| `is_settled` | `Is::settled` | +| `coroutine` | `Coroutine::of` | + + +## Security + +If you discover a security vulnerability within this package, please send an email to security@tidelift.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced. Please see [Security Policy](https://github.com/guzzle/promises/security/policy) for more information. + +## License + +Guzzle is made available under the MIT License (MIT). Please see [License File](LICENSE) for more information. + +## For Enterprise + +Available as part of the Tidelift Subscription + +The maintainers of Guzzle and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-guzzlehttp-promises?utm_source=packagist-guzzlehttp-promises&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) diff --git a/vendor/guzzlehttp/promises/composer.json b/vendor/guzzlehttp/promises/composer.json index ec41a61e..c959fb32 100644 --- a/vendor/guzzlehttp/promises/composer.json +++ b/vendor/guzzlehttp/promises/composer.json @@ -4,17 +4,32 @@ "keywords": ["promise"], "license": "MIT", "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], "require": { - "php": ">=5.5.0" + "php": ">=5.5" }, "require-dev": { - "phpunit/phpunit": "^4.0" + "symfony/phpunit-bridge": "^4.4 || ^5.1" }, "autoload": { "psr-4": { @@ -22,13 +37,22 @@ }, "files": ["src/functions_include.php"] }, + "autoload-dev": { + "psr-4": { + "GuzzleHttp\\Promise\\Tests\\": "tests/" + } + }, "scripts": { - "test": "vendor/bin/phpunit", - "test-ci": "vendor/bin/phpunit --coverage-text" + "test": "vendor/bin/simple-phpunit", + "test-ci": "vendor/bin/simple-phpunit --coverage-text" }, "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.5-dev" } + }, + "config": { + "preferred-install": "dist", + "sort-packages": true } } diff --git a/vendor/guzzlehttp/promises/src/AggregateException.php b/vendor/guzzlehttp/promises/src/AggregateException.php index 6a5690c3..d2b5712b 100644 --- a/vendor/guzzlehttp/promises/src/AggregateException.php +++ b/vendor/guzzlehttp/promises/src/AggregateException.php @@ -1,4 +1,5 @@ currentPromise->wait(); } }); - $this->nextCoroutine($this->generator->current()); + try { + $this->nextCoroutine($this->generator->current()); + } catch (\Exception $exception) { + $this->result->reject($exception); + } catch (Throwable $throwable) { + $this->result->reject($throwable); + } + } + + /** + * Create a new coroutine. + * + * @return self + */ + public static function of(callable $generatorFn) + { + return new self($generatorFn); } public function then( @@ -108,7 +126,7 @@ public function cancel() private function nextCoroutine($yielded) { - $this->currentPromise = promise_for($yielded) + $this->currentPromise = Create::promiseFor($yielded) ->then([$this, '_handleSuccess'], [$this, '_handleFailure']); } @@ -139,7 +157,7 @@ public function _handleFailure($reason) { unset($this->currentPromise); try { - $nextYield = $this->generator->throw(exception_for($reason)); + $nextYield = $this->generator->throw(Create::exceptionFor($reason)); // The throw was caught, so keep iterating on the coroutine $this->nextCoroutine($nextYield); } catch (Exception $exception) { diff --git a/vendor/guzzlehttp/promises/src/Create.php b/vendor/guzzlehttp/promises/src/Create.php new file mode 100644 index 00000000..8d038e9c --- /dev/null +++ b/vendor/guzzlehttp/promises/src/Create.php @@ -0,0 +1,84 @@ +then([$promise, 'resolve'], [$promise, 'reject']); + return $promise; + } + + return new FulfilledPromise($value); + } + + /** + * Creates a rejected promise for a reason if the reason is not a promise. + * If the provided reason is a promise, then it is returned as-is. + * + * @param mixed $reason Promise or reason. + * + * @return PromiseInterface + */ + public static function rejectionFor($reason) + { + if ($reason instanceof PromiseInterface) { + return $reason; + } + + return new RejectedPromise($reason); + } + + /** + * Create an exception for a rejected promise value. + * + * @param mixed $reason + * + * @return \Exception|\Throwable + */ + public static function exceptionFor($reason) + { + if ($reason instanceof \Exception || $reason instanceof \Throwable) { + return $reason; + } + + return new RejectionException($reason); + } + + /** + * Returns an iterator for the given value. + * + * @param mixed $value + * + * @return \Iterator + */ + public static function iterFor($value) + { + if ($value instanceof \Iterator) { + return $value; + } + + if (is_array($value)) { + return new \ArrayIterator($value); + } + + return new \ArrayIterator([$value]); + } +} diff --git a/vendor/guzzlehttp/promises/src/Each.php b/vendor/guzzlehttp/promises/src/Each.php new file mode 100644 index 00000000..1dda3549 --- /dev/null +++ b/vendor/guzzlehttp/promises/src/Each.php @@ -0,0 +1,90 @@ + $onFulfilled, + 'rejected' => $onRejected + ]))->promise(); + } + + /** + * Like of, but only allows a certain number of outstanding promises at any + * given time. + * + * $concurrency may be an integer or a function that accepts the number of + * pending promises and returns a numeric concurrency limit value to allow + * for dynamic a concurrency size. + * + * @param mixed $iterable + * @param int|callable $concurrency + * @param callable $onFulfilled + * @param callable $onRejected + * + * @return PromiseInterface + */ + public static function ofLimit( + $iterable, + $concurrency, + callable $onFulfilled = null, + callable $onRejected = null + ) { + return (new EachPromise($iterable, [ + 'fulfilled' => $onFulfilled, + 'rejected' => $onRejected, + 'concurrency' => $concurrency + ]))->promise(); + } + + /** + * Like limit, but ensures that no promise in the given $iterable argument + * is rejected. If any promise is rejected, then the aggregate promise is + * rejected with the encountered rejection. + * + * @param mixed $iterable + * @param int|callable $concurrency + * @param callable $onFulfilled + * + * @return PromiseInterface + */ + public static function ofLimitAll( + $iterable, + $concurrency, + callable $onFulfilled = null + ) { + return each_limit( + $iterable, + $concurrency, + $onFulfilled, + function ($reason, $idx, PromiseInterface $aggregate) { + $aggregate->reject($reason); + } + ); + } +} diff --git a/vendor/guzzlehttp/promises/src/EachPromise.php b/vendor/guzzlehttp/promises/src/EachPromise.php index d0ddf603..38ecb59b 100644 --- a/vendor/guzzlehttp/promises/src/EachPromise.php +++ b/vendor/guzzlehttp/promises/src/EachPromise.php @@ -1,4 +1,5 @@ iterable = iter_for($iterable); + $this->iterable = Create::iterFor($iterable); if (isset($config['concurrency'])) { $this->concurrency = $config['concurrency']; @@ -65,6 +68,7 @@ public function __construct($iterable, array $config = []) } } + /** @psalm-suppress InvalidNullableReturnType */ public function promise() { if ($this->aggregate) { @@ -73,14 +77,27 @@ public function promise() try { $this->createPromise(); + /** @psalm-assert Promise $this->aggregate */ $this->iterable->rewind(); $this->refillPending(); } catch (\Throwable $e) { + /** + * @psalm-suppress NullReference + * @phpstan-ignore-next-line + */ $this->aggregate->reject($e); } catch (\Exception $e) { + /** + * @psalm-suppress NullReference + * @phpstan-ignore-next-line + */ $this->aggregate->reject($e); } + /** + * @psalm-suppress NullableReturnStatement + * @phpstan-ignore-next-line + */ return $this->aggregate; } @@ -88,18 +105,16 @@ private function createPromise() { $this->mutex = false; $this->aggregate = new Promise(function () { - reset($this->pending); - if (empty($this->pending) && !$this->iterable->valid()) { - $this->aggregate->resolve(null); + if ($this->checkIfFinished()) { return; } - + reset($this->pending); // Consume a potentially fluctuating list of promises while // ensuring that indexes are maintained (precluding array_shift). while ($promise = current($this->pending)) { next($this->pending); $promise->wait(); - if ($this->aggregate->getState() !== PromiseInterface::PENDING) { + if (Is::settled($this->aggregate)) { return; } } @@ -109,6 +124,7 @@ private function createPromise() $clearFn = function () { $this->iterable = $this->concurrency = $this->pending = null; $this->onFulfilled = $this->onRejected = null; + $this->nextPendingIndex = 0; }; $this->aggregate->then($clearFn, $clearFn); @@ -148,22 +164,32 @@ private function addPending() return false; } - $promise = promise_for($this->iterable->current()); - $idx = $this->iterable->key(); + $promise = Create::promiseFor($this->iterable->current()); + $key = $this->iterable->key(); + + // Iterable keys may not be unique, so we use a counter to + // guarantee uniqueness + $idx = $this->nextPendingIndex++; $this->pending[$idx] = $promise->then( - function ($value) use ($idx) { + function ($value) use ($idx, $key) { if ($this->onFulfilled) { call_user_func( - $this->onFulfilled, $value, $idx, $this->aggregate + $this->onFulfilled, + $value, + $key, + $this->aggregate ); } $this->step($idx); }, - function ($reason) use ($idx) { + function ($reason) use ($idx, $key) { if ($this->onRejected) { call_user_func( - $this->onRejected, $reason, $idx, $this->aggregate + $this->onRejected, + $reason, + $key, + $this->aggregate ); } $this->step($idx); @@ -201,7 +227,7 @@ private function advanceIterator() private function step($idx) { // If the promise was already resolved, then ignore this step. - if ($this->aggregate->getState() !== PromiseInterface::PENDING) { + if (Is::settled($this->aggregate)) { return; } diff --git a/vendor/guzzlehttp/promises/src/FulfilledPromise.php b/vendor/guzzlehttp/promises/src/FulfilledPromise.php index dbbeeb9f..98f72a62 100644 --- a/vendor/guzzlehttp/promises/src/FulfilledPromise.php +++ b/vendor/guzzlehttp/promises/src/FulfilledPromise.php @@ -1,4 +1,5 @@ value = $value; @@ -30,11 +32,11 @@ public function then( return $this; } - $queue = queue(); + $queue = Utils::queue(); $p = new Promise([$queue, 'run']); $value = $this->value; $queue->add(static function () use ($p, $value, $onFulfilled) { - if ($p->getState() === self::PENDING) { + if (Is::pending($p)) { try { $p->resolve($onFulfilled($value)); } catch (\Throwable $e) { diff --git a/vendor/guzzlehttp/promises/src/Is.php b/vendor/guzzlehttp/promises/src/Is.php new file mode 100644 index 00000000..c3ed8d01 --- /dev/null +++ b/vendor/guzzlehttp/promises/src/Is.php @@ -0,0 +1,46 @@ +getState() === PromiseInterface::PENDING; + } + + /** + * Returns true if a promise is fulfilled or rejected. + * + * @return bool + */ + public static function settled(PromiseInterface $promise) + { + return $promise->getState() !== PromiseInterface::PENDING; + } + + /** + * Returns true if a promise is fulfilled. + * + * @return bool + */ + public static function fulfilled(PromiseInterface $promise) + { + return $promise->getState() === PromiseInterface::FULFILLED; + } + + /** + * Returns true if a promise is rejected. + * + * @return bool + */ + public static function rejected(PromiseInterface $promise) + { + return $promise->getState() === PromiseInterface::REJECTED; + } +} diff --git a/vendor/guzzlehttp/promises/src/Promise.php b/vendor/guzzlehttp/promises/src/Promise.php index 844ada07..75939057 100644 --- a/vendor/guzzlehttp/promises/src/Promise.php +++ b/vendor/guzzlehttp/promises/src/Promise.php @@ -1,4 +1,5 @@ state === self::FULFILLED) { - return $onFulfilled - ? promise_for($this->result)->then($onFulfilled) - : promise_for($this->result); + $promise = Create::promiseFor($this->result); + return $onFulfilled ? $promise->then($onFulfilled) : $promise; } // It's either cancelled or rejected, so return a rejected promise // and immediately invoke any callbacks. - $rejection = rejection_for($this->result); + $rejection = Create::rejectionFor($this->result); return $onRejected ? $rejection->then(null, $onRejected) : $rejection; } @@ -61,19 +61,15 @@ public function wait($unwrap = true) { $this->waitIfPending(); - $inner = $this->result instanceof PromiseInterface - ? $this->result->wait($unwrap) - : $this->result; - + if ($this->result instanceof PromiseInterface) { + return $this->result->wait($unwrap); + } if ($unwrap) { - if ($this->result instanceof PromiseInterface - || $this->state === self::FULFILLED - ) { - return $inner; - } else { - // It's rejected so "unwrap" and throw an exception. - throw exception_for($inner); + if ($this->state === self::FULFILLED) { + return $this->result; } + // It's rejected so "unwrap" and throw an exception. + throw Create::exceptionFor($this->result); } } @@ -103,6 +99,7 @@ public function cancel() } // Reject the promise only if it wasn't rejected in a then callback. + /** @psalm-suppress RedundantCondition */ if ($this->state === self::PENDING) { $this->reject(new CancellationException('Promise has been cancelled')); } @@ -148,17 +145,15 @@ private function settle($state, $value) // If the value was not a settled promise or a thenable, then resolve // it in the task queue using the correct ID. - if (!method_exists($value, 'then')) { + if (!is_object($value) || !method_exists($value, 'then')) { $id = $state === self::FULFILLED ? 1 : 2; // It's a success, so resolve the handlers in the queue. - queue()->add(static function () use ($id, $value, $handlers) { + Utils::queue()->add(static function () use ($id, $value, $handlers) { foreach ($handlers as $handler) { self::callHandler($id, $value, $handler); } }); - } elseif ($value instanceof Promise - && $value->getState() === self::PENDING - ) { + } elseif ($value instanceof Promise && Is::pending($value)) { // We can just merge our handlers onto the next promise. $value->handlers = array_merge($value->handlers, $handlers); } else { @@ -184,8 +179,6 @@ static function ($reason) use ($handlers) { * @param int $index 1 (resolve) or 2 (reject). * @param mixed $value Value to pass to the callback. * @param array $handler Array of handler data (promise and callbacks). - * - * @return array Returns the next group to resolve. */ private static function callHandler($index, $value, array $handler) { @@ -194,13 +187,21 @@ private static function callHandler($index, $value, array $handler) // The promise may have been cancelled or resolved before placing // this thunk in the queue. - if ($promise->getState() !== self::PENDING) { + if (Is::settled($promise)) { return; } try { if (isset($handler[$index])) { - $promise->resolve($handler[$index]($value)); + /* + * If $f throws an exception, then $handler will be in the exception + * stack trace. Since $handler contains a reference to the callable + * itself we get a circular reference. We clear the $handler + * here to avoid that memory leak. + */ + $f = $handler[$index]; + unset($handler); + $promise->resolve($f($value)); } elseif ($index === 1) { // Forward resolution values as-is. $promise->resolve($value); @@ -224,15 +225,16 @@ private function waitIfPending() } elseif ($this->waitList) { $this->invokeWaitList(); } else { - // If there's not wait function, then reject the promise. + // If there's no wait function, then reject the promise. $this->reject('Cannot wait on a promise that has ' . 'no internal wait function. You must provide a wait ' . 'function when constructing the promise to be able to ' . 'wait on a promise.'); } - queue()->run(); + Utils::queue()->run(); + /** @psalm-suppress RedundantCondition */ if ($this->state === self::PENDING) { $this->reject('Invoking the wait callback did not resolve the promise'); } @@ -263,17 +265,13 @@ private function invokeWaitList() $this->waitList = null; foreach ($waitList as $result) { - while (true) { + do { $result->waitIfPending(); + $result = $result->result; + } while ($result instanceof Promise); - if ($result->result instanceof Promise) { - $result = $result->result; - } else { - if ($result->result instanceof PromiseInterface) { - $result->result->wait(false); - } - break; - } + if ($result instanceof PromiseInterface) { + $result->wait(false); } } } diff --git a/vendor/guzzlehttp/promises/src/PromiseInterface.php b/vendor/guzzlehttp/promises/src/PromiseInterface.php index 8f5f4b99..e5983314 100644 --- a/vendor/guzzlehttp/promises/src/PromiseInterface.php +++ b/vendor/guzzlehttp/promises/src/PromiseInterface.php @@ -1,4 +1,5 @@ reason = $reason; @@ -30,11 +32,11 @@ public function then( return $this; } - $queue = queue(); + $queue = Utils::queue(); $reason = $this->reason; $p = new Promise([$queue, 'run']); $queue->add(static function () use ($p, $reason, $onRejected) { - if ($p->getState() === self::PENDING) { + if (Is::pending($p)) { try { // Return a resolved promise if onRejected does not throw. $p->resolve($onRejected($reason)); @@ -59,8 +61,10 @@ public function otherwise(callable $onRejected) public function wait($unwrap = true, $defaultDelivery = null) { if ($unwrap) { - throw exception_for($this->reason); + throw Create::exceptionFor($this->reason); } + + return null; } public function getState() diff --git a/vendor/guzzlehttp/promises/src/RejectionException.php b/vendor/guzzlehttp/promises/src/RejectionException.php index 07c1136d..e2f13770 100644 --- a/vendor/guzzlehttp/promises/src/RejectionException.php +++ b/vendor/guzzlehttp/promises/src/RejectionException.php @@ -1,4 +1,5 @@ run(); + * GuzzleHttp\Promise\Utils::queue()->run(); */ class TaskQueue implements TaskQueueInterface { @@ -42,8 +43,8 @@ public function add(callable $task) public function run() { - /** @var callable $task */ while ($task = array_shift($this->queue)) { + /** @var callable $task */ $task(); } } diff --git a/vendor/guzzlehttp/promises/src/TaskQueueInterface.php b/vendor/guzzlehttp/promises/src/TaskQueueInterface.php index ac8306e1..723d4d54 100644 --- a/vendor/guzzlehttp/promises/src/TaskQueueInterface.php +++ b/vendor/guzzlehttp/promises/src/TaskQueueInterface.php @@ -1,4 +1,5 @@ + * while ($eventLoop->isRunning()) { + * GuzzleHttp\Promise\Utils::queue()->run(); + * } + * + * + * @param TaskQueueInterface $assign Optionally specify a new queue instance. + * + * @return TaskQueueInterface + */ + public static function queue(TaskQueueInterface $assign = null) + { + static $queue; + + if ($assign) { + $queue = $assign; + } elseif (!$queue) { + $queue = new TaskQueue(); + } + + return $queue; + } + + /** + * Adds a function to run in the task queue when it is next `run()` and + * returns a promise that is fulfilled or rejected with the result. + * + * @param callable $task Task function to run. + * + * @return PromiseInterface + */ + public static function task(callable $task) + { + $queue = self::queue(); + $promise = new Promise([$queue, 'run']); + $queue->add(function () use ($task, $promise) { + try { + if (Is::pending($promise)) { + $promise->resolve($task()); + } + } catch (\Throwable $e) { + $promise->reject($e); + } catch (\Exception $e) { + $promise->reject($e); + } + }); + + return $promise; + } + + /** + * Synchronously waits on a promise to resolve and returns an inspection + * state array. + * + * Returns a state associative array containing a "state" key mapping to a + * valid promise state. If the state of the promise is "fulfilled", the + * array will contain a "value" key mapping to the fulfilled value of the + * promise. If the promise is rejected, the array will contain a "reason" + * key mapping to the rejection reason of the promise. + * + * @param PromiseInterface $promise Promise or value. + * + * @return array + */ + public static function inspect(PromiseInterface $promise) + { + try { + return [ + 'state' => PromiseInterface::FULFILLED, + 'value' => $promise->wait() + ]; + } catch (RejectionException $e) { + return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()]; + } catch (\Throwable $e) { + return ['state' => PromiseInterface::REJECTED, 'reason' => $e]; + } catch (\Exception $e) { + return ['state' => PromiseInterface::REJECTED, 'reason' => $e]; + } + } + + /** + * Waits on all of the provided promises, but does not unwrap rejected + * promises as thrown exception. + * + * Returns an array of inspection state arrays. + * + * @see inspect for the inspection state array format. + * + * @param PromiseInterface[] $promises Traversable of promises to wait upon. + * + * @return array + */ + public static function inspectAll($promises) + { + $results = []; + foreach ($promises as $key => $promise) { + $results[$key] = inspect($promise); + } + + return $results; + } + + /** + * Waits on all of the provided promises and returns the fulfilled values. + * + * Returns an array that contains the value of each promise (in the same + * order the promises were provided). An exception is thrown if any of the + * promises are rejected. + * + * @param iterable $promises Iterable of PromiseInterface objects to wait on. + * + * @return array + * + * @throws \Exception on error + * @throws \Throwable on error in PHP >=7 + */ + public static function unwrap($promises) + { + $results = []; + foreach ($promises as $key => $promise) { + $results[$key] = $promise->wait(); + } + + return $results; + } + + /** + * Given an array of promises, return a promise that is fulfilled when all + * the items in the array are fulfilled. + * + * The promise's fulfillment value is an array with fulfillment values at + * respective positions to the original array. If any promise in the array + * rejects, the returned promise is rejected with the rejection reason. + * + * @param mixed $promises Promises or values. + * @param bool $recursive If true, resolves new promises that might have been added to the stack during its own resolution. + * + * @return PromiseInterface + */ + public static function all($promises, $recursive = false) + { + $results = []; + $promise = Each::of( + $promises, + function ($value, $idx) use (&$results) { + $results[$idx] = $value; + }, + function ($reason, $idx, Promise $aggregate) { + $aggregate->reject($reason); + } + )->then(function () use (&$results) { + ksort($results); + return $results; + }); + + if (true === $recursive) { + $promise = $promise->then(function ($results) use ($recursive, &$promises) { + foreach ($promises as $promise) { + if (Is::pending($promise)) { + return self::all($promises, $recursive); + } + } + return $results; + }); + } + + return $promise; + } + + /** + * Initiate a competitive race between multiple promises or values (values + * will become immediately fulfilled promises). + * + * When count amount of promises have been fulfilled, the returned promise + * is fulfilled with an array that contains the fulfillment values of the + * winners in order of resolution. + * + * This promise is rejected with a {@see AggregateException} if the number + * of fulfilled promises is less than the desired $count. + * + * @param int $count Total number of promises. + * @param mixed $promises Promises or values. + * + * @return PromiseInterface + */ + public static function some($count, $promises) + { + $results = []; + $rejections = []; + + return Each::of( + $promises, + function ($value, $idx, PromiseInterface $p) use (&$results, $count) { + if (Is::settled($p)) { + return; + } + $results[$idx] = $value; + if (count($results) >= $count) { + $p->resolve(null); + } + }, + function ($reason) use (&$rejections) { + $rejections[] = $reason; + } + )->then( + function () use (&$results, &$rejections, $count) { + if (count($results) !== $count) { + throw new AggregateException( + 'Not enough promises to fulfill count', + $rejections + ); + } + ksort($results); + return array_values($results); + } + ); + } + + /** + * Like some(), with 1 as count. However, if the promise fulfills, the + * fulfillment value is not an array of 1 but the value directly. + * + * @param mixed $promises Promises or values. + * + * @return PromiseInterface + */ + public static function any($promises) + { + return self::some(1, $promises)->then(function ($values) { + return $values[0]; + }); + } + + /** + * Returns a promise that is fulfilled when all of the provided promises have + * been fulfilled or rejected. + * + * The returned promise is fulfilled with an array of inspection state arrays. + * + * @see inspect for the inspection state array format. + * + * @param mixed $promises Promises or values. + * + * @return PromiseInterface + */ + public static function settle($promises) + { + $results = []; + + return Each::of( + $promises, + function ($value, $idx) use (&$results) { + $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value]; + }, + function ($reason, $idx) use (&$results) { + $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason]; + } + )->then(function () use (&$results) { + ksort($results); + return $results; + }); + } +} diff --git a/vendor/guzzlehttp/promises/src/functions.php b/vendor/guzzlehttp/promises/src/functions.php index 4e27709a..c03d39d0 100644 --- a/vendor/guzzlehttp/promises/src/functions.php +++ b/vendor/guzzlehttp/promises/src/functions.php @@ -1,4 +1,5 @@ add(function () use ($task, $promise) { - try { - $promise->resolve($task()); - } catch (\Throwable $e) { - $promise->reject($e); - } catch (\Exception $e) { - $promise->reject($e); - } - }); - - return $promise; + return Utils::task($task); } /** @@ -62,23 +47,12 @@ function task(callable $task) * @param mixed $value Promise or value. * * @return PromiseInterface + * + * @deprecated promise_for will be removed in guzzlehttp/promises:2.0. Use Create::promiseFor instead. */ function promise_for($value) { - if ($value instanceof PromiseInterface) { - return $value; - } - - // Return a Guzzle promise that shadows the given promise. - if (method_exists($value, 'then')) { - $wfn = method_exists($value, 'wait') ? [$value, 'wait'] : null; - $cfn = method_exists($value, 'cancel') ? [$value, 'cancel'] : null; - $promise = new Promise($wfn, $cfn); - $value->then([$promise, 'resolve'], [$promise, 'reject']); - return $promise; - } - - return new FulfilledPromise($value); + return Create::promiseFor($value); } /** @@ -88,14 +62,12 @@ function promise_for($value) * @param mixed $reason Promise or reason. * * @return PromiseInterface + * + * @deprecated rejection_for will be removed in guzzlehttp/promises:2.0. Use Create::rejectionFor instead. */ function rejection_for($reason) { - if ($reason instanceof PromiseInterface) { - return $reason; - } - - return new RejectedPromise($reason); + return Create::rejectionFor($reason); } /** @@ -104,12 +76,12 @@ function rejection_for($reason) * @param mixed $reason * * @return \Exception|\Throwable + * + * @deprecated exception_for will be removed in guzzlehttp/promises:2.0. Use Create::exceptionFor instead. */ function exception_for($reason) { - return $reason instanceof \Exception || $reason instanceof \Throwable - ? $reason - : new RejectionException($reason); + return Create::exceptionFor($reason); } /** @@ -118,16 +90,12 @@ function exception_for($reason) * @param mixed $value * * @return \Iterator + * + * @deprecated iter_for will be removed in guzzlehttp/promises:2.0. Use Create::iterFor instead. */ function iter_for($value) { - if ($value instanceof \Iterator) { - return $value; - } elseif (is_array($value)) { - return new \ArrayIterator($value); - } else { - return new \ArrayIterator([$value]); - } + return Create::iterFor($value); } /** @@ -143,21 +111,12 @@ function iter_for($value) * @param PromiseInterface $promise Promise or value. * * @return array + * + * @deprecated inspect will be removed in guzzlehttp/promises:2.0. Use Utils::inspect instead. */ function inspect(PromiseInterface $promise) { - try { - return [ - 'state' => PromiseInterface::FULFILLED, - 'value' => $promise->wait() - ]; - } catch (RejectionException $e) { - return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()]; - } catch (\Throwable $e) { - return ['state' => PromiseInterface::REJECTED, 'reason' => $e]; - } catch (\Exception $e) { - return ['state' => PromiseInterface::REJECTED, 'reason' => $e]; - } + return Utils::inspect($promise); } /** @@ -166,19 +125,17 @@ function inspect(PromiseInterface $promise) * * Returns an array of inspection state arrays. * + * @see inspect for the inspection state array format. + * * @param PromiseInterface[] $promises Traversable of promises to wait upon. * * @return array - * @see GuzzleHttp\Promise\inspect for the inspection state array format. + * + * @deprecated inspect will be removed in guzzlehttp/promises:2.0. Use Utils::inspectAll instead. */ function inspect_all($promises) { - $results = []; - foreach ($promises as $key => $promise) { - $results[$key] = inspect($promise); - } - - return $results; + return Utils::inspectAll($promises); } /** @@ -188,20 +145,18 @@ function inspect_all($promises) * the promises were provided). An exception is thrown if any of the promises * are rejected. * - * @param mixed $promises Iterable of PromiseInterface objects to wait on. + * @param iterable $promises Iterable of PromiseInterface objects to wait on. * * @return array + * * @throws \Exception on error * @throws \Throwable on error in PHP >=7 + * + * @deprecated unwrap will be removed in guzzlehttp/promises:2.0. Use Utils::unwrap instead. */ function unwrap($promises) { - $results = []; - foreach ($promises as $key => $promise) { - $results[$key] = $promise->wait(); - } - - return $results; + return Utils::unwrap($promises); } /** @@ -212,25 +167,16 @@ function unwrap($promises) * respective positions to the original array. If any promise in the array * rejects, the returned promise is rejected with the rejection reason. * - * @param mixed $promises Promises or values. + * @param mixed $promises Promises or values. + * @param bool $recursive If true, resolves new promises that might have been added to the stack during its own resolution. * * @return PromiseInterface + * + * @deprecated all will be removed in guzzlehttp/promises:2.0. Use Utils::all instead. */ -function all($promises) +function all($promises, $recursive = false) { - $results = []; - return each( - $promises, - function ($value, $idx) use (&$results) { - $results[$idx] = $value; - }, - function ($reason, $idx, Promise $aggregate) { - $aggregate->reject($reason); - } - )->then(function () use (&$results) { - ksort($results); - return $results; - }); + return Utils::all($promises, $recursive); } /** @@ -241,45 +187,19 @@ function ($reason, $idx, Promise $aggregate) { * fulfilled with an array that contains the fulfillment values of the winners * in order of resolution. * - * This prommise is rejected with a {@see GuzzleHttp\Promise\AggregateException} - * if the number of fulfilled promises is less than the desired $count. + * This promise is rejected with a {@see AggregateException} if the number of + * fulfilled promises is less than the desired $count. * * @param int $count Total number of promises. * @param mixed $promises Promises or values. * * @return PromiseInterface + * + * @deprecated some will be removed in guzzlehttp/promises:2.0. Use Utils::some instead. */ function some($count, $promises) { - $results = []; - $rejections = []; - - return each( - $promises, - function ($value, $idx, PromiseInterface $p) use (&$results, $count) { - if ($p->getState() !== PromiseInterface::PENDING) { - return; - } - $results[$idx] = $value; - if (count($results) >= $count) { - $p->resolve(null); - } - }, - function ($reason) use (&$rejections) { - $rejections[] = $reason; - } - )->then( - function () use (&$results, &$rejections, $count) { - if (count($results) !== $count) { - throw new AggregateException( - 'Not enough promises to fulfill count', - $rejections - ); - } - ksort($results); - return array_values($results); - } - ); + return Utils::some($count, $promises); } /** @@ -289,10 +209,12 @@ function () use (&$results, &$rejections, $count) { * @param mixed $promises Promises or values. * * @return PromiseInterface + * + * @deprecated any will be removed in guzzlehttp/promises:2.0. Use Utils::any instead. */ function any($promises) { - return some(1, $promises)->then(function ($values) { return $values[0]; }); + return Utils::any($promises); } /** @@ -301,27 +223,17 @@ function any($promises) * * The returned promise is fulfilled with an array of inspection state arrays. * + * @see inspect for the inspection state array format. + * * @param mixed $promises Promises or values. * * @return PromiseInterface - * @see GuzzleHttp\Promise\inspect for the inspection state array format. + * + * @deprecated settle will be removed in guzzlehttp/promises:2.0. Use Utils::settle instead. */ function settle($promises) { - $results = []; - - return each( - $promises, - function ($value, $idx) use (&$results) { - $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value]; - }, - function ($reason, $idx) use (&$results) { - $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason]; - } - )->then(function () use (&$results) { - ksort($results); - return $results; - }); + return Utils::settle($promises); } /** @@ -329,29 +241,28 @@ function ($reason, $idx) use (&$results) { * fulfilled with a null value when the iterator has been consumed or the * aggregate promise has been fulfilled or rejected. * - * $onFulfilled is a function that accepts the fulfilled value, iterator - * index, and the aggregate promise. The callback can invoke any necessary side - * effects and choose to resolve or reject the aggregate promise if needed. + * $onFulfilled is a function that accepts the fulfilled value, iterator index, + * and the aggregate promise. The callback can invoke any necessary side + * effects and choose to resolve or reject the aggregate if needed. * - * $onRejected is a function that accepts the rejection reason, iterator - * index, and the aggregate promise. The callback can invoke any necessary side - * effects and choose to resolve or reject the aggregate promise if needed. + * $onRejected is a function that accepts the rejection reason, iterator index, + * and the aggregate promise. The callback can invoke any necessary side + * effects and choose to resolve or reject the aggregate if needed. * * @param mixed $iterable Iterator or array to iterate over. * @param callable $onFulfilled * @param callable $onRejected * * @return PromiseInterface + * + * @deprecated each will be removed in guzzlehttp/promises:2.0. Use Each::of instead. */ function each( $iterable, callable $onFulfilled = null, callable $onRejected = null ) { - return (new EachPromise($iterable, [ - 'fulfilled' => $onFulfilled, - 'rejected' => $onRejected - ]))->promise(); + return Each::of($iterable, $onFulfilled, $onRejected); } /** @@ -368,6 +279,8 @@ function each( * @param callable $onRejected * * @return PromiseInterface + * + * @deprecated each_limit will be removed in guzzlehttp/promises:2.0. Use Each::ofLimit instead. */ function each_limit( $iterable, @@ -375,11 +288,7 @@ function each_limit( callable $onFulfilled = null, callable $onRejected = null ) { - return (new EachPromise($iterable, [ - 'fulfilled' => $onFulfilled, - 'rejected' => $onRejected, - 'concurrency' => $concurrency - ]))->promise(); + return Each::ofLimit($iterable, $concurrency, $onFulfilled, $onRejected); } /** @@ -392,66 +301,63 @@ function each_limit( * @param callable $onFulfilled * * @return PromiseInterface + * + * @deprecated each_limit_all will be removed in guzzlehttp/promises:2.0. Use Each::ofLimitAll instead. */ function each_limit_all( $iterable, $concurrency, callable $onFulfilled = null ) { - return each_limit( - $iterable, - $concurrency, - $onFulfilled, - function ($reason, $idx, PromiseInterface $aggregate) { - $aggregate->reject($reason); - } - ); + return Each::ofLimitAll($iterable, $concurrency, $onFulfilled); } /** * Returns true if a promise is fulfilled. * - * @param PromiseInterface $promise - * * @return bool + * + * @deprecated is_fulfilled will be removed in guzzlehttp/promises:2.0. Use Is::fulfilled instead. */ function is_fulfilled(PromiseInterface $promise) { - return $promise->getState() === PromiseInterface::FULFILLED; + return Is::fulfilled($promise); } /** * Returns true if a promise is rejected. * - * @param PromiseInterface $promise - * * @return bool + * + * @deprecated is_rejected will be removed in guzzlehttp/promises:2.0. Use Is::rejected instead. */ function is_rejected(PromiseInterface $promise) { - return $promise->getState() === PromiseInterface::REJECTED; + return Is::rejected($promise); } /** * Returns true if a promise is fulfilled or rejected. * - * @param PromiseInterface $promise - * * @return bool + * + * @deprecated is_settled will be removed in guzzlehttp/promises:2.0. Use Is::settled instead. */ function is_settled(PromiseInterface $promise) { - return $promise->getState() !== PromiseInterface::PENDING; + return Is::settled($promise); } /** - * @see Coroutine + * Create a new coroutine. * - * @param callable $generatorFn + * @see Coroutine * * @return PromiseInterface + * + * @deprecated coroutine will be removed in guzzlehttp/promises:2.0. Use Coroutine::of instead. */ function coroutine(callable $generatorFn) { - return new Coroutine($generatorFn); + return Coroutine::of($generatorFn); } diff --git a/vendor/guzzlehttp/psr7/.github/FUNDING.yml b/vendor/guzzlehttp/psr7/.github/FUNDING.yml new file mode 100644 index 00000000..7d222c58 --- /dev/null +++ b/vendor/guzzlehttp/psr7/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: [Nyholm, GrahamCampbell] +tidelift: "packagist/guzzlehttp/psr7" diff --git a/vendor/guzzlehttp/psr7/.github/stale.yml b/vendor/guzzlehttp/psr7/.github/stale.yml new file mode 100644 index 00000000..53faa71b --- /dev/null +++ b/vendor/guzzlehttp/psr7/.github/stale.yml @@ -0,0 +1,14 @@ +daysUntilStale: 120 +daysUntilClose: 14 +exemptLabels: + - lifecycle/keep-open + - lifecycle/ready-for-merge +# Label to use when marking an issue as stale +staleLabel: lifecycle/stale +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed after 2 weeks if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/vendor/guzzlehttp/psr7/.github/workflows/ci.yml b/vendor/guzzlehttp/psr7/.github/workflows/ci.yml new file mode 100644 index 00000000..eda7dceb --- /dev/null +++ b/vendor/guzzlehttp/psr7/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: CI + +on: + pull_request: + +jobs: + build: + name: Build + runs-on: ubuntu-latest + strategy: + max-parallel: 10 + matrix: + php: ['5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] + + steps: + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: 'none' + extensions: mbstring + + - name: Checkout code + uses: actions/checkout@v2 + + - name: Mimic PHP 8.0 + run: composer config platform.php 8.0.999 + if: matrix.php > 8 + + - name: Install dependencies + run: composer update --no-interaction --no-progress + + - name: Run tests + run: make test diff --git a/vendor/guzzlehttp/psr7/.github/workflows/integration.yml b/vendor/guzzlehttp/psr7/.github/workflows/integration.yml new file mode 100644 index 00000000..3c31f9ef --- /dev/null +++ b/vendor/guzzlehttp/psr7/.github/workflows/integration.yml @@ -0,0 +1,37 @@ +name: Integration + +on: + pull_request: + +jobs: + + build: + name: Test + runs-on: ubuntu-latest + strategy: + max-parallel: 10 + matrix: + php: ['7.2', '7.3', '7.4', '8.0'] + + steps: + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + + - name: Checkout code + uses: actions/checkout@v2 + + - name: Download dependencies + uses: ramsey/composer-install@v1 + with: + composer-options: --no-interaction --optimize-autoloader + + - name: Start server + run: php -S 127.0.0.1:10002 tests/Integration/server.php & + + - name: Run tests + env: + TEST_SERVER: 127.0.0.1:10002 + run: ./vendor/bin/phpunit --testsuite Integration diff --git a/vendor/guzzlehttp/psr7/.github/workflows/static.yml b/vendor/guzzlehttp/psr7/.github/workflows/static.yml new file mode 100644 index 00000000..ab4d68ba --- /dev/null +++ b/vendor/guzzlehttp/psr7/.github/workflows/static.yml @@ -0,0 +1,29 @@ +name: Static analysis + +on: + pull_request: + +jobs: + php-cs-fixer: + name: PHP-CS-Fixer + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + coverage: none + extensions: mbstring + + - name: Download dependencies + run: composer update --no-interaction --no-progress + + - name: Download PHP CS Fixer + run: composer require "friendsofphp/php-cs-fixer:2.18.4" + + - name: Execute PHP CS Fixer + run: vendor/bin/php-cs-fixer fix --diff-format udiff --dry-run diff --git a/vendor/guzzlehttp/psr7/.php_cs.dist b/vendor/guzzlehttp/psr7/.php_cs.dist new file mode 100644 index 00000000..e4f0bd53 --- /dev/null +++ b/vendor/guzzlehttp/psr7/.php_cs.dist @@ -0,0 +1,56 @@ +setRiskyAllowed(true) + ->setRules([ + '@PSR2' => true, + 'array_syntax' => ['syntax' => 'short'], + 'concat_space' => ['spacing' => 'one'], + 'declare_strict_types' => false, + 'final_static_access' => true, + 'fully_qualified_strict_types' => true, + 'header_comment' => false, + 'is_null' => ['use_yoda_style' => true], + 'list_syntax' => ['syntax' => 'long'], + 'lowercase_cast' => true, + 'magic_method_casing' => true, + 'modernize_types_casting' => true, + 'multiline_comment_opening_closing' => true, + 'no_alias_functions' => true, + 'no_alternative_syntax' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_empty_comment' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_blank_lines' => true, + 'no_leading_import_slash' => true, + 'no_trailing_comma_in_singleline_array' => true, + 'no_unset_cast' => true, + 'no_unused_imports' => true, + 'no_whitespace_in_blank_line' => true, + 'ordered_imports' => true, + 'php_unit_ordered_covers' => true, + 'php_unit_test_annotation' => ['style' => 'prefix'], + 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'], + 'phpdoc_align' => ['align' => 'vertical'], + 'phpdoc_no_useless_inheritdoc' => true, + 'phpdoc_scalar' => true, + 'phpdoc_separation' => true, + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_trim' => true, + 'phpdoc_trim_consecutive_blank_line_separation' => true, + 'phpdoc_types' => true, + 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], + 'phpdoc_var_without_name' => true, + 'single_trait_insert_per_statement' => true, + 'standardize_not_equals' => true, + ]) + ->setFinder( + PhpCsFixer\Finder::create() + ->in(__DIR__.'/src') + ->in(__DIR__.'/tests') + ->name('*.php') + ) +; + +return $config; diff --git a/vendor/guzzlehttp/psr7/CHANGELOG.md b/vendor/guzzlehttp/psr7/CHANGELOG.md index 5c252b3a..b4fdf3c6 100644 --- a/vendor/guzzlehttp/psr7/CHANGELOG.md +++ b/vendor/guzzlehttp/psr7/CHANGELOG.md @@ -1,32 +1,175 @@ -# CHANGELOG +# Change Log -## 1.4.2 - 2017-03-20 -* Reverted BC break to `Uri::resolve` and `Uri::removeDotSegments` by removing +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## Unreleased + +## 1.9.0 - 2022-06-20 + +### Added + +- Added `UriComparator::isCrossOrigin` method + +## 1.8.5 - 2022-03-20 + +### Fixed + +- Correct header value validation + +## 1.8.4 - 2022-03-20 + +### Fixed + +- Validate header values properly + +## 1.8.3 - 2021-10-05 + +### Fixed + +- Return `null` in caching stream size if remote size is `null` + +## 1.8.2 - 2021-04-26 + +### Fixed + +- Handle possibly unset `url` in `stream_get_meta_data` + +## 1.8.1 - 2021-03-21 + +### Fixed + +- Issue parsing IPv6 URLs +- Issue modifying ServerRequest lost all its attributes + +## 1.8.0 - 2021-03-21 + +### Added + +- Locale independent URL parsing +- Most classes got a `@final` annotation to prepare for 2.0 + +### Fixed + +- Issue when creating stream from `php://input` and curl-ext is not installed +- Broken `Utils::tryFopen()` on PHP 8 + +## 1.7.0 - 2020-09-30 + +### Added + +- Replaced functions by static methods + +### Fixed + +- Converting a non-seekable stream to a string +- Handle multiple Set-Cookie correctly +- Ignore array keys in header values when merging +- Allow multibyte characters to be parsed in `Message:bodySummary()` + +### Changed + +- Restored partial HHVM 3 support + + +## [1.6.1] - 2019-07-02 + +### Fixed + +- Accept null and bool header values again + + +## [1.6.0] - 2019-06-30 + +### Added + +- Allowed version `^3.0` of `ralouphie/getallheaders` dependency (#244) +- Added MIME type for WEBP image format (#246) +- Added more validation of values according to PSR-7 and RFC standards, e.g. status code range (#250, #272) + +### Changed + +- Tests don't pass with HHVM 4.0, so HHVM support got dropped. Other libraries like composer have done the same. (#262) +- Accept port number 0 to be valid (#270) + +### Fixed + +- Fixed subsequent reads from `php://input` in ServerRequest (#247) +- Fixed readable/writable detection for certain stream modes (#248) +- Fixed encoding of special characters in the `userInfo` component of an URI (#253) + + +## [1.5.2] - 2018-12-04 + +### Fixed + +- Check body size when getting the message summary + + +## [1.5.1] - 2018-12-04 + +### Fixed + +- Get the summary of a body only if it is readable + + +## [1.5.0] - 2018-12-03 + +### Added + +- Response first-line to response string exception (fixes #145) +- A test for #129 behavior +- `get_message_body_summary` function in order to get the message summary +- `3gp` and `mkv` mime types + +### Changed + +- Clarify exception message when stream is detached + +### Deprecated + +- Deprecated parsing folded header lines as per RFC 7230 + +### Fixed + +- Fix `AppendStream::detach` to not close streams +- `InflateStream` preserves `isSeekable` attribute of the underlying stream +- `ServerRequest::getUriFromGlobals` to support URLs in query parameters + + +Several other fixes and improvements. + + +## [1.4.2] - 2017-03-20 + +### Fixed + +- Reverted BC break to `Uri::resolve` and `Uri::removeDotSegments` by removing calls to `trigger_error` when deprecated methods are invoked. -## 1.4.1 - 2017-02-27 -* Reverted BC break by reintroducing behavior to automagically fix a URI with a +## [1.4.1] - 2017-02-27 + +### Added + +- Rriggering of silenced deprecation warnings. + +### Fixed + +- Reverted BC break by reintroducing behavior to automagically fix a URI with a relative path and an authority by adding a leading slash to the path. It's only deprecated now. -* Added triggering of silenced deprecation warnings. -## 1.4.0 - 2017-02-21 -* Fix `Stream::read` when length parameter <= 0. -* `copy_to_stream` reads bytes in chunks instead of `maxLen` into memory. -* Fix `ServerRequest::getUriFromGlobals` when `Host` header contains port. -* Ensure `ServerRequest::getUriFromGlobals` returns a URI in absolute form. -* Allow `parse_response` to parse a response without delimiting space and reason. -* Ensure each URI modification results in a valid URI according to PSR-7 discussions. - Invalid modifications will throw an exception instead of returning a wrong URI or - doing some magic. - - `(new Uri)->withPath('foo')->withHost('example.com')` will throw an exception - because the path of a URI with an authority must start with a slash "/" or be empty - - `(new Uri())->withScheme('http')` will return `'http://localhost'` -* Fix compatibility of URIs with `file` scheme and empty host. -* Added common URI utility methods based on RFC 3986 (see documentation in the readme): +## [1.4.0] - 2017-02-21 + +### Added + +- Added common URI utility methods based on RFC 3986 (see documentation in the readme): - `Uri::isDefaultPort` - `Uri::isAbsolute` - `Uri::isNetworkPathReference` @@ -37,69 +180,117 @@ - `UriNormalizer::normalize` - `UriNormalizer::isEquivalent` - `UriResolver::relativize` -* Deprecated `Uri::resolve` in favor of `UriResolver::resolve` -* Deprecated `Uri::removeDotSegments` in favor of `UriResolver::removeDotSegments` -## 1.3.1 - 2016-06-25 +### Changed + +- Ensure `ServerRequest::getUriFromGlobals` returns a URI in absolute form. +- Allow `parse_response` to parse a response without delimiting space and reason. +- Ensure each URI modification results in a valid URI according to PSR-7 discussions. + Invalid modifications will throw an exception instead of returning a wrong URI or + doing some magic. + - `(new Uri)->withPath('foo')->withHost('example.com')` will throw an exception + because the path of a URI with an authority must start with a slash "/" or be empty + - `(new Uri())->withScheme('http')` will return `'http://localhost'` + +### Deprecated + +- `Uri::resolve` in favor of `UriResolver::resolve` +- `Uri::removeDotSegments` in favor of `UriResolver::removeDotSegments` + +### Fixed + +- `Stream::read` when length parameter <= 0. +- `copy_to_stream` reads bytes in chunks instead of `maxLen` into memory. +- `ServerRequest::getUriFromGlobals` when `Host` header contains port. +- Compatibility of URIs with `file` scheme and empty host. + -* Fix `Uri::__toString` for network path references, e.g. `//example.org`. -* Fix missing lowercase normalization for host. -* Fix handling of URI components in case they are `'0'` in a lot of places, +## [1.3.1] - 2016-06-25 + +### Fixed + +- `Uri::__toString` for network path references, e.g. `//example.org`. +- Missing lowercase normalization for host. +- Handling of URI components in case they are `'0'` in a lot of places, e.g. as a user info password. -* Fix `Uri::withAddedHeader` to correctly merge headers with different case. -* Fix trimming of header values in `Uri::withAddedHeader`. Header values may +- `Uri::withAddedHeader` to correctly merge headers with different case. +- Trimming of header values in `Uri::withAddedHeader`. Header values may be surrounded by whitespace which should be ignored according to RFC 7230 Section 3.2.4. This does not apply to header names. -* Fix `Uri::withAddedHeader` with an array of header values. -* Fix `Uri::resolve` when base path has no slash and handling of fragment. -* Fix handling of encoding in `Uri::with(out)QueryValue` so one can pass the +- `Uri::withAddedHeader` with an array of header values. +- `Uri::resolve` when base path has no slash and handling of fragment. +- Handling of encoding in `Uri::with(out)QueryValue` so one can pass the key/value both in encoded as well as decoded form to those methods. This is consistent with withPath, withQuery etc. -* Fix `ServerRequest::withoutAttribute` when attribute value is null. +- `ServerRequest::withoutAttribute` when attribute value is null. + + +## [1.3.0] - 2016-04-13 -## 1.3.0 - 2016-04-13 +### Added -* Added remaining interfaces needed for full PSR7 compatibility +- Remaining interfaces needed for full PSR7 compatibility (ServerRequestInterface, UploadedFileInterface, etc.). -* Added support for stream_for from scalars. -* Can now extend Uri. -* Fixed a bug in validating request methods by making it more permissive. +- Support for stream_for from scalars. + +### Changed + +- Can now extend Uri. + +### Fixed +- A bug in validating request methods by making it more permissive. -## 1.2.3 - 2016-02-18 -* Fixed support in `GuzzleHttp\Psr7\CachingStream` for seeking forward on remote +## [1.2.3] - 2016-02-18 + +### Fixed + +- Support in `GuzzleHttp\Psr7\CachingStream` for seeking forward on remote streams, which can sometimes return fewer bytes than requested with `fread`. -* Fixed handling of gzipped responses with FNAME headers. +- Handling of gzipped responses with FNAME headers. + + +## [1.2.2] - 2016-01-22 + +### Added + +- Support for URIs without any authority. +- Support for HTTP 451 'Unavailable For Legal Reasons.' +- Support for using '0' as a filename. +- Support for including non-standard ports in Host headers. + -## 1.2.2 - 2016-01-22 +## [1.2.1] - 2015-11-02 -* Added support for URIs without any authority. -* Added support for HTTP 451 'Unavailable For Legal Reasons.' -* Added support for using '0' as a filename. -* Added support for including non-standard ports in Host headers. +### Changes -## 1.2.1 - 2015-11-02 +- Now supporting negative offsets when seeking to SEEK_END. -* Now supporting negative offsets when seeking to SEEK_END. -## 1.2.0 - 2015-08-15 +## [1.2.0] - 2015-08-15 -* Body as `"0"` is now properly added to a response. -* Now allowing forward seeking in CachingStream. -* Now properly parsing HTTP requests that contain proxy targets in +### Changed + +- Body as `"0"` is now properly added to a response. +- Now allowing forward seeking in CachingStream. +- Now properly parsing HTTP requests that contain proxy targets in `parse_request`. -* functions.php is now conditionally required. -* user-info is no longer dropped when resolving URIs. +- functions.php is now conditionally required. +- user-info is no longer dropped when resolving URIs. + -## 1.1.0 - 2015-06-24 +## [1.1.0] - 2015-06-24 -* URIs can now be relative. -* `multipart/form-data` headers are now overridden case-insensitively. -* URI paths no longer encode the following characters because they are allowed +### Changed + +- URIs can now be relative. +- `multipart/form-data` headers are now overridden case-insensitively. +- URI paths no longer encode the following characters because they are allowed in URIs: "(", ")", "*", "!", "'" -* A port is no longer added to a URI when the scheme is missing and no port is +- A port is no longer added to a URI when the scheme is missing and no port is present. + ## 1.0.0 - 2015-05-19 Initial release. @@ -108,3 +299,20 @@ Currently unsupported: - `Psr\Http\Message\ServerRequestInterface` - `Psr\Http\Message\UploadedFileInterface` + + + +[1.6.0]: https://github.com/guzzle/psr7/compare/1.5.2...1.6.0 +[1.5.2]: https://github.com/guzzle/psr7/compare/1.5.1...1.5.2 +[1.5.1]: https://github.com/guzzle/psr7/compare/1.5.0...1.5.1 +[1.5.0]: https://github.com/guzzle/psr7/compare/1.4.2...1.5.0 +[1.4.2]: https://github.com/guzzle/psr7/compare/1.4.1...1.4.2 +[1.4.1]: https://github.com/guzzle/psr7/compare/1.4.0...1.4.1 +[1.4.0]: https://github.com/guzzle/psr7/compare/1.3.1...1.4.0 +[1.3.1]: https://github.com/guzzle/psr7/compare/1.3.0...1.3.1 +[1.3.0]: https://github.com/guzzle/psr7/compare/1.2.3...1.3.0 +[1.2.3]: https://github.com/guzzle/psr7/compare/1.2.2...1.2.3 +[1.2.2]: https://github.com/guzzle/psr7/compare/1.2.1...1.2.2 +[1.2.1]: https://github.com/guzzle/psr7/compare/1.2.0...1.2.1 +[1.2.0]: https://github.com/guzzle/psr7/compare/1.1.0...1.2.0 +[1.1.0]: https://github.com/guzzle/psr7/compare/1.0.0...1.1.0 diff --git a/vendor/guzzlehttp/psr7/LICENSE b/vendor/guzzlehttp/psr7/LICENSE index 581d95f9..51c7ec81 100644 --- a/vendor/guzzlehttp/psr7/LICENSE +++ b/vendor/guzzlehttp/psr7/LICENSE @@ -1,4 +1,11 @@ -Copyright (c) 2015 Michael Dowling, https://github.com/mtdowling +The MIT License (MIT) + +Copyright (c) 2015 Michael Dowling +Copyright (c) 2015 Mรกrk Sรกgi-Kazรกr +Copyright (c) 2015 Graham Campbell +Copyright (c) 2016 Tobias Schultze +Copyright (c) 2016 George Mponos +Copyright (c) 2018 Tobias Nyholm Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/guzzlehttp/psr7/README.md b/vendor/guzzlehttp/psr7/README.md index 16499358..64776cb6 100644 --- a/vendor/guzzlehttp/psr7/README.md +++ b/vendor/guzzlehttp/psr7/README.md @@ -1,6 +1,6 @@ # PSR-7 Message Implementation -This repository contains a full [PSR-7](http://www.php-fig.org/psr/psr-7/) +This repository contains a full [PSR-7](https://www.php-fig.org/psr/psr-7/) message implementation, several stream decorators, and some helpful functionality like query string parsing. @@ -23,11 +23,11 @@ Reads from multiple streams, one after the other. ```php use GuzzleHttp\Psr7; -$a = Psr7\stream_for('abc, '); -$b = Psr7\stream_for('123.'); +$a = Psr7\Utils::streamFor('abc, '); +$b = Psr7\Utils::streamFor('123.'); $composed = new Psr7\AppendStream([$a, $b]); -$composed->addStream(Psr7\stream_for(' Above all listen to me')); +$composed->addStream(Psr7\Utils::streamFor(' Above all listen to me')); echo $composed; // abc, 123. Above all listen to me. ``` @@ -65,7 +65,7 @@ then on disk. ```php use GuzzleHttp\Psr7; -$original = Psr7\stream_for(fopen('http://www.google.com', 'r')); +$original = Psr7\Utils::streamFor(fopen('http://www.google.com', 'r')); $stream = new Psr7\CachingStream($original); $stream->read(1024); @@ -89,7 +89,7 @@ stream becomes too full. use GuzzleHttp\Psr7; // Create an empty stream -$stream = Psr7\stream_for(); +$stream = Psr7\Utils::streamFor(); // Start dropping data when the stream has more than 10 bytes $dropping = new Psr7\DroppingStream($stream, 10); @@ -112,7 +112,7 @@ to create a concrete class for a simple extension point. use GuzzleHttp\Psr7; -$stream = Psr7\stream_for('hi'); +$stream = Psr7\Utils::streamFor('hi'); $fnStream = Psr7\FnStream::decorate($stream, [ 'rewind' => function () use ($stream) { echo 'About to rewind - '; @@ -167,7 +167,7 @@ chunks (e.g. Amazon S3's multipart upload API). ```php use GuzzleHttp\Psr7; -$original = Psr7\stream_for(fopen('/tmp/test.txt', 'r+')); +$original = Psr7\Utils::streamFor(fopen('/tmp/test.txt', 'r+')); echo $original->getSize(); // >>> 1048576 @@ -197,7 +197,7 @@ NoSeekStream wraps a stream and does not allow seeking. ```php use GuzzleHttp\Psr7; -$original = Psr7\stream_for('foo'); +$original = Psr7\Utils::streamFor('foo'); $noSeek = new Psr7\NoSeekStream($original); echo $noSeek->read(3); @@ -271,7 +271,7 @@ This decorator could be added to any existing stream and used like so: ```php use GuzzleHttp\Psr7; -$original = Psr7\stream_for('foo'); +$original = Psr7\Utils::streamFor('foo'); $eofStream = new EofCallbackStream($original, function () { echo 'EOF!'; @@ -297,228 +297,292 @@ stream from a PSR-7 stream. ```php use GuzzleHttp\Psr7\StreamWrapper; -$stream = GuzzleHttp\Psr7\stream_for('hello!'); +$stream = GuzzleHttp\Psr7\Utils::streamFor('hello!'); $resource = StreamWrapper::getResource($stream); echo fread($resource, 6); // outputs hello! ``` -# Function API +# Static API -There are various functions available under the `GuzzleHttp\Psr7` namespace. +There are various static methods available under the `GuzzleHttp\Psr7` namespace. -## `function str` +## `GuzzleHttp\Psr7\Message::toString` -`function str(MessageInterface $message)` +`public static function toString(MessageInterface $message): string` Returns the string representation of an HTTP message. ```php $request = new GuzzleHttp\Psr7\Request('GET', 'http://example.com'); -echo GuzzleHttp\Psr7\str($request); +echo GuzzleHttp\Psr7\Message::toString($request); ``` -## `function uri_for` +## `GuzzleHttp\Psr7\Message::bodySummary` -`function uri_for($uri)` +`public static function bodySummary(MessageInterface $message, int $truncateAt = 120): string|null` -This function accepts a string or `Psr\Http\Message\UriInterface` and returns a -UriInterface for the given value. If the value is already a `UriInterface`, it -is returned as-is. +Get a short summary of the message body. -```php -$uri = GuzzleHttp\Psr7\uri_for('http://example.com'); -assert($uri === GuzzleHttp\Psr7\uri_for($uri)); -``` +Will return `null` if the response is not printable. -## `function stream_for` +## `GuzzleHttp\Psr7\Message::rewindBody` -`function stream_for($resource = '', array $options = [])` +`public static function rewindBody(MessageInterface $message): void` -Create a new stream based on the input type. +Attempts to rewind a message body and throws an exception on failure. -Options is an associative array that can contain the following keys: +The body of the message will only be rewound if a call to `tell()` +returns a value other than `0`. -* - metadata: Array of custom metadata. -* - size: Size of the stream. -This method accepts the following `$resource` types: +## `GuzzleHttp\Psr7\Message::parseMessage` -- `Psr\Http\Message\StreamInterface`: Returns the value as-is. -- `string`: Creates a stream object that uses the given string as the contents. -- `resource`: Creates a stream object that wraps the given PHP stream resource. -- `Iterator`: If the provided value implements `Iterator`, then a read-only - stream object will be created that wraps the given iterable. Each time the - stream is read from, data from the iterator will fill a buffer and will be - continuously called until the buffer is equal to the requested read size. - Subsequent read calls will first read from the buffer and then call `next` - on the underlying iterator until it is exhausted. -- `object` with `__toString()`: If the object has the `__toString()` method, - the object will be cast to a string and then a stream will be returned that - uses the string value. -- `NULL`: When `null` is passed, an empty stream object is returned. -- `callable` When a callable is passed, a read-only stream object will be - created that invokes the given callable. The callable is invoked with the - number of suggested bytes to read. The callable can return any number of - bytes, but MUST return `false` when there is no more data to return. The - stream object that wraps the callable will invoke the callable until the - number of requested bytes are available. Any additional bytes will be - buffered and used in subsequent reads. +`public static function parseMessage(string $message): array` -```php -$stream = GuzzleHttp\Psr7\stream_for('foo'); -$stream = GuzzleHttp\Psr7\stream_for(fopen('/path/to/file', 'r')); +Parses an HTTP message into an associative array. -$generator function ($bytes) { - for ($i = 0; $i < $bytes; $i++) { - yield ' '; - } -} +The array contains the "start-line" key containing the start line of +the message, "headers" key containing an associative array of header +array values, and a "body" key containing the body of the message. -$stream = GuzzleHttp\Psr7\stream_for($generator(100)); -``` +## `GuzzleHttp\Psr7\Message::parseRequestUri` -## `function parse_header` +`public static function parseRequestUri(string $path, array $headers): string` -`function parse_header($header)` +Constructs a URI for an HTTP request message. -Parse an array of header values containing ";" separated data into an array of -associative arrays representing the header key value pair data of the header. -When a parameter does not contain a value, but just contains a key, this -function will inject a key with a '' string value. +## `GuzzleHttp\Psr7\Message::parseRequest` -## `function normalize_header` +`public static function parseRequest(string $message): Request` -`function normalize_header($header)` +Parses a request message string into a request object. -Converts an array of header values that may contain comma separated headers -into an array of headers with no comma separated values. +## `GuzzleHttp\Psr7\Message::parseResponse` -## `function modify_request` +`public static function parseResponse(string $message): Response` -`function modify_request(RequestInterface $request, array $changes)` +Parses a response message string into a response object. -Clone and modify a request with the given changes. This method is useful for -reducing the number of clones needed to mutate a message. -The changes can be one of: +## `GuzzleHttp\Psr7\Header::parse` -- method: (string) Changes the HTTP method. -- set_headers: (array) Sets the given headers. -- remove_headers: (array) Remove the given headers. -- body: (mixed) Sets the given body. -- uri: (UriInterface) Set the URI. -- query: (string) Set the query string value of the URI. -- version: (string) Set the protocol version. +`public static function parse(string|array $header): array` +Parse an array of header values containing ";" separated data into an +array of associative arrays representing the header key value pair data +of the header. When a parameter does not contain a value, but just +contains a key, this function will inject a key with a '' string value. -## `function rewind_body` -`function rewind_body(MessageInterface $message)` +## `GuzzleHttp\Psr7\Header::normalize` -Attempts to rewind a message body and throws an exception on failure. The body -of the message will only be rewound if a call to `tell()` returns a value other -than `0`. +`public static function normalize(string|array $header): array` +Converts an array of header values that may contain comma separated +headers into an array of headers with no comma separated values. -## `function try_fopen` -`function try_fopen($filename, $mode)` +## `GuzzleHttp\Psr7\Query::parse` -Safely opens a PHP stream resource using a filename. +`public static function parse(string $str, int|bool $urlEncoding = true): array` + +Parse a query string into an associative array. + +If multiple values are found for the same key, the value of that key +value pair will become an array. This function does not parse nested +PHP style arrays into an associative array (e.g., `foo[a]=1&foo[b]=2` +will be parsed into `['foo[a]' => '1', 'foo[b]' => '2'])`. -When fopen fails, PHP normally raises a warning. This function adds an error -handler that checks for errors and throws an exception instead. +## `GuzzleHttp\Psr7\Query::build` + +`public static function build(array $params, int|false $encoding = PHP_QUERY_RFC3986): string` + +Build a query string from an array of key value pairs. + +This function can use the return value of `parse()` to build a query +string. This function does not modify the provided keys when an array is +encountered (like `http_build_query()` would). -## `function copy_to_string` -`function copy_to_string(StreamInterface $stream, $maxLen = -1)` +## `GuzzleHttp\Psr7\Utils::caselessRemove` -Copy the contents of a stream into a string until the given number of bytes -have been read. +`public static function caselessRemove(iterable $keys, $keys, array $data): array` +Remove the items given by the keys, case insensitively from the data. -## `function copy_to_stream` -`function copy_to_stream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)` +## `GuzzleHttp\Psr7\Utils::copyToStream` -Copy the contents of a stream into another stream until the given number of +`public static function copyToStream(StreamInterface $source, StreamInterface $dest, int $maxLen = -1): void` + +Copy the contents of a stream into another stream until the given number +of bytes have been read. + + +## `GuzzleHttp\Psr7\Utils::copyToString` + +`public static function copyToString(StreamInterface $stream, int $maxLen = -1): string` + +Copy the contents of a stream into a string until the given number of bytes have been read. -## `function hash` +## `GuzzleHttp\Psr7\Utils::hash` + +`public static function hash(StreamInterface $stream, string $algo, bool $rawOutput = false): string` + +Calculate a hash of a stream. + +This method reads the entire stream to calculate a rolling hash, based on +PHP's `hash_init` functions. -`function hash(StreamInterface $stream, $algo, $rawOutput = false)` -Calculate a hash of a Stream. This method reads the entire stream to calculate -a rolling hash (based on PHP's hash_init functions). +## `GuzzleHttp\Psr7\Utils::modifyRequest` + +`public static function modifyRequest(RequestInterface $request, array $changes): RequestInterface` + +Clone and modify a request with the given changes. + +This method is useful for reducing the number of clones needed to mutate +a message. + +- method: (string) Changes the HTTP method. +- set_headers: (array) Sets the given headers. +- remove_headers: (array) Remove the given headers. +- body: (mixed) Sets the given body. +- uri: (UriInterface) Set the URI. +- query: (string) Set the query string value of the URI. +- version: (string) Set the protocol version. -## `function readline` +## `GuzzleHttp\Psr7\Utils::readLine` -`function readline(StreamInterface $stream, $maxLength = null)` +`public static function readLine(StreamInterface $stream, int $maxLength = null): string` Read a line from the stream up to the maximum allowed buffer length. -## `function parse_request` +## `GuzzleHttp\Psr7\Utils::streamFor` -`function parse_request($message)` +`public static function streamFor(resource|string|null|int|float|bool|StreamInterface|callable|\Iterator $resource = '', array $options = []): StreamInterface` -Parses a request message string into a request object. +Create a new stream based on the input type. +Options is an associative array that can contain the following keys: -## `function parse_response` +- metadata: Array of custom metadata. +- size: Size of the stream. -`function parse_response($message)` +This method accepts the following `$resource` types: -Parses a response message string into a response object. +- `Psr\Http\Message\StreamInterface`: Returns the value as-is. +- `string`: Creates a stream object that uses the given string as the contents. +- `resource`: Creates a stream object that wraps the given PHP stream resource. +- `Iterator`: If the provided value implements `Iterator`, then a read-only + stream object will be created that wraps the given iterable. Each time the + stream is read from, data from the iterator will fill a buffer and will be + continuously called until the buffer is equal to the requested read size. + Subsequent read calls will first read from the buffer and then call `next` + on the underlying iterator until it is exhausted. +- `object` with `__toString()`: If the object has the `__toString()` method, + the object will be cast to a string and then a stream will be returned that + uses the string value. +- `NULL`: When `null` is passed, an empty stream object is returned. +- `callable` When a callable is passed, a read-only stream object will be + created that invokes the given callable. The callable is invoked with the + number of suggested bytes to read. The callable can return any number of + bytes, but MUST return `false` when there is no more data to return. The + stream object that wraps the callable will invoke the callable until the + number of requested bytes are available. Any additional bytes will be + buffered and used in subsequent reads. +```php +$stream = GuzzleHttp\Psr7\Utils::streamFor('foo'); +$stream = GuzzleHttp\Psr7\Utils::streamFor(fopen('/path/to/file', 'r')); -## `function parse_query` +$generator = function ($bytes) { + for ($i = 0; $i < $bytes; $i++) { + yield ' '; + } +} -`function parse_query($str, $urlEncoding = true)` +$stream = GuzzleHttp\Psr7\Utils::streamFor($generator(100)); +``` -Parse a query string into an associative array. -If multiple values are found for the same key, the value of that key value pair -will become an array. This function does not parse nested PHP style arrays into -an associative array (e.g., `foo[a]=1&foo[b]=2` will be parsed into -`['foo[a]' => '1', 'foo[b]' => '2']`). +## `GuzzleHttp\Psr7\Utils::tryFopen` +`public static function tryFopen(string $filename, string $mode): resource` -## `function build_query` +Safely opens a PHP stream resource using a filename. -`function build_query(array $params, $encoding = PHP_QUERY_RFC3986)` +When fopen fails, PHP normally raises a warning. This function adds an +error handler that checks for errors and throws an exception instead. -Build a query string from an array of key value pairs. -This function can use the return value of parse_query() to build a query string. -This function does not modify the provided keys when an array is encountered -(like http_build_query would). +## `GuzzleHttp\Psr7\Utils::uriFor` + +`public static function uriFor(string|UriInterface $uri): UriInterface` + +Returns a UriInterface for the given value. +This function accepts a string or UriInterface and returns a +UriInterface for the given value. If the value is already a +UriInterface, it is returned as-is. -## `function mimetype_from_filename` -`function mimetype_from_filename($filename)` +## `GuzzleHttp\Psr7\MimeType::fromFilename` + +`public static function fromFilename(string $filename): string|null` Determines the mimetype of a file by looking at its extension. -## `function mimetype_from_extension` +## `GuzzleHttp\Psr7\MimeType::fromExtension` -`function mimetype_from_extension($extension)` +`public static function fromExtension(string $extension): string|null` Maps a file extensions to a mimetype. +## Upgrading from Function API + +The static API was first introduced in 1.7.0, in order to mitigate problems with functions conflicting between global and local copies of the package. The function API will be removed in 2.0.0. A migration table has been provided here for your convenience: + +| Original Function | Replacement Method | +|----------------|----------------| +| `str` | `Message::toString` | +| `uri_for` | `Utils::uriFor` | +| `stream_for` | `Utils::streamFor` | +| `parse_header` | `Header::parse` | +| `normalize_header` | `Header::normalize` | +| `modify_request` | `Utils::modifyRequest` | +| `rewind_body` | `Message::rewindBody` | +| `try_fopen` | `Utils::tryFopen` | +| `copy_to_string` | `Utils::copyToString` | +| `copy_to_stream` | `Utils::copyToStream` | +| `hash` | `Utils::hash` | +| `readline` | `Utils::readLine` | +| `parse_request` | `Message::parseRequest` | +| `parse_response` | `Message::parseResponse` | +| `parse_query` | `Query::parse` | +| `build_query` | `Query::build` | +| `mimetype_from_filename` | `MimeType::fromFilename` | +| `mimetype_from_extension` | `MimeType::fromExtension` | +| `_parse_message` | `Message::parseMessage` | +| `_parse_request_uri` | `Message::parseRequestUri` | +| `get_message_body_summary` | `Message::bodySummary` | +| `_caseless_remove` | `Utils::caselessRemove` | + + # Additional URI Methods Aside from the standard `Psr\Http\Message\UriInterface` implementation in form of the `GuzzleHttp\Psr7\Uri` class, @@ -595,7 +659,7 @@ manually but instead is used indirectly via `Psr\Http\Message\UriInterface::__to `public static function fromParts(array $parts): UriInterface` -Creates a URI from a hash of [`parse_url`](http://php.net/manual/en/function.parse-url.php) components. +Creates a URI from a hash of [`parse_url`](https://www.php.net/manual/en/function.parse-url.php) components. ### `GuzzleHttp\Psr7\Uri::withQueryValue` @@ -606,6 +670,12 @@ Creates a new URI with a specific query string value. Any existing query string provided key are removed and replaced with the given key value pair. A value of null will set the query string key without a value, e.g. "key" instead of "key=value". +### `GuzzleHttp\Psr7\Uri::withQueryValues` + +`public static function withQueryValues(UriInterface $uri, array $keyValueArray): UriInterface` + +Creates a new URI with multiple query string values. It has the same behavior as `withQueryValue()` but for an +associative array of key => value. ### `GuzzleHttp\Psr7\Uri::withoutQueryValue` @@ -614,6 +684,16 @@ key without a value, e.g. "key" instead of "key=value". Creates a new URI with a specific query string value removed. Any existing query string values that exactly match the provided key are removed. +## Cross-Origin Detection + +`GuzzleHttp\Psr7\UriComparator` provides methods to determine if a modified URL should be considered cross-origin. + +### `GuzzleHttp\Psr7\UriComparator::isCrossOrigin` + +`public static function isCrossOrigin(UriInterface $original, UriInterface $modified): bool` + +Determines if a modified URL should be considered cross-origin with respect to an original URL. + ## Reference Resolution `GuzzleHttp\Psr7\UriResolver` provides methods to resolve a URI reference in the context of a base URI according @@ -737,3 +817,28 @@ Whether two URIs can be considered equivalent. Both URIs are normalized automati `$normalizations` bitmask. The method also accepts relative URI references and returns true when they are equivalent. This of course assumes they will be resolved against the same base URI. If this is not the case, determination of equivalence or difference of relative references does not mean anything. + + +## Version Guidance + +| Version | Status | PHP Version | +|---------|----------------|------------------| +| 1.x | Security fixes | >=5.4,<8.1 | +| 2.x | Latest | ^7.2.5 \|\| ^8.0 | + + +## Security + +If you discover a security vulnerability within this package, please send an email to security@tidelift.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced. Please see [Security Policy](https://github.com/guzzle/psr7/security/policy) for more information. + + +## License + +Guzzle is made available under the MIT License (MIT). Please see [License File](LICENSE) for more information. + + +## For Enterprise + +Available as part of the Tidelift Subscription + +The maintainers of Guzzle and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-guzzlehttp-psr7?utm_source=packagist-guzzlehttp-psr7&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) diff --git a/vendor/guzzlehttp/psr7/composer.json b/vendor/guzzlehttp/psr7/composer.json index b1c5a90b..0e36920d 100644 --- a/vendor/guzzlehttp/psr7/composer.json +++ b/vendor/guzzlehttp/psr7/composer.json @@ -1,39 +1,76 @@ { "name": "guzzlehttp/psr7", - "type": "library", "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": ["request", "response", "message", "stream", "http", "uri", "url"], + "keywords": ["request", "response", "message", "stream", "http", "uri", "url", "psr-7"], "license": "MIT", "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Mรกrk Sรกgi-Kazรกr", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, { "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", "homepage": "https://github.com/Tobion" } ], "require": { "php": ">=5.4.0", - "psr/http-message": "~1.0" + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10", + "ext-zlib": "*" }, "provide": { "psr/http-message-implementation": "1.0" }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, "autoload": { "psr-4": { "GuzzleHttp\\Psr7\\": "src/" }, "files": ["src/functions_include.php"] }, + "autoload-dev": { + "psr-4": { + "GuzzleHttp\\Tests\\Psr7\\": "tests/" + } + }, "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.9-dev" + } + }, + "config": { + "preferred-install": "dist", + "sort-packages": true, + "allow-plugins": { + "bamarni/composer-bin-plugin": true } } } diff --git a/vendor/guzzlehttp/psr7/src/AppendStream.php b/vendor/guzzlehttp/psr7/src/AppendStream.php index 23039fd7..fa9153d7 100644 --- a/vendor/guzzlehttp/psr7/src/AppendStream.php +++ b/vendor/guzzlehttp/psr7/src/AppendStream.php @@ -1,4 +1,5 @@ pos = $this->current = 0; + $this->seekable = true; foreach ($this->streams as $stream) { $stream->close(); @@ -82,14 +85,24 @@ public function close() } /** - * Detaches each attached stream + * Detaches each attached stream. + * + * Returns null as it's not clear which underlying stream resource to return. * * {@inheritdoc} */ public function detach() { - $this->close(); - $this->detached = true; + $this->pos = $this->current = 0; + $this->seekable = true; + + foreach ($this->streams as $stream) { + $stream->detach(); + } + + $this->streams = []; + + return null; } public function tell() diff --git a/vendor/guzzlehttp/psr7/src/BufferStream.php b/vendor/guzzlehttp/psr7/src/BufferStream.php index af4d4c22..783859c1 100644 --- a/vendor/guzzlehttp/psr7/src/BufferStream.php +++ b/vendor/guzzlehttp/psr7/src/BufferStream.php @@ -1,4 +1,5 @@ close(); + + return null; } public function getSize() diff --git a/vendor/guzzlehttp/psr7/src/CachingStream.php b/vendor/guzzlehttp/psr7/src/CachingStream.php index ed68f086..febade9f 100644 --- a/vendor/guzzlehttp/psr7/src/CachingStream.php +++ b/vendor/guzzlehttp/psr7/src/CachingStream.php @@ -1,4 +1,5 @@ remoteStream = $stream; - $this->stream = $target ?: new Stream(fopen('php://temp', 'r+')); + $this->stream = $target ?: new Stream(Utils::tryFopen('php://temp', 'r+')); } public function getSize() { - return max($this->stream->getSize(), $this->remoteStream->getSize()); + $remoteSize = $this->remoteStream->getSize(); + + if (null === $remoteSize) { + return null; + } + + return max($this->stream->getSize(), $remoteSize); } public function rewind() @@ -131,7 +140,7 @@ public function close() private function cacheEntireStream() { $target = new FnStream(['write' => 'strlen']); - copy_to_stream($this, $target); + Utils::copyToStream($this, $target); return $this->tell(); } diff --git a/vendor/guzzlehttp/psr7/src/DroppingStream.php b/vendor/guzzlehttp/psr7/src/DroppingStream.php index 8935c80d..9f7420c4 100644 --- a/vendor/guzzlehttp/psr7/src/DroppingStream.php +++ b/vendor/guzzlehttp/psr7/src/DroppingStream.php @@ -1,4 +1,5 @@ ]+>|[^=]+/', $kvp, $matches)) { + $m = $matches[0]; + if (isset($m[1])) { + $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed); + } else { + $part[] = trim($m[0], $trimmed); + } + } + } + if ($part) { + $params[] = $part; + } + } + + return $params; + } + + /** + * Converts an array of header values that may contain comma separated + * headers into an array of headers with no comma separated values. + * + * @param string|array $header Header to normalize. + * + * @return array Returns the normalized header field values. + */ + public static function normalize($header) + { + if (!is_array($header)) { + return array_map('trim', explode(',', $header)); + } + + $result = []; + foreach ($header as $value) { + foreach ((array) $value as $v) { + if (strpos($v, ',') === false) { + $result[] = $v; + continue; + } + foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $v) as $vv) { + $result[] = trim($vv); + } + } + } + + return $result; + } +} diff --git a/vendor/guzzlehttp/psr7/src/InflateStream.php b/vendor/guzzlehttp/psr7/src/InflateStream.php index 0051d3fe..0cbd2cce 100644 --- a/vendor/guzzlehttp/psr7/src/InflateStream.php +++ b/vendor/guzzlehttp/psr7/src/InflateStream.php @@ -1,4 +1,5 @@ stream = new Stream($resource); + $this->stream = $stream->isSeekable() ? new Stream($resource) : new NoSeekStream(new Stream($resource)); } /** * @param StreamInterface $stream * @param $header + * * @return int */ private function getLengthOfPossibleFilenameHeader(StreamInterface $stream, $header) diff --git a/vendor/guzzlehttp/psr7/src/LazyOpenStream.php b/vendor/guzzlehttp/psr7/src/LazyOpenStream.php index 02cec3af..911e127d 100644 --- a/vendor/guzzlehttp/psr7/src/LazyOpenStream.php +++ b/vendor/guzzlehttp/psr7/src/LazyOpenStream.php @@ -1,4 +1,5 @@ filename, $this->mode)); + return Utils::streamFor(Utils::tryFopen($this->filename, $this->mode)); } } diff --git a/vendor/guzzlehttp/psr7/src/LimitStream.php b/vendor/guzzlehttp/psr7/src/LimitStream.php index 3c13d4f4..1173ec40 100644 --- a/vendor/guzzlehttp/psr7/src/LimitStream.php +++ b/vendor/guzzlehttp/psr7/src/LimitStream.php @@ -1,11 +1,13 @@ getMethod() . ' ' + . $message->getRequestTarget()) + . ' HTTP/' . $message->getProtocolVersion(); + if (!$message->hasHeader('host')) { + $msg .= "\r\nHost: " . $message->getUri()->getHost(); + } + } elseif ($message instanceof ResponseInterface) { + $msg = 'HTTP/' . $message->getProtocolVersion() . ' ' + . $message->getStatusCode() . ' ' + . $message->getReasonPhrase(); + } else { + throw new \InvalidArgumentException('Unknown message type'); + } + + foreach ($message->getHeaders() as $name => $values) { + if (strtolower($name) === 'set-cookie') { + foreach ($values as $value) { + $msg .= "\r\n{$name}: " . $value; + } + } else { + $msg .= "\r\n{$name}: " . implode(', ', $values); + } + } + + return "{$msg}\r\n\r\n" . $message->getBody(); + } + + /** + * Get a short summary of the message body. + * + * Will return `null` if the response is not printable. + * + * @param MessageInterface $message The message to get the body summary + * @param int $truncateAt The maximum allowed size of the summary + * + * @return string|null + */ + public static function bodySummary(MessageInterface $message, $truncateAt = 120) + { + $body = $message->getBody(); + + if (!$body->isSeekable() || !$body->isReadable()) { + return null; + } + + $size = $body->getSize(); + + if ($size === 0) { + return null; + } + + $summary = $body->read($truncateAt); + $body->rewind(); + + if ($size > $truncateAt) { + $summary .= ' (truncated...)'; + } + + // Matches any printable character, including unicode characters: + // letters, marks, numbers, punctuation, spacing, and separators. + if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/u', $summary)) { + return null; + } + + return $summary; + } + + /** + * Attempts to rewind a message body and throws an exception on failure. + * + * The body of the message will only be rewound if a call to `tell()` + * returns a value other than `0`. + * + * @param MessageInterface $message Message to rewind + * + * @throws \RuntimeException + */ + public static function rewindBody(MessageInterface $message) + { + $body = $message->getBody(); + + if ($body->tell()) { + $body->rewind(); + } + } + + /** + * Parses an HTTP message into an associative array. + * + * The array contains the "start-line" key containing the start line of + * the message, "headers" key containing an associative array of header + * array values, and a "body" key containing the body of the message. + * + * @param string $message HTTP request or response to parse. + * + * @return array + */ + public static function parseMessage($message) + { + if (!$message) { + throw new \InvalidArgumentException('Invalid message'); + } + + $message = ltrim($message, "\r\n"); + + $messageParts = preg_split("/\r?\n\r?\n/", $message, 2); + + if ($messageParts === false || count($messageParts) !== 2) { + throw new \InvalidArgumentException('Invalid message: Missing header delimiter'); + } + + list($rawHeaders, $body) = $messageParts; + $rawHeaders .= "\r\n"; // Put back the delimiter we split previously + $headerParts = preg_split("/\r?\n/", $rawHeaders, 2); + + if ($headerParts === false || count($headerParts) !== 2) { + throw new \InvalidArgumentException('Invalid message: Missing status line'); + } + + list($startLine, $rawHeaders) = $headerParts; + + if (preg_match("/(?:^HTTP\/|^[A-Z]+ \S+ HTTP\/)(\d+(?:\.\d+)?)/i", $startLine, $matches) && $matches[1] === '1.0') { + // Header folding is deprecated for HTTP/1.1, but allowed in HTTP/1.0 + $rawHeaders = preg_replace(Rfc7230::HEADER_FOLD_REGEX, ' ', $rawHeaders); + } + + /** @var array[] $headerLines */ + $count = preg_match_all(Rfc7230::HEADER_REGEX, $rawHeaders, $headerLines, PREG_SET_ORDER); + + // If these aren't the same, then one line didn't match and there's an invalid header. + if ($count !== substr_count($rawHeaders, "\n")) { + // Folding is deprecated, see https://tools.ietf.org/html/rfc7230#section-3.2.4 + if (preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) { + throw new \InvalidArgumentException('Invalid header syntax: Obsolete line folding'); + } + + throw new \InvalidArgumentException('Invalid header syntax'); + } + + $headers = []; + + foreach ($headerLines as $headerLine) { + $headers[$headerLine[1]][] = $headerLine[2]; + } + + return [ + 'start-line' => $startLine, + 'headers' => $headers, + 'body' => $body, + ]; + } + + /** + * Constructs a URI for an HTTP request message. + * + * @param string $path Path from the start-line + * @param array $headers Array of headers (each value an array). + * + * @return string + */ + public static function parseRequestUri($path, array $headers) + { + $hostKey = array_filter(array_keys($headers), function ($k) { + return strtolower($k) === 'host'; + }); + + // If no host is found, then a full URI cannot be constructed. + if (!$hostKey) { + return $path; + } + + $host = $headers[reset($hostKey)][0]; + $scheme = substr($host, -4) === ':443' ? 'https' : 'http'; + + return $scheme . '://' . $host . '/' . ltrim($path, '/'); + } + + /** + * Parses a request message string into a request object. + * + * @param string $message Request message string. + * + * @return Request + */ + public static function parseRequest($message) + { + $data = self::parseMessage($message); + $matches = []; + if (!preg_match('/^[\S]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) { + throw new \InvalidArgumentException('Invalid request string'); + } + $parts = explode(' ', $data['start-line'], 3); + $version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1'; + + $request = new Request( + $parts[0], + $matches[1] === '/' ? self::parseRequestUri($parts[1], $data['headers']) : $parts[1], + $data['headers'], + $data['body'], + $version + ); + + return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]); + } + + /** + * Parses a response message string into a response object. + * + * @param string $message Response message string. + * + * @return Response + */ + public static function parseResponse($message) + { + $data = self::parseMessage($message); + // According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space + // between status-code and reason-phrase is required. But browsers accept + // responses without space and reason as well. + if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) { + throw new \InvalidArgumentException('Invalid response string: ' . $data['start-line']); + } + $parts = explode(' ', $data['start-line'], 3); + + return new Response( + (int) $parts[1], + $data['headers'], + $data['body'], + explode('/', $parts[0])[1], + isset($parts[2]) ? $parts[2] : null + ); + } +} diff --git a/vendor/guzzlehttp/psr7/src/MessageTrait.php b/vendor/guzzlehttp/psr7/src/MessageTrait.php index 1e4da649..0ac8663d 100644 --- a/vendor/guzzlehttp/psr7/src/MessageTrait.php +++ b/vendor/guzzlehttp/psr7/src/MessageTrait.php @@ -1,4 +1,5 @@ trimHeaderValues($value); + $this->assertHeader($header); + $value = $this->normalizeHeaderValue($value); $normalized = strtolower($header); $new = clone $this; @@ -85,11 +83,8 @@ public function withHeader($header, $value) public function withAddedHeader($header, $value) { - if (!is_array($value)) { - $value = [$value]; - } - - $value = $this->trimHeaderValues($value); + $this->assertHeader($header); + $value = $this->normalizeHeaderValue($value); $normalized = strtolower($header); $new = clone $this; @@ -123,7 +118,7 @@ public function withoutHeader($header) public function getBody() { if (!$this->stream) { - $this->stream = stream_for(''); + $this->stream = Utils::streamFor(''); } return $this->stream; @@ -144,11 +139,13 @@ private function setHeaders(array $headers) { $this->headerNames = $this->headers = []; foreach ($headers as $header => $value) { - if (!is_array($value)) { - $value = [$value]; + if (is_int($header)) { + // Numeric array keys are converted to int by PHP but having a header name '123' is not forbidden by the spec + // and also allowed in withHeader(). So we need to cast it to string again for the following assertion to pass. + $header = (string) $header; } - - $value = $this->trimHeaderValues($value); + $this->assertHeader($header); + $value = $this->normalizeHeaderValue($value); $normalized = strtolower($header); if (isset($this->headerNames[$normalized])) { $header = $this->headerNames[$normalized]; @@ -160,6 +157,24 @@ private function setHeaders(array $headers) } } + /** + * @param mixed $value + * + * @return string[] + */ + private function normalizeHeaderValue($value) + { + if (!is_array($value)) { + return $this->trimAndValidateHeaderValues([$value]); + } + + if (count($value) === 0) { + throw new \InvalidArgumentException('Header value can not be an empty array.'); + } + + return $this->trimAndValidateHeaderValues($value); + } + /** * Trims whitespace from the header values. * @@ -168,16 +183,88 @@ private function setHeaders(array $headers) * header-field = field-name ":" OWS field-value OWS * OWS = *( SP / HTAB ) * - * @param string[] $values Header values + * @param mixed[] $values Header values * * @return string[] Trimmed header values * * @see https://tools.ietf.org/html/rfc7230#section-3.2.4 */ - private function trimHeaderValues(array $values) + private function trimAndValidateHeaderValues(array $values) { return array_map(function ($value) { - return trim($value, " \t"); - }, $values); + if (!is_scalar($value) && null !== $value) { + throw new \InvalidArgumentException(sprintf( + 'Header value must be scalar or null but %s provided.', + is_object($value) ? get_class($value) : gettype($value) + )); + } + + $trimmed = trim((string) $value, " \t"); + $this->assertValue($trimmed); + + return $trimmed; + }, array_values($values)); + } + + /** + * @see https://tools.ietf.org/html/rfc7230#section-3.2 + * + * @param mixed $header + * + * @return void + */ + private function assertHeader($header) + { + if (!is_string($header)) { + throw new \InvalidArgumentException(sprintf( + 'Header name must be a string but %s provided.', + is_object($header) ? get_class($header) : gettype($header) + )); + } + + if ($header === '') { + throw new \InvalidArgumentException('Header name can not be empty.'); + } + + if (! preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/', $header)) { + throw new \InvalidArgumentException( + sprintf( + '"%s" is not valid header name', + $header + ) + ); + } + } + + /** + * @param string $value + * + * @return void + * + * @see https://tools.ietf.org/html/rfc7230#section-3.2 + * + * field-value = *( field-content / obs-fold ) + * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] + * field-vchar = VCHAR / obs-text + * VCHAR = %x21-7E + * obs-text = %x80-FF + * obs-fold = CRLF 1*( SP / HTAB ) + */ + private function assertValue($value) + { + // The regular expression intentionally does not support the obs-fold production, because as + // per RFC 7230#3.2.4: + // + // A sender MUST NOT generate a message that includes + // line folding (i.e., that has any field-value that contains a match to + // the obs-fold rule) unless the message is intended for packaging + // within the message/http media type. + // + // Clients must not send a request with line folding and a server sending folded headers is + // likely very rare. Line folding is a fairly obscure feature of HTTP/1.1 and thus not accepting + // folding is not likely to break any legitimate use case. + if (! preg_match('/^[\x20\x09\x21-\x7E\x80-\xFF]*$/', $value)) { + throw new \InvalidArgumentException(sprintf('"%s" is not valid header value', $value)); + } } } diff --git a/vendor/guzzlehttp/psr7/src/MimeType.php b/vendor/guzzlehttp/psr7/src/MimeType.php new file mode 100644 index 00000000..205c7b1f --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/MimeType.php @@ -0,0 +1,140 @@ + 'video/3gpp', + '7z' => 'application/x-7z-compressed', + 'aac' => 'audio/x-aac', + 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'asc' => 'text/plain', + 'asf' => 'video/x-ms-asf', + 'atom' => 'application/atom+xml', + 'avi' => 'video/x-msvideo', + 'bmp' => 'image/bmp', + 'bz2' => 'application/x-bzip2', + 'cer' => 'application/pkix-cert', + 'crl' => 'application/pkix-crl', + 'crt' => 'application/x-x509-ca-cert', + 'css' => 'text/css', + 'csv' => 'text/csv', + 'cu' => 'application/cu-seeme', + 'deb' => 'application/x-debian-package', + 'doc' => 'application/msword', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dvi' => 'application/x-dvi', + 'eot' => 'application/vnd.ms-fontobject', + 'eps' => 'application/postscript', + 'epub' => 'application/epub+zip', + 'etx' => 'text/x-setext', + 'flac' => 'audio/flac', + 'flv' => 'video/x-flv', + 'gif' => 'image/gif', + 'gz' => 'application/gzip', + 'htm' => 'text/html', + 'html' => 'text/html', + 'ico' => 'image/x-icon', + 'ics' => 'text/calendar', + 'ini' => 'text/plain', + 'iso' => 'application/x-iso9660-image', + 'jar' => 'application/java-archive', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'js' => 'text/javascript', + 'json' => 'application/json', + 'latex' => 'application/x-latex', + 'log' => 'text/plain', + 'm4a' => 'audio/mp4', + 'm4v' => 'video/mp4', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mov' => 'video/quicktime', + 'mkv' => 'video/x-matroska', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mp4a' => 'audio/mp4', + 'mp4v' => 'video/mp4', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpg4' => 'video/mp4', + 'oga' => 'audio/ogg', + 'ogg' => 'audio/ogg', + 'ogv' => 'video/ogg', + 'ogx' => 'application/ogg', + 'pbm' => 'image/x-portable-bitmap', + 'pdf' => 'application/pdf', + 'pgm' => 'image/x-portable-graymap', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'ppm' => 'image/x-portable-pixmap', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'ps' => 'application/postscript', + 'qt' => 'video/quicktime', + 'rar' => 'application/x-rar-compressed', + 'ras' => 'image/x-cmu-raster', + 'rss' => 'application/rss+xml', + 'rtf' => 'application/rtf', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'svg' => 'image/svg+xml', + 'swf' => 'application/x-shockwave-flash', + 'tar' => 'application/x-tar', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'torrent' => 'application/x-bittorrent', + 'ttf' => 'application/x-font-ttf', + 'txt' => 'text/plain', + 'wav' => 'audio/x-wav', + 'webm' => 'video/webm', + 'webp' => 'image/webp', + 'wma' => 'audio/x-ms-wma', + 'wmv' => 'video/x-ms-wmv', + 'woff' => 'application/x-font-woff', + 'wsdl' => 'application/wsdl+xml', + 'xbm' => 'image/x-xbitmap', + 'xls' => 'application/vnd.ms-excel', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xml' => 'application/xml', + 'xpm' => 'image/x-xpixmap', + 'xwd' => 'image/x-xwindowdump', + 'yaml' => 'text/yaml', + 'yml' => 'text/yaml', + 'zip' => 'application/zip', + ]; + + $extension = strtolower($extension); + + return isset($mimetypes[$extension]) + ? $mimetypes[$extension] + : null; + } +} diff --git a/vendor/guzzlehttp/psr7/src/MultipartStream.php b/vendor/guzzlehttp/psr7/src/MultipartStream.php index c0fd584f..5a6079a8 100644 --- a/vendor/guzzlehttp/psr7/src/MultipartStream.php +++ b/vendor/guzzlehttp/psr7/src/MultipartStream.php @@ -1,4 +1,5 @@ addStream(stream_for("--{$this->boundary}--\r\n")); + $stream->addStream(Utils::streamFor("--{$this->boundary}--\r\n")); return $stream; } @@ -84,7 +87,7 @@ private function addElement(AppendStream $stream, array $element) } } - $element['contents'] = stream_for($element['contents']); + $element['contents'] = Utils::streamFor($element['contents']); if (empty($element['filename'])) { $uri = $element['contents']->getMetadata('uri'); @@ -100,9 +103,9 @@ private function addElement(AppendStream $stream, array $element) isset($element['headers']) ? $element['headers'] : [] ); - $stream->addStream(stream_for($this->getHeaders($headers))); + $stream->addStream(Utils::streamFor($this->getHeaders($headers))); $stream->addStream($body); - $stream->addStream(stream_for("\r\n")); + $stream->addStream(Utils::streamFor("\r\n")); } /** @@ -114,9 +117,11 @@ private function createElement($name, StreamInterface $stream, $filename, array $disposition = $this->getHeader($headers, 'content-disposition'); if (!$disposition) { $headers['Content-Disposition'] = ($filename === '0' || $filename) - ? sprintf('form-data; name="%s"; filename="%s"', + ? sprintf( + 'form-data; name="%s"; filename="%s"', $name, - basename($filename)) + basename($filename) + ) : "form-data; name=\"{$name}\""; } @@ -131,7 +136,7 @@ private function createElement($name, StreamInterface $stream, $filename, array // Set a default Content-Type if one was not supplied $type = $this->getHeader($headers, 'content-type'); if (!$type && ($filename === '0' || $filename)) { - if ($type = mimetype_from_filename($filename)) { + if ($type = MimeType::fromFilename($filename)) { $headers['Content-Type'] = $type; } } diff --git a/vendor/guzzlehttp/psr7/src/NoSeekStream.php b/vendor/guzzlehttp/psr7/src/NoSeekStream.php index 23322180..d66bdde4 100644 --- a/vendor/guzzlehttp/psr7/src/NoSeekStream.php +++ b/vendor/guzzlehttp/psr7/src/NoSeekStream.php @@ -1,10 +1,13 @@ tellPos = false; $this->source = null; + + return null; } public function getSize() diff --git a/vendor/guzzlehttp/psr7/src/Query.php b/vendor/guzzlehttp/psr7/src/Query.php new file mode 100644 index 00000000..5a7cc035 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/Query.php @@ -0,0 +1,113 @@ + '1', 'foo[b]' => '2'])`. + * + * @param string $str Query string to parse + * @param int|bool $urlEncoding How the query string is encoded + * + * @return array + */ + public static function parse($str, $urlEncoding = true) + { + $result = []; + + if ($str === '') { + return $result; + } + + if ($urlEncoding === true) { + $decoder = function ($value) { + return rawurldecode(str_replace('+', ' ', $value)); + }; + } elseif ($urlEncoding === PHP_QUERY_RFC3986) { + $decoder = 'rawurldecode'; + } elseif ($urlEncoding === PHP_QUERY_RFC1738) { + $decoder = 'urldecode'; + } else { + $decoder = function ($str) { + return $str; + }; + } + + foreach (explode('&', $str) as $kvp) { + $parts = explode('=', $kvp, 2); + $key = $decoder($parts[0]); + $value = isset($parts[1]) ? $decoder($parts[1]) : null; + if (!isset($result[$key])) { + $result[$key] = $value; + } else { + if (!is_array($result[$key])) { + $result[$key] = [$result[$key]]; + } + $result[$key][] = $value; + } + } + + return $result; + } + + /** + * Build a query string from an array of key value pairs. + * + * This function can use the return value of `parse()` to build a query + * string. This function does not modify the provided keys when an array is + * encountered (like `http_build_query()` would). + * + * @param array $params Query string parameters. + * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986 + * to encode using RFC3986, or PHP_QUERY_RFC1738 + * to encode using RFC1738. + * + * @return string + */ + public static function build(array $params, $encoding = PHP_QUERY_RFC3986) + { + if (!$params) { + return ''; + } + + if ($encoding === false) { + $encoder = function ($str) { + return $str; + }; + } elseif ($encoding === PHP_QUERY_RFC3986) { + $encoder = 'rawurlencode'; + } elseif ($encoding === PHP_QUERY_RFC1738) { + $encoder = 'urlencode'; + } else { + throw new \InvalidArgumentException('Invalid type'); + } + + $qs = ''; + foreach ($params as $k => $v) { + $k = $encoder($k); + if (!is_array($v)) { + $qs .= $k; + if ($v !== null) { + $qs .= '=' . $encoder($v); + } + $qs .= '&'; + } else { + foreach ($v as $vv) { + $qs .= $k; + if ($vv !== null) { + $qs .= '=' . $encoder($vv); + } + $qs .= '&'; + } + } + } + + return $qs ? (string) substr($qs, 0, -1) : ''; + } +} diff --git a/vendor/guzzlehttp/psr7/src/Request.php b/vendor/guzzlehttp/psr7/src/Request.php index 08285484..c1cdaebf 100644 --- a/vendor/guzzlehttp/psr7/src/Request.php +++ b/vendor/guzzlehttp/psr7/src/Request.php @@ -1,4 +1,5 @@ assertMethod($method); if (!($uri instanceof UriInterface)) { $uri = new Uri($uri); } @@ -45,12 +47,12 @@ public function __construct( $this->setHeaders($headers); $this->protocol = $version; - if (!$this->hasHeader('Host')) { + if (!isset($this->headerNames['host'])) { $this->updateHostFromUri(); } if ($body !== '' && $body !== null) { - $this->stream = stream_for($body); + $this->stream = Utils::streamFor($body); } } @@ -91,6 +93,7 @@ public function getMethod() public function withMethod($method) { + $this->assertMethod($method); $new = clone $this; $new->method = strtoupper($method); return $new; @@ -110,7 +113,7 @@ public function withUri(UriInterface $uri, $preserveHost = false) $new = clone $this; $new->uri = $uri; - if (!$preserveHost) { + if (!$preserveHost || !isset($this->headerNames['host'])) { $new->updateHostFromUri(); } @@ -139,4 +142,11 @@ private function updateHostFromUri() // See: http://tools.ietf.org/html/rfc7230#section-5.4 $this->headers = [$header => [$host]] + $this->headers; } + + private function assertMethod($method) + { + if (!is_string($method) || $method === '') { + throw new \InvalidArgumentException('Method must be a non-empty string.'); + } + } } diff --git a/vendor/guzzlehttp/psr7/src/Response.php b/vendor/guzzlehttp/psr7/src/Response.php index 2830c6c9..8c01a0f5 100644 --- a/vendor/guzzlehttp/psr7/src/Response.php +++ b/vendor/guzzlehttp/psr7/src/Response.php @@ -1,4 +1,5 @@ statusCode = (int) $status; + $this->assertStatusCodeIsInteger($status); + $status = (int) $status; + $this->assertStatusCodeRange($status); + + $this->statusCode = $status; if ($body !== '' && $body !== null) { - $this->stream = stream_for($body); + $this->stream = Utils::streamFor($body); } $this->setHeaders($headers); @@ -121,12 +126,30 @@ public function getReasonPhrase() public function withStatus($code, $reasonPhrase = '') { + $this->assertStatusCodeIsInteger($code); + $code = (int) $code; + $this->assertStatusCodeRange($code); + $new = clone $this; - $new->statusCode = (int) $code; + $new->statusCode = $code; if ($reasonPhrase == '' && isset(self::$phrases[$new->statusCode])) { $reasonPhrase = self::$phrases[$new->statusCode]; } - $new->reasonPhrase = $reasonPhrase; + $new->reasonPhrase = (string) $reasonPhrase; return $new; } + + private function assertStatusCodeIsInteger($statusCode) + { + if (filter_var($statusCode, FILTER_VALIDATE_INT) === false) { + throw new \InvalidArgumentException('Status code must be an integer value.'); + } + } + + private function assertStatusCodeRange($statusCode) + { + if ($statusCode < 100 || $statusCode >= 600) { + throw new \InvalidArgumentException('Status code must be an integer value between 1xx and 5xx.'); + } + } } diff --git a/vendor/guzzlehttp/psr7/src/Rfc7230.php b/vendor/guzzlehttp/psr7/src/Rfc7230.php new file mode 100644 index 00000000..51b571f2 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/Rfc7230.php @@ -0,0 +1,19 @@ +@,;:\\\"/[\]?={}\x01-\x20\x7F]++):[ \t]*+((?:[ \t]*+[\x21-\x7E\x80-\xFF]++)*+)[ \t]*+\r?\n)m"; + const HEADER_FOLD_REGEX = "(\r?\n[ \t]++)"; +} diff --git a/vendor/guzzlehttp/psr7/src/ServerRequest.php b/vendor/guzzlehttp/psr7/src/ServerRequest.php index 575aab84..e6d26f5f 100644 --- a/vendor/guzzlehttp/psr7/src/ServerRequest.php +++ b/vendor/guzzlehttp/psr7/src/ServerRequest.php @@ -4,9 +4,9 @@ use InvalidArgumentException; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Message\UriInterface; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UploadedFileInterface; +use Psr\Http\Message\UriInterface; /** * Server-side HTTP request @@ -35,7 +35,7 @@ class ServerRequest extends Request implements ServerRequestInterface private $cookieParams = []; /** - * @var null|array|object + * @var array|object|null */ private $parsedBody; @@ -58,7 +58,7 @@ class ServerRequest extends Request implements ServerRequestInterface * @param string $method HTTP method * @param string|UriInterface $uri URI * @param array $headers Request headers - * @param string|null|resource|StreamInterface $body Request body + * @param string|resource|StreamInterface|null $body Request body * @param string $version Protocol version * @param array $serverParams Typically the $_SERVER superglobal */ @@ -79,8 +79,10 @@ public function __construct( * Return an UploadedFile instance array. * * @param array $files A array which respect $_FILES structure - * @throws InvalidArgumentException for unrecognized values + * * @return array + * + * @throws InvalidArgumentException for unrecognized values */ public static function normalizeFiles(array $files) { @@ -109,6 +111,7 @@ public static function normalizeFiles(array $files) * delegate to normalizeNestedFileSpec() and return that return value. * * @param array $value $_FILES struct + * * @return array|UploadedFileInterface */ private static function createUploadedFileFromSpec(array $value) @@ -133,6 +136,7 @@ private static function createUploadedFileFromSpec(array $value) * UploadedFileInterface instances. * * @param array $files + * * @return UploadedFileInterface[] */ private static function normalizeNestedFileSpec(array $files = []) @@ -166,9 +170,9 @@ private static function normalizeNestedFileSpec(array $files = []) public static function fromGlobals() { $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET'; - $headers = function_exists('getallheaders') ? getallheaders() : []; + $headers = getallheaders(); $uri = self::getUriFromGlobals(); - $body = new LazyOpenStream('php://input', 'r+'); + $body = new CachingStream(new LazyOpenStream('php://input', 'r+')); $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1'; $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER); @@ -180,23 +184,41 @@ public static function fromGlobals() ->withUploadedFiles(self::normalizeFiles($_FILES)); } + private static function extractHostAndPortFromAuthority($authority) + { + $uri = 'http://' . $authority; + $parts = parse_url($uri); + if (false === $parts) { + return [null, null]; + } + + $host = isset($parts['host']) ? $parts['host'] : null; + $port = isset($parts['port']) ? $parts['port'] : null; + + return [$host, $port]; + } + /** * Get a Uri populated with values from $_SERVER. * * @return UriInterface */ - public static function getUriFromGlobals() { + public static function getUriFromGlobals() + { $uri = new Uri(''); $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http'); $hasPort = false; if (isset($_SERVER['HTTP_HOST'])) { - $hostHeaderParts = explode(':', $_SERVER['HTTP_HOST']); - $uri = $uri->withHost($hostHeaderParts[0]); - if (isset($hostHeaderParts[1])) { + list($host, $port) = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']); + if ($host !== null) { + $uri = $uri->withHost($host); + } + + if ($port !== null) { $hasPort = true; - $uri = $uri->withPort($hostHeaderParts[1]); + $uri = $uri->withPort($port); } } elseif (isset($_SERVER['SERVER_NAME'])) { $uri = $uri->withHost($_SERVER['SERVER_NAME']); @@ -210,7 +232,7 @@ public static function getUriFromGlobals() { $hasQuery = false; if (isset($_SERVER['REQUEST_URI'])) { - $requestUriParts = explode('?', $_SERVER['REQUEST_URI']); + $requestUriParts = explode('?', $_SERVER['REQUEST_URI'], 2); $uri = $uri->withPath($requestUriParts[0]); if (isset($requestUriParts[1])) { $hasQuery = true; @@ -225,7 +247,6 @@ public static function getUriFromGlobals() { return $uri; } - /** * {@inheritdoc} */ diff --git a/vendor/guzzlehttp/psr7/src/Stream.php b/vendor/guzzlehttp/psr7/src/Stream.php index e3366287..3865d6d6 100644 --- a/vendor/guzzlehttp/psr7/src/Stream.php +++ b/vendor/guzzlehttp/psr7/src/Stream.php @@ -1,4 +1,5 @@ [ - 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true, - 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, - 'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true, - 'x+t' => true, 'c+t' => true, 'a+' => true - ], - 'write' => [ - 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true, - 'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true, - 'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true, - 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true - ] - ]; - /** * This constructor accepts an associative array of options. * @@ -65,20 +61,11 @@ public function __construct($stream, $options = []) $this->stream = $stream; $meta = stream_get_meta_data($this->stream); $this->seekable = $meta['seekable']; - $this->readable = isset(self::$readWriteHash['read'][$meta['mode']]); - $this->writable = isset(self::$readWriteHash['write'][$meta['mode']]); + $this->readable = (bool)preg_match(self::READABLE_MODES, $meta['mode']); + $this->writable = (bool)preg_match(self::WRITABLE_MODES, $meta['mode']); $this->uri = $this->getMetadata('uri'); } - public function __get($name) - { - if ($name == 'stream') { - throw new \RuntimeException('The stream is detached'); - } - - throw new \BadMethodCallException('No value for ' . $name); - } - /** * Closes the stream when the destructed */ @@ -90,8 +77,10 @@ public function __destruct() public function __toString() { try { - $this->seek(0); - return (string) stream_get_contents($this->stream); + if ($this->isSeekable()) { + $this->seek(0); + } + return $this->getContents(); } catch (\Exception $e) { return ''; } @@ -99,6 +88,10 @@ public function __toString() public function getContents() { + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + $contents = stream_get_contents($this->stream); if ($contents === false) { @@ -173,11 +166,19 @@ public function isSeekable() public function eof() { - return !$this->stream || feof($this->stream); + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + + return feof($this->stream); } public function tell() { + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + $result = ftell($this->stream); if ($result === false) { @@ -194,9 +195,15 @@ public function rewind() public function seek($offset, $whence = SEEK_SET) { + $whence = (int) $whence; + + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } if (!$this->seekable) { throw new \RuntimeException('Stream is not seekable'); - } elseif (fseek($this->stream, $offset, $whence) === -1) { + } + if (fseek($this->stream, $offset, $whence) === -1) { throw new \RuntimeException('Unable to seek to stream position ' . $offset . ' with whence ' . var_export($whence, true)); } @@ -204,6 +211,9 @@ public function seek($offset, $whence = SEEK_SET) public function read($length) { + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } if (!$this->readable) { throw new \RuntimeException('Cannot read from non-readable stream'); } @@ -225,6 +235,9 @@ public function read($length) public function write($string) { + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } if (!$this->writable) { throw new \RuntimeException('Cannot write to a non-writable stream'); } diff --git a/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php b/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php index daec6f52..5025dd67 100644 --- a/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php +++ b/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php @@ -1,10 +1,12 @@ ['stream' => $stream] - ])); + ]); } /** @@ -94,12 +110,21 @@ public function stream_seek($offset, $whence) return true; } + public function stream_cast($cast_as) + { + $stream = clone($this->stream); + + return $stream->detach(); + } + public function stream_stat() { static $modeMap = [ 'r' => 33060, + 'rb' => 33060, 'r+' => 33206, - 'w' => 33188 + 'w' => 33188, + 'wb' => 33188 ]; return [ @@ -118,4 +143,23 @@ public function stream_stat() 'blocks' => 0 ]; } + + public function url_stat($path, $flags) + { + return [ + 'dev' => 0, + 'ino' => 0, + 'mode' => 0, + 'nlink' => 0, + 'uid' => 0, + 'gid' => 0, + 'rdev' => 0, + 'size' => 0, + 'atime' => 0, + 'mtime' => 0, + 'ctime' => 0, + 'blksize' => 0, + 'blocks' => 0 + ]; + } } diff --git a/vendor/guzzlehttp/psr7/src/UploadedFile.php b/vendor/guzzlehttp/psr7/src/UploadedFile.php index e62bd5c8..bf342c4d 100644 --- a/vendor/guzzlehttp/psr7/src/UploadedFile.php +++ b/vendor/guzzlehttp/psr7/src/UploadedFile.php @@ -1,4 +1,5 @@ file, $targetPath) : move_uploaded_file($this->file, $targetPath); } else { - copy_to_stream( + Utils::copyToStream( $this->getStream(), new LazyOpenStream($targetPath, 'w') ); @@ -288,6 +299,7 @@ public function getSize() * {@inheritdoc} * * @see http://php.net/manual/en/features.file-upload.errors.php + * * @return int One of PHP's UPLOAD_ERR_XXX constants. */ public function getError() @@ -299,7 +311,7 @@ public function getError() * {@inheritdoc} * * @return string|null The filename sent by the client or null if none - * was provided. + * was provided. */ public function getClientFilename() { diff --git a/vendor/guzzlehttp/psr7/src/Uri.php b/vendor/guzzlehttp/psr7/src/Uri.php index f46c1db9..0f9f020d 100644 --- a/vendor/guzzlehttp/psr7/src/Uri.php +++ b/vendor/guzzlehttp/psr7/src/Uri.php @@ -1,4 +1,5 @@ getQuery(); - if ($current === '') { - return $uri; - } - - $decodedKey = rawurldecode($key); - $result = array_filter(explode('&', $current), function ($part) use ($decodedKey) { - return rawurldecode(explode('=', $part)[0]) !== $decodedKey; - }); + $result = self::getFilteredQueryString($uri, [$key]); return $uri->withQuery(implode('&', $result)); } @@ -331,26 +372,29 @@ public static function withoutQueryValue(UriInterface $uri, $key) */ public static function withQueryValue(UriInterface $uri, $key, $value) { - $current = $uri->getQuery(); + $result = self::getFilteredQueryString($uri, [$key]); - if ($current === '') { - $result = []; - } else { - $decodedKey = rawurldecode($key); - $result = array_filter(explode('&', $current), function ($part) use ($decodedKey) { - return rawurldecode(explode('=', $part)[0]) !== $decodedKey; - }); - } + $result[] = self::generateQueryString($key, $value); - // Query string separators ("=", "&") within the key or value need to be encoded - // (while preventing double-encoding) before setting the query string. All other - // chars that need percent-encoding will be encoded by withQuery(). - $key = strtr($key, self::$replaceQuery); + return $uri->withQuery(implode('&', $result)); + } - if ($value !== null) { - $result[] = $key . '=' . strtr($value, self::$replaceQuery); - } else { - $result[] = $key; + /** + * Creates a new URI with multiple specific query string values. + * + * It has the same behavior as withQueryValue() but for an associative array of key => value. + * + * @param UriInterface $uri URI to use as a base. + * @param array $keyValueArray Associative array of key and values + * + * @return UriInterface + */ + public static function withQueryValues(UriInterface $uri, array $keyValueArray) + { + $result = self::getFilteredQueryString($uri, array_keys($keyValueArray)); + + foreach ($keyValueArray as $key => $value) { + $result[] = self::generateQueryString($key, $value); } return $uri->withQuery(implode('&', $result)); @@ -362,6 +406,7 @@ public static function withQueryValue(UriInterface $uri, $key, $value) * @param array $parts * * @return UriInterface + * * @link http://php.net/manual/en/function.parse-url.php * * @throws \InvalidArgumentException If the components do not form a valid URI. @@ -442,9 +487,9 @@ public function withScheme($scheme) public function withUserInfo($user, $password = null) { - $info = $user; - if ($password != '') { - $info .= ':' . $password; + $info = $this->filterUserInfoComponent($user); + if ($password !== null) { + $info .= ':' . $this->filterUserInfoComponent($password); } if ($this->userInfo === $info) { @@ -542,7 +587,9 @@ private function applyParts(array $parts) $this->scheme = isset($parts['scheme']) ? $this->filterScheme($parts['scheme']) : ''; - $this->userInfo = isset($parts['user']) ? $parts['user'] : ''; + $this->userInfo = isset($parts['user']) + ? $this->filterUserInfoComponent($parts['user']) + : ''; $this->host = isset($parts['host']) ? $this->filterHost($parts['host']) : ''; @@ -559,7 +606,7 @@ private function applyParts(array $parts) ? $this->filterQueryAndFragment($parts['fragment']) : ''; if (isset($parts['pass'])) { - $this->userInfo .= ':' . $parts['pass']; + $this->userInfo .= ':' . $this->filterUserInfoComponent($parts['pass']); } $this->removeDefaultPort(); @@ -578,7 +625,27 @@ private function filterScheme($scheme) throw new \InvalidArgumentException('Scheme must be a string'); } - return strtolower($scheme); + return \strtr($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); + } + + /** + * @param string $component + * + * @return string + * + * @throws \InvalidArgumentException If the user info is invalid. + */ + private function filterUserInfoComponent($component) + { + if (!is_string($component)) { + throw new \InvalidArgumentException('User info must be a string'); + } + + return preg_replace_callback( + '/(?:[^%' . self::$charUnreserved . self::$charSubDelims . ']+|%(?![A-Fa-f0-9]{2}))/', + [$this, 'rawurlencodeMatchZero'], + $component + ); } /** @@ -594,7 +661,7 @@ private function filterHost($host) throw new \InvalidArgumentException('Host must be a string'); } - return strtolower($host); + return \strtr($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); } /** @@ -611,15 +678,56 @@ private function filterPort($port) } $port = (int) $port; - if (1 > $port || 0xffff < $port) { + if (0 > $port || 0xffff < $port) { throw new \InvalidArgumentException( - sprintf('Invalid port: %d. Must be between 1 and 65535', $port) + sprintf('Invalid port: %d. Must be between 0 and 65535', $port) ); } return $port; } + /** + * @param UriInterface $uri + * @param array $keys + * + * @return array + */ + private static function getFilteredQueryString(UriInterface $uri, array $keys) + { + $current = $uri->getQuery(); + + if ($current === '') { + return []; + } + + $decodedKeys = array_map('rawurldecode', $keys); + + return array_filter(explode('&', $current), function ($part) use ($decodedKeys) { + return !in_array(rawurldecode(explode('=', $part)[0]), $decodedKeys, true); + }); + } + + /** + * @param string $key + * @param string|null $value + * + * @return string + */ + private static function generateQueryString($key, $value) + { + // Query string separators ("=", "&") within the key or value need to be encoded + // (while preventing double-encoding) before setting the query string. All other + // chars that need percent-encoding will be encoded by withQuery(). + $queryString = strtr($key, self::$replaceQuery); + + if ($value !== null) { + $queryString .= '=' . strtr($value, self::$replaceQuery); + } + + return $queryString; + } + private function removeDefaultPort() { if ($this->port !== null && self::isDefaultPort($this)) { @@ -695,7 +803,7 @@ private function validateState() 'by adding a leading slash to the path is deprecated since version 1.4 and will throw an exception instead.', E_USER_DEPRECATED ); - $this->path = '/'. $this->path; + $this->path = '/' . $this->path; //throw new \InvalidArgumentException('The path of a URI with an authority must start with a slash "/" or be empty'); } } diff --git a/vendor/guzzlehttp/psr7/src/UriComparator.php b/vendor/guzzlehttp/psr7/src/UriComparator.php new file mode 100644 index 00000000..ccf51ffb --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/UriComparator.php @@ -0,0 +1,55 @@ +getHost(), $modified->getHost()) !== 0) { + return true; + } + + if ($original->getScheme() !== $modified->getScheme()) { + return true; + } + + if (self::computePort($original) !== self::computePort($modified)) { + return true; + } + + return false; + } + + /** + * @return int + */ + private static function computePort(UriInterface $uri) + { + $port = $uri->getPort(); + + if (null !== $port) { + return $port; + } + + return 'https' === $uri->getScheme() ? 443 : 80; + } + + private function __construct() + { + // cannot be instantiated + } +} diff --git a/vendor/guzzlehttp/psr7/src/UriNormalizer.php b/vendor/guzzlehttp/psr7/src/UriNormalizer.php index 384c29e5..81419ead 100644 --- a/vendor/guzzlehttp/psr7/src/UriNormalizer.php +++ b/vendor/guzzlehttp/psr7/src/UriNormalizer.php @@ -1,4 +1,5 @@ $keys + * + * @return array + */ + public static function caselessRemove($keys, array $data) + { + $result = []; + + foreach ($keys as &$key) { + $key = strtolower($key); + } + + foreach ($data as $k => $v) { + if (!in_array(strtolower($k), $keys)) { + $result[$k] = $v; + } + } + + return $result; + } + + /** + * Copy the contents of a stream into another stream until the given number + * of bytes have been read. + * + * @param StreamInterface $source Stream to read from + * @param StreamInterface $dest Stream to write to + * @param int $maxLen Maximum number of bytes to read. Pass -1 + * to read the entire stream. + * + * @throws \RuntimeException on error. + */ + public static function copyToStream(StreamInterface $source, StreamInterface $dest, $maxLen = -1) + { + $bufferSize = 8192; + + if ($maxLen === -1) { + while (!$source->eof()) { + if (!$dest->write($source->read($bufferSize))) { + break; + } + } + } else { + $remaining = $maxLen; + while ($remaining > 0 && !$source->eof()) { + $buf = $source->read(min($bufferSize, $remaining)); + $len = strlen($buf); + if (!$len) { + break; + } + $remaining -= $len; + $dest->write($buf); + } + } + } + + /** + * Copy the contents of a stream into a string until the given number of + * bytes have been read. + * + * @param StreamInterface $stream Stream to read + * @param int $maxLen Maximum number of bytes to read. Pass -1 + * to read the entire stream. + * + * @return string + * + * @throws \RuntimeException on error. + */ + public static function copyToString(StreamInterface $stream, $maxLen = -1) + { + $buffer = ''; + + if ($maxLen === -1) { + while (!$stream->eof()) { + $buf = $stream->read(1048576); + // Using a loose equality here to match on '' and false. + if ($buf == null) { + break; + } + $buffer .= $buf; + } + return $buffer; + } + + $len = 0; + while (!$stream->eof() && $len < $maxLen) { + $buf = $stream->read($maxLen - $len); + // Using a loose equality here to match on '' and false. + if ($buf == null) { + break; + } + $buffer .= $buf; + $len = strlen($buffer); + } + + return $buffer; + } + + /** + * Calculate a hash of a stream. + * + * This method reads the entire stream to calculate a rolling hash, based + * on PHP's `hash_init` functions. + * + * @param StreamInterface $stream Stream to calculate the hash for + * @param string $algo Hash algorithm (e.g. md5, crc32, etc) + * @param bool $rawOutput Whether or not to use raw output + * + * @return string Returns the hash of the stream + * + * @throws \RuntimeException on error. + */ + public static function hash(StreamInterface $stream, $algo, $rawOutput = false) + { + $pos = $stream->tell(); + + if ($pos > 0) { + $stream->rewind(); + } + + $ctx = hash_init($algo); + while (!$stream->eof()) { + hash_update($ctx, $stream->read(1048576)); + } + + $out = hash_final($ctx, (bool) $rawOutput); + $stream->seek($pos); + + return $out; + } + + /** + * Clone and modify a request with the given changes. + * + * This method is useful for reducing the number of clones needed to mutate + * a message. + * + * The changes can be one of: + * - method: (string) Changes the HTTP method. + * - set_headers: (array) Sets the given headers. + * - remove_headers: (array) Remove the given headers. + * - body: (mixed) Sets the given body. + * - uri: (UriInterface) Set the URI. + * - query: (string) Set the query string value of the URI. + * - version: (string) Set the protocol version. + * + * @param RequestInterface $request Request to clone and modify. + * @param array $changes Changes to apply. + * + * @return RequestInterface + */ + public static function modifyRequest(RequestInterface $request, array $changes) + { + if (!$changes) { + return $request; + } + + $headers = $request->getHeaders(); + + if (!isset($changes['uri'])) { + $uri = $request->getUri(); + } else { + // Remove the host header if one is on the URI + if ($host = $changes['uri']->getHost()) { + $changes['set_headers']['Host'] = $host; + + if ($port = $changes['uri']->getPort()) { + $standardPorts = ['http' => 80, 'https' => 443]; + $scheme = $changes['uri']->getScheme(); + if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) { + $changes['set_headers']['Host'] .= ':' . $port; + } + } + } + $uri = $changes['uri']; + } + + if (!empty($changes['remove_headers'])) { + $headers = self::caselessRemove($changes['remove_headers'], $headers); + } + + if (!empty($changes['set_headers'])) { + $headers = self::caselessRemove(array_keys($changes['set_headers']), $headers); + $headers = $changes['set_headers'] + $headers; + } + + if (isset($changes['query'])) { + $uri = $uri->withQuery($changes['query']); + } + + if ($request instanceof ServerRequestInterface) { + $new = (new ServerRequest( + isset($changes['method']) ? $changes['method'] : $request->getMethod(), + $uri, + $headers, + isset($changes['body']) ? $changes['body'] : $request->getBody(), + isset($changes['version']) + ? $changes['version'] + : $request->getProtocolVersion(), + $request->getServerParams() + )) + ->withParsedBody($request->getParsedBody()) + ->withQueryParams($request->getQueryParams()) + ->withCookieParams($request->getCookieParams()) + ->withUploadedFiles($request->getUploadedFiles()); + + foreach ($request->getAttributes() as $key => $value) { + $new = $new->withAttribute($key, $value); + } + + return $new; + } + + return new Request( + isset($changes['method']) ? $changes['method'] : $request->getMethod(), + $uri, + $headers, + isset($changes['body']) ? $changes['body'] : $request->getBody(), + isset($changes['version']) + ? $changes['version'] + : $request->getProtocolVersion() + ); + } + + /** + * Read a line from the stream up to the maximum allowed buffer length. + * + * @param StreamInterface $stream Stream to read from + * @param int|null $maxLength Maximum buffer length + * + * @return string + */ + public static function readLine(StreamInterface $stream, $maxLength = null) + { + $buffer = ''; + $size = 0; + + while (!$stream->eof()) { + // Using a loose equality here to match on '' and false. + if (null == ($byte = $stream->read(1))) { + return $buffer; + } + $buffer .= $byte; + // Break when a new line is found or the max length - 1 is reached + if ($byte === "\n" || ++$size === $maxLength - 1) { + break; + } + } + + return $buffer; + } + + /** + * Create a new stream based on the input type. + * + * Options is an associative array that can contain the following keys: + * - metadata: Array of custom metadata. + * - size: Size of the stream. + * + * This method accepts the following `$resource` types: + * - `Psr\Http\Message\StreamInterface`: Returns the value as-is. + * - `string`: Creates a stream object that uses the given string as the contents. + * - `resource`: Creates a stream object that wraps the given PHP stream resource. + * - `Iterator`: If the provided value implements `Iterator`, then a read-only + * stream object will be created that wraps the given iterable. Each time the + * stream is read from, data from the iterator will fill a buffer and will be + * continuously called until the buffer is equal to the requested read size. + * Subsequent read calls will first read from the buffer and then call `next` + * on the underlying iterator until it is exhausted. + * - `object` with `__toString()`: If the object has the `__toString()` method, + * the object will be cast to a string and then a stream will be returned that + * uses the string value. + * - `NULL`: When `null` is passed, an empty stream object is returned. + * - `callable` When a callable is passed, a read-only stream object will be + * created that invokes the given callable. The callable is invoked with the + * number of suggested bytes to read. The callable can return any number of + * bytes, but MUST return `false` when there is no more data to return. The + * stream object that wraps the callable will invoke the callable until the + * number of requested bytes are available. Any additional bytes will be + * buffered and used in subsequent reads. + * + * @param resource|string|int|float|bool|StreamInterface|callable|\Iterator|null $resource Entity body data + * @param array $options Additional options + * + * @return StreamInterface + * + * @throws \InvalidArgumentException if the $resource arg is not valid. + */ + public static function streamFor($resource = '', array $options = []) + { + if (is_scalar($resource)) { + $stream = self::tryFopen('php://temp', 'r+'); + if ($resource !== '') { + fwrite($stream, $resource); + fseek($stream, 0); + } + return new Stream($stream, $options); + } + + switch (gettype($resource)) { + case 'resource': + /* + * The 'php://input' is a special stream with quirks and inconsistencies. + * We avoid using that stream by reading it into php://temp + */ + $metaData = \stream_get_meta_data($resource); + if (isset($metaData['uri']) && $metaData['uri'] === 'php://input') { + $stream = self::tryFopen('php://temp', 'w+'); + fwrite($stream, stream_get_contents($resource)); + fseek($stream, 0); + $resource = $stream; + } + return new Stream($resource, $options); + case 'object': + if ($resource instanceof StreamInterface) { + return $resource; + } elseif ($resource instanceof \Iterator) { + return new PumpStream(function () use ($resource) { + if (!$resource->valid()) { + return false; + } + $result = $resource->current(); + $resource->next(); + return $result; + }, $options); + } elseif (method_exists($resource, '__toString')) { + return Utils::streamFor((string) $resource, $options); + } + break; + case 'NULL': + return new Stream(self::tryFopen('php://temp', 'r+'), $options); + } + + if (is_callable($resource)) { + return new PumpStream($resource, $options); + } + + throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource)); + } + + /** + * Safely opens a PHP stream resource using a filename. + * + * When fopen fails, PHP normally raises a warning. This function adds an + * error handler that checks for errors and throws an exception instead. + * + * @param string $filename File to open + * @param string $mode Mode used to open the file + * + * @return resource + * + * @throws \RuntimeException if the file cannot be opened + */ + public static function tryFopen($filename, $mode) + { + $ex = null; + set_error_handler(function () use ($filename, $mode, &$ex) { + $ex = new \RuntimeException(sprintf( + 'Unable to open "%s" using mode "%s": %s', + $filename, + $mode, + func_get_args()[1] + )); + + return true; + }); + + try { + $handle = fopen($filename, $mode); + } catch (\Throwable $e) { + $ex = new \RuntimeException(sprintf( + 'Unable to open "%s" using mode "%s": %s', + $filename, + $mode, + $e->getMessage() + ), 0, $e); + } + + restore_error_handler(); + + if ($ex) { + /** @var $ex \RuntimeException */ + throw $ex; + } + + return $handle; + } + + /** + * Returns a UriInterface for the given value. + * + * This function accepts a string or UriInterface and returns a + * UriInterface for the given value. If the value is already a + * UriInterface, it is returned as-is. + * + * @param string|UriInterface $uri + * + * @return UriInterface + * + * @throws \InvalidArgumentException + */ + public static function uriFor($uri) + { + if ($uri instanceof UriInterface) { + return $uri; + } + + if (is_string($uri)) { + return new Uri($uri); + } + + throw new \InvalidArgumentException('URI must be a string or UriInterface'); + } +} diff --git a/vendor/guzzlehttp/psr7/src/functions.php b/vendor/guzzlehttp/psr7/src/functions.php index e40348d6..b0901fad 100644 --- a/vendor/guzzlehttp/psr7/src/functions.php +++ b/vendor/guzzlehttp/psr7/src/functions.php @@ -1,10 +1,9 @@ getMethod() . ' ' - . $message->getRequestTarget()) - . ' HTTP/' . $message->getProtocolVersion(); - if (!$message->hasHeader('host')) { - $msg .= "\r\nHost: " . $message->getUri()->getHost(); - } - } elseif ($message instanceof ResponseInterface) { - $msg = 'HTTP/' . $message->getProtocolVersion() . ' ' - . $message->getStatusCode() . ' ' - . $message->getReasonPhrase(); - } else { - throw new \InvalidArgumentException('Unknown message type'); - } - - foreach ($message->getHeaders() as $name => $values) { - $msg .= "\r\n{$name}: " . implode(', ', $values); - } - - return "{$msg}\r\n\r\n" . $message->getBody(); + return Message::toString($message); } /** * Returns a UriInterface for the given value. * - * This function accepts a string or {@see Psr\Http\Message\UriInterface} and - * returns a UriInterface for the given value. If the value is already a - * `UriInterface`, it is returned as-is. + * This function accepts a string or UriInterface and returns a + * UriInterface for the given value. If the value is already a + * UriInterface, it is returned as-is. * * @param string|UriInterface $uri * * @return UriInterface + * * @throws \InvalidArgumentException + * + * @deprecated uri_for will be removed in guzzlehttp/psr7:2.0. Use Utils::uriFor instead. */ function uri_for($uri) { - if ($uri instanceof UriInterface) { - return $uri; - } elseif (is_string($uri)) { - return new Uri($uri); - } - - throw new \InvalidArgumentException('URI must be a string or UriInterface'); + return Utils::uriFor($uri); } /** @@ -69,86 +48,57 @@ function uri_for($uri) * - metadata: Array of custom metadata. * - size: Size of the stream. * - * @param resource|string|null|int|float|bool|StreamInterface|callable $resource Entity body data - * @param array $options Additional options + * This method accepts the following `$resource` types: + * - `Psr\Http\Message\StreamInterface`: Returns the value as-is. + * - `string`: Creates a stream object that uses the given string as the contents. + * - `resource`: Creates a stream object that wraps the given PHP stream resource. + * - `Iterator`: If the provided value implements `Iterator`, then a read-only + * stream object will be created that wraps the given iterable. Each time the + * stream is read from, data from the iterator will fill a buffer and will be + * continuously called until the buffer is equal to the requested read size. + * Subsequent read calls will first read from the buffer and then call `next` + * on the underlying iterator until it is exhausted. + * - `object` with `__toString()`: If the object has the `__toString()` method, + * the object will be cast to a string and then a stream will be returned that + * uses the string value. + * - `NULL`: When `null` is passed, an empty stream object is returned. + * - `callable` When a callable is passed, a read-only stream object will be + * created that invokes the given callable. The callable is invoked with the + * number of suggested bytes to read. The callable can return any number of + * bytes, but MUST return `false` when there is no more data to return. The + * stream object that wraps the callable will invoke the callable until the + * number of requested bytes are available. Any additional bytes will be + * buffered and used in subsequent reads. + * + * @param resource|string|int|float|bool|StreamInterface|callable|\Iterator|null $resource Entity body data + * @param array $options Additional options + * + * @return StreamInterface * - * @return Stream * @throws \InvalidArgumentException if the $resource arg is not valid. + * + * @deprecated stream_for will be removed in guzzlehttp/psr7:2.0. Use Utils::streamFor instead. */ function stream_for($resource = '', array $options = []) { - if (is_scalar($resource)) { - $stream = fopen('php://temp', 'r+'); - if ($resource !== '') { - fwrite($stream, $resource); - fseek($stream, 0); - } - return new Stream($stream, $options); - } - - switch (gettype($resource)) { - case 'resource': - return new Stream($resource, $options); - case 'object': - if ($resource instanceof StreamInterface) { - return $resource; - } elseif ($resource instanceof \Iterator) { - return new PumpStream(function () use ($resource) { - if (!$resource->valid()) { - return false; - } - $result = $resource->current(); - $resource->next(); - return $result; - }, $options); - } elseif (method_exists($resource, '__toString')) { - return stream_for((string) $resource, $options); - } - break; - case 'NULL': - return new Stream(fopen('php://temp', 'r+'), $options); - } - - if (is_callable($resource)) { - return new PumpStream($resource, $options); - } - - throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource)); + return Utils::streamFor($resource, $options); } /** * Parse an array of header values containing ";" separated data into an - * array of associative arrays representing the header key value pair - * data of the header. When a parameter does not contain a value, but just + * array of associative arrays representing the header key value pair data + * of the header. When a parameter does not contain a value, but just * contains a key, this function will inject a key with a '' string value. * * @param string|array $header Header to parse into components. * * @return array Returns the parsed header values. + * + * @deprecated parse_header will be removed in guzzlehttp/psr7:2.0. Use Header::parse instead. */ function parse_header($header) { - static $trimmed = "\"' \n\t\r"; - $params = $matches = []; - - foreach (normalize_header($header) as $val) { - $part = []; - foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) { - if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) { - $m = $matches[0]; - if (isset($m[1])) { - $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed); - } else { - $part[] = trim($m[0], $trimmed); - } - } - } - if ($part) { - $params[] = $part; - } - } - - return $params; + return Header::parse($header); } /** @@ -158,32 +108,20 @@ function parse_header($header) * @param string|array $header Header to normalize. * * @return array Returns the normalized header field values. + * + * @deprecated normalize_header will be removed in guzzlehttp/psr7:2.0. Use Header::normalize instead. */ function normalize_header($header) { - if (!is_array($header)) { - return array_map('trim', explode(',', $header)); - } - - $result = []; - foreach ($header as $value) { - foreach ((array) $value as $v) { - if (strpos($v, ',') === false) { - $result[] = $v; - continue; - } - foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $v) as $vv) { - $result[] = trim($vv); - } - } - } - - return $result; + return Header::normalize($header); } /** * Clone and modify a request with the given changes. * + * This method is useful for reducing the number of clones needed to mutate a + * message. + * * The changes can be one of: * - method: (string) Changes the HTTP method. * - set_headers: (array) Sets the given headers. @@ -197,68 +135,12 @@ function normalize_header($header) * @param array $changes Changes to apply. * * @return RequestInterface + * + * @deprecated modify_request will be removed in guzzlehttp/psr7:2.0. Use Utils::modifyRequest instead. */ function modify_request(RequestInterface $request, array $changes) { - if (!$changes) { - return $request; - } - - $headers = $request->getHeaders(); - - if (!isset($changes['uri'])) { - $uri = $request->getUri(); - } else { - // Remove the host header if one is on the URI - if ($host = $changes['uri']->getHost()) { - $changes['set_headers']['Host'] = $host; - - if ($port = $changes['uri']->getPort()) { - $standardPorts = ['http' => 80, 'https' => 443]; - $scheme = $changes['uri']->getScheme(); - if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) { - $changes['set_headers']['Host'] .= ':'.$port; - } - } - } - $uri = $changes['uri']; - } - - if (!empty($changes['remove_headers'])) { - $headers = _caseless_remove($changes['remove_headers'], $headers); - } - - if (!empty($changes['set_headers'])) { - $headers = _caseless_remove(array_keys($changes['set_headers']), $headers); - $headers = $changes['set_headers'] + $headers; - } - - if (isset($changes['query'])) { - $uri = $uri->withQuery($changes['query']); - } - - if ($request instanceof ServerRequestInterface) { - return new ServerRequest( - isset($changes['method']) ? $changes['method'] : $request->getMethod(), - $uri, - $headers, - isset($changes['body']) ? $changes['body'] : $request->getBody(), - isset($changes['version']) - ? $changes['version'] - : $request->getProtocolVersion(), - $request->getServerParams() - ); - } - - return new Request( - isset($changes['method']) ? $changes['method'] : $request->getMethod(), - $uri, - $headers, - isset($changes['body']) ? $changes['body'] : $request->getBody(), - isset($changes['version']) - ? $changes['version'] - : $request->getProtocolVersion() - ); + return Utils::modifyRequest($request, $changes); } /** @@ -270,14 +152,12 @@ function modify_request(RequestInterface $request, array $changes) * @param MessageInterface $message Message to rewind * * @throws \RuntimeException + * + * @deprecated rewind_body will be removed in guzzlehttp/psr7:2.0. Use Message::rewindBody instead. */ function rewind_body(MessageInterface $message) { - $body = $message->getBody(); - - if ($body->tell()) { - $body->rewind(); - } + Message::rewindBody($message); } /** @@ -290,29 +170,14 @@ function rewind_body(MessageInterface $message) * @param string $mode Mode used to open the file * * @return resource + * * @throws \RuntimeException if the file cannot be opened + * + * @deprecated try_fopen will be removed in guzzlehttp/psr7:2.0. Use Utils::tryFopen instead. */ function try_fopen($filename, $mode) { - $ex = null; - set_error_handler(function () use ($filename, $mode, &$ex) { - $ex = new \RuntimeException(sprintf( - 'Unable to open %s using mode %s: %s', - $filename, - $mode, - func_get_args()[1] - )); - }); - - $handle = fopen($filename, $mode); - restore_error_handler(); - - if ($ex) { - /** @var $ex \RuntimeException */ - throw $ex; - } - - return $handle; + return Utils::tryFopen($filename, $mode); } /** @@ -322,37 +187,16 @@ function try_fopen($filename, $mode) * @param StreamInterface $stream Stream to read * @param int $maxLen Maximum number of bytes to read. Pass -1 * to read the entire stream. + * * @return string + * * @throws \RuntimeException on error. + * + * @deprecated copy_to_string will be removed in guzzlehttp/psr7:2.0. Use Utils::copyToString instead. */ function copy_to_string(StreamInterface $stream, $maxLen = -1) { - $buffer = ''; - - if ($maxLen === -1) { - while (!$stream->eof()) { - $buf = $stream->read(1048576); - // Using a loose equality here to match on '' and false. - if ($buf == null) { - break; - } - $buffer .= $buf; - } - return $buffer; - } - - $len = 0; - while (!$stream->eof() && $len < $maxLen) { - $buf = $stream->read($maxLen - $len); - // Using a loose equality here to match on '' and false. - if ($buf == null) { - break; - } - $buffer .= $buf; - $len = strlen($buffer); - } - - return $buffer; + return Utils::copyToString($stream, $maxLen); } /** @@ -365,92 +209,48 @@ function copy_to_string(StreamInterface $stream, $maxLen = -1) * to read the entire stream. * * @throws \RuntimeException on error. + * + * @deprecated copy_to_stream will be removed in guzzlehttp/psr7:2.0. Use Utils::copyToStream instead. */ -function copy_to_stream( - StreamInterface $source, - StreamInterface $dest, - $maxLen = -1 -) { - $bufferSize = 8192; - - if ($maxLen === -1) { - while (!$source->eof()) { - if (!$dest->write($source->read($bufferSize))) { - break; - } - } - } else { - $remaining = $maxLen; - while ($remaining > 0 && !$source->eof()) { - $buf = $source->read(min($bufferSize, $remaining)); - $len = strlen($buf); - if (!$len) { - break; - } - $remaining -= $len; - $dest->write($buf); - } - } +function copy_to_stream(StreamInterface $source, StreamInterface $dest, $maxLen = -1) +{ + return Utils::copyToStream($source, $dest, $maxLen); } /** - * Calculate a hash of a Stream + * Calculate a hash of a stream. + * + * This method reads the entire stream to calculate a rolling hash, based on + * PHP's `hash_init` functions. * * @param StreamInterface $stream Stream to calculate the hash for * @param string $algo Hash algorithm (e.g. md5, crc32, etc) * @param bool $rawOutput Whether or not to use raw output * * @return string Returns the hash of the stream + * * @throws \RuntimeException on error. + * + * @deprecated hash will be removed in guzzlehttp/psr7:2.0. Use Utils::hash instead. */ -function hash( - StreamInterface $stream, - $algo, - $rawOutput = false -) { - $pos = $stream->tell(); - - if ($pos > 0) { - $stream->rewind(); - } - - $ctx = hash_init($algo); - while (!$stream->eof()) { - hash_update($ctx, $stream->read(1048576)); - } - - $out = hash_final($ctx, (bool) $rawOutput); - $stream->seek($pos); - - return $out; +function hash(StreamInterface $stream, $algo, $rawOutput = false) +{ + return Utils::hash($stream, $algo, $rawOutput); } /** - * Read a line from the stream up to the maximum allowed buffer length + * Read a line from the stream up to the maximum allowed buffer length. * * @param StreamInterface $stream Stream to read from - * @param int $maxLength Maximum buffer length + * @param int|null $maxLength Maximum buffer length + * + * @return string * - * @return string|bool + * @deprecated readline will be removed in guzzlehttp/psr7:2.0. Use Utils::readLine instead. */ function readline(StreamInterface $stream, $maxLength = null) { - $buffer = ''; - $size = 0; - - while (!$stream->eof()) { - // Using a loose equality here to match on '' and false. - if (null == ($byte = $stream->read(1))) { - return $buffer; - } - $buffer .= $byte; - // Break when a new line is found or the max length - 1 is reached - if ($byte === "\n" || ++$size === $maxLength - 1) { - break; - } - } - - return $buffer; + return Utils::readLine($stream, $maxLength); } /** @@ -459,26 +259,12 @@ function readline(StreamInterface $stream, $maxLength = null) * @param string $message Request message string. * * @return Request + * + * @deprecated parse_request will be removed in guzzlehttp/psr7:2.0. Use Message::parseRequest instead. */ function parse_request($message) { - $data = _parse_message($message); - $matches = []; - if (!preg_match('/^[\S]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) { - throw new \InvalidArgumentException('Invalid request string'); - } - $parts = explode(' ', $data['start-line'], 3); - $version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1'; - - $request = new Request( - $parts[0], - $matches[1] === '/' ? _parse_request_uri($parts[1], $data['headers']) : $parts[1], - $data['headers'], - $data['body'], - $version - ); - - return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]); + return Message::parseRequest($message); } /** @@ -487,139 +273,67 @@ function parse_request($message) * @param string $message Response message string. * * @return Response + * + * @deprecated parse_response will be removed in guzzlehttp/psr7:2.0. Use Message::parseResponse instead. */ function parse_response($message) { - $data = _parse_message($message); - // According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space - // between status-code and reason-phrase is required. But browsers accept - // responses without space and reason as well. - if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) { - throw new \InvalidArgumentException('Invalid response string'); - } - $parts = explode(' ', $data['start-line'], 3); - - return new Response( - $parts[1], - $data['headers'], - $data['body'], - explode('/', $parts[0])[1], - isset($parts[2]) ? $parts[2] : null - ); + return Message::parseResponse($message); } /** * Parse a query string into an associative array. * - * If multiple values are found for the same key, the value of that key - * value pair will become an array. This function does not parse nested - * PHP style arrays into an associative array (e.g., foo[a]=1&foo[b]=2 will - * be parsed into ['foo[a]' => '1', 'foo[b]' => '2']). + * If multiple values are found for the same key, the value of that key value + * pair will become an array. This function does not parse nested PHP style + * arrays into an associative array (e.g., `foo[a]=1&foo[b]=2` will be parsed + * into `['foo[a]' => '1', 'foo[b]' => '2'])`. * - * @param string $str Query string to parse - * @param bool|string $urlEncoding How the query string is encoded + * @param string $str Query string to parse + * @param int|bool $urlEncoding How the query string is encoded * * @return array + * + * @deprecated parse_query will be removed in guzzlehttp/psr7:2.0. Use Query::parse instead. */ function parse_query($str, $urlEncoding = true) { - $result = []; - - if ($str === '') { - return $result; - } - - if ($urlEncoding === true) { - $decoder = function ($value) { - return rawurldecode(str_replace('+', ' ', $value)); - }; - } elseif ($urlEncoding == PHP_QUERY_RFC3986) { - $decoder = 'rawurldecode'; - } elseif ($urlEncoding == PHP_QUERY_RFC1738) { - $decoder = 'urldecode'; - } else { - $decoder = function ($str) { return $str; }; - } - - foreach (explode('&', $str) as $kvp) { - $parts = explode('=', $kvp, 2); - $key = $decoder($parts[0]); - $value = isset($parts[1]) ? $decoder($parts[1]) : null; - if (!isset($result[$key])) { - $result[$key] = $value; - } else { - if (!is_array($result[$key])) { - $result[$key] = [$result[$key]]; - } - $result[$key][] = $value; - } - } - - return $result; + return Query::parse($str, $urlEncoding); } /** * Build a query string from an array of key value pairs. * - * This function can use the return value of parse_query() to build a query + * This function can use the return value of `parse_query()` to build a query * string. This function does not modify the provided keys when an array is - * encountered (like http_build_query would). + * encountered (like `http_build_query()` would). * * @param array $params Query string parameters. * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986 * to encode using RFC3986, or PHP_QUERY_RFC1738 * to encode using RFC1738. + * * @return string + * + * @deprecated build_query will be removed in guzzlehttp/psr7:2.0. Use Query::build instead. */ function build_query(array $params, $encoding = PHP_QUERY_RFC3986) { - if (!$params) { - return ''; - } - - if ($encoding === false) { - $encoder = function ($str) { return $str; }; - } elseif ($encoding === PHP_QUERY_RFC3986) { - $encoder = 'rawurlencode'; - } elseif ($encoding === PHP_QUERY_RFC1738) { - $encoder = 'urlencode'; - } else { - throw new \InvalidArgumentException('Invalid type'); - } - - $qs = ''; - foreach ($params as $k => $v) { - $k = $encoder($k); - if (!is_array($v)) { - $qs .= $k; - if ($v !== null) { - $qs .= '=' . $encoder($v); - } - $qs .= '&'; - } else { - foreach ($v as $vv) { - $qs .= $k; - if ($vv !== null) { - $qs .= '=' . $encoder($vv); - } - $qs .= '&'; - } - } - } - - return $qs ? (string) substr($qs, 0, -1) : ''; + return Query::build($params, $encoding); } /** * Determines the mimetype of a file by looking at its extension. * - * @param $filename + * @param string $filename + * + * @return string|null * - * @return null|string + * @deprecated mimetype_from_filename will be removed in guzzlehttp/psr7:2.0. Use MimeType::fromFilename instead. */ function mimetype_from_filename($filename) { - return mimetype_from_extension(pathinfo($filename, PATHINFO_EXTENSION)); + return MimeType::fromFilename($filename); } /** @@ -628,116 +342,13 @@ function mimetype_from_filename($filename) * @param $extension string The file extension. * * @return string|null + * * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types + * @deprecated mimetype_from_extension will be removed in guzzlehttp/psr7:2.0. Use MimeType::fromExtension instead. */ function mimetype_from_extension($extension) { - static $mimetypes = [ - '7z' => 'application/x-7z-compressed', - 'aac' => 'audio/x-aac', - 'ai' => 'application/postscript', - 'aif' => 'audio/x-aiff', - 'asc' => 'text/plain', - 'asf' => 'video/x-ms-asf', - 'atom' => 'application/atom+xml', - 'avi' => 'video/x-msvideo', - 'bmp' => 'image/bmp', - 'bz2' => 'application/x-bzip2', - 'cer' => 'application/pkix-cert', - 'crl' => 'application/pkix-crl', - 'crt' => 'application/x-x509-ca-cert', - 'css' => 'text/css', - 'csv' => 'text/csv', - 'cu' => 'application/cu-seeme', - 'deb' => 'application/x-debian-package', - 'doc' => 'application/msword', - 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'dvi' => 'application/x-dvi', - 'eot' => 'application/vnd.ms-fontobject', - 'eps' => 'application/postscript', - 'epub' => 'application/epub+zip', - 'etx' => 'text/x-setext', - 'flac' => 'audio/flac', - 'flv' => 'video/x-flv', - 'gif' => 'image/gif', - 'gz' => 'application/gzip', - 'htm' => 'text/html', - 'html' => 'text/html', - 'ico' => 'image/x-icon', - 'ics' => 'text/calendar', - 'ini' => 'text/plain', - 'iso' => 'application/x-iso9660-image', - 'jar' => 'application/java-archive', - 'jpe' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'js' => 'text/javascript', - 'json' => 'application/json', - 'latex' => 'application/x-latex', - 'log' => 'text/plain', - 'm4a' => 'audio/mp4', - 'm4v' => 'video/mp4', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'mov' => 'video/quicktime', - 'mp3' => 'audio/mpeg', - 'mp4' => 'video/mp4', - 'mp4a' => 'audio/mp4', - 'mp4v' => 'video/mp4', - 'mpe' => 'video/mpeg', - 'mpeg' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'mpg4' => 'video/mp4', - 'oga' => 'audio/ogg', - 'ogg' => 'audio/ogg', - 'ogv' => 'video/ogg', - 'ogx' => 'application/ogg', - 'pbm' => 'image/x-portable-bitmap', - 'pdf' => 'application/pdf', - 'pgm' => 'image/x-portable-graymap', - 'png' => 'image/png', - 'pnm' => 'image/x-portable-anymap', - 'ppm' => 'image/x-portable-pixmap', - 'ppt' => 'application/vnd.ms-powerpoint', - 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'ps' => 'application/postscript', - 'qt' => 'video/quicktime', - 'rar' => 'application/x-rar-compressed', - 'ras' => 'image/x-cmu-raster', - 'rss' => 'application/rss+xml', - 'rtf' => 'application/rtf', - 'sgm' => 'text/sgml', - 'sgml' => 'text/sgml', - 'svg' => 'image/svg+xml', - 'swf' => 'application/x-shockwave-flash', - 'tar' => 'application/x-tar', - 'tif' => 'image/tiff', - 'tiff' => 'image/tiff', - 'torrent' => 'application/x-bittorrent', - 'ttf' => 'application/x-font-ttf', - 'txt' => 'text/plain', - 'wav' => 'audio/x-wav', - 'webm' => 'video/webm', - 'wma' => 'audio/x-ms-wma', - 'wmv' => 'video/x-ms-wmv', - 'woff' => 'application/x-font-woff', - 'wsdl' => 'application/wsdl+xml', - 'xbm' => 'image/x-xbitmap', - 'xls' => 'application/vnd.ms-excel', - 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'xml' => 'application/xml', - 'xpm' => 'image/x-xpixmap', - 'xwd' => 'image/x-xwindowdump', - 'yaml' => 'text/yaml', - 'yml' => 'text/yaml', - 'zip' => 'application/zip', - ]; - - $extension = strtolower($extension); - - return isset($mimetypes[$extension]) - ? $mimetypes[$extension] - : null; + return MimeType::fromExtension($extension); } /** @@ -750,37 +361,14 @@ function mimetype_from_extension($extension) * @param string $message HTTP request or response to parse. * * @return array + * * @internal + * + * @deprecated _parse_message will be removed in guzzlehttp/psr7:2.0. Use Message::parseMessage instead. */ function _parse_message($message) { - if (!$message) { - throw new \InvalidArgumentException('Invalid message'); - } - - // Iterate over each line in the message, accounting for line endings - $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE); - $result = ['start-line' => array_shift($lines), 'headers' => [], 'body' => '']; - array_shift($lines); - - for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) { - $line = $lines[$i]; - // If two line breaks were encountered, then this is the end of body - if (empty($line)) { - if ($i < $totalLines - 1) { - $result['body'] = implode('', array_slice($lines, $i + 2)); - } - break; - } - if (strpos($line, ':')) { - $parts = explode(':', $line, 2); - $key = trim($parts[0]); - $value = isset($parts[1]) ? trim($parts[1]) : ''; - $result['headers'][$key][] = $value; - } - } - - return $result; + return Message::parseMessage($message); } /** @@ -790,39 +378,45 @@ function _parse_message($message) * @param array $headers Array of headers (each value an array). * * @return string + * * @internal + * + * @deprecated _parse_request_uri will be removed in guzzlehttp/psr7:2.0. Use Message::parseRequestUri instead. */ function _parse_request_uri($path, array $headers) { - $hostKey = array_filter(array_keys($headers), function ($k) { - return strtolower($k) === 'host'; - }); - - // If no host is found, then a full URI cannot be constructed. - if (!$hostKey) { - return $path; - } - - $host = $headers[reset($hostKey)][0]; - $scheme = substr($host, -4) === ':443' ? 'https' : 'http'; + return Message::parseRequestUri($path, $headers); +} - return $scheme . '://' . $host . '/' . ltrim($path, '/'); +/** + * Get a short summary of the message body. + * + * Will return `null` if the response is not printable. + * + * @param MessageInterface $message The message to get the body summary + * @param int $truncateAt The maximum allowed size of the summary + * + * @return string|null + * + * @deprecated get_message_body_summary will be removed in guzzlehttp/psr7:2.0. Use Message::bodySummary instead. + */ +function get_message_body_summary(MessageInterface $message, $truncateAt = 120) +{ + return Message::bodySummary($message, $truncateAt); } -/** @internal */ +/** + * Remove the items given by the keys, case insensitively from the data. + * + * @param iterable $keys + * + * @return array + * + * @internal + * + * @deprecated _caseless_remove will be removed in guzzlehttp/psr7:2.0. Use Utils::caselessRemove instead. + */ function _caseless_remove($keys, array $data) { - $result = []; - - foreach ($keys as &$key) { - $key = strtolower($key); - } - - foreach ($data as $k => $v) { - if (!in_array(strtolower($k), $keys)) { - $result[$k] = $v; - } - } - - return $result; + return Utils::caselessRemove($keys, $data); } diff --git a/vendor/paragonie/random_compat/LICENSE b/vendor/paragonie/random_compat/LICENSE new file mode 100644 index 00000000..45c7017d --- /dev/null +++ b/vendor/paragonie/random_compat/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Paragon Initiative Enterprises + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/paragonie/random_compat/composer.json b/vendor/paragonie/random_compat/composer.json new file mode 100644 index 00000000..794e7fea --- /dev/null +++ b/vendor/paragonie/random_compat/composer.json @@ -0,0 +1,38 @@ +{ + "name": "paragonie/random_compat", + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "random", + "polyfill", + "pseudorandom" + ], + "license": "MIT", + "type": "library", + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "support": { + "issues": "https://github.com/paragonie/random_compat/issues", + "email": "info@paragonie.com", + "source": "https://github.com/paragonie/random_compat" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "autoload": { + "files": [ + "lib/random.php" + ] + } +} diff --git a/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey new file mode 100644 index 00000000..eb50ebfc --- /dev/null +++ b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey @@ -0,0 +1,5 @@ +-----BEGIN PUBLIC KEY----- +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm +pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p ++h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc +-----END PUBLIC KEY----- diff --git a/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc new file mode 100644 index 00000000..6a1d7f30 --- /dev/null +++ b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2.0.22 (MingW32) + +iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip +QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg +1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW +NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA +NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV +JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74= +=B6+8 +-----END PGP SIGNATURE----- diff --git a/vendor/paragonie/random_compat/lib/byte_safe_strings.php b/vendor/paragonie/random_compat/lib/byte_safe_strings.php new file mode 100644 index 00000000..ef24488f --- /dev/null +++ b/vendor/paragonie/random_compat/lib/byte_safe_strings.php @@ -0,0 +1,195 @@ + RandomCompat_strlen($binary_string)) { + return ''; + } + + return (string) mb_substr( + (string) $binary_string, + (int) $start, + (int) $length, + '8bit' + ); + } + + } else { + + /** + * substr() implementation that isn't brittle to mbstring.func_overload + * + * This version just uses the default substr() + * + * @param string $binary_string + * @param int $start + * @param int|null $length (optional) + * + * @throws TypeError + * + * @return string + */ + function RandomCompat_substr($binary_string, $start, $length = null) + { + if (!is_string($binary_string)) { + throw new TypeError( + 'RandomCompat_substr(): First argument should be a string' + ); + } + + if (!is_int($start)) { + throw new TypeError( + 'RandomCompat_substr(): Second argument should be an integer' + ); + } + + if ($length !== null) { + if (!is_int($length)) { + throw new TypeError( + 'RandomCompat_substr(): Third argument should be an integer, or omitted' + ); + } + + return (string) substr( + (string )$binary_string, + (int) $start, + (int) $length + ); + } + + return (string) substr( + (string) $binary_string, + (int) $start + ); + } + } +} diff --git a/vendor/paragonie/random_compat/lib/cast_to_int.php b/vendor/paragonie/random_compat/lib/cast_to_int.php new file mode 100644 index 00000000..1b1bbfe8 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/cast_to_int.php @@ -0,0 +1,77 @@ + operators might accidentally let a float + * through. + * + * @param int|float $number The number we want to convert to an int + * @param bool $fail_open Set to true to not throw an exception + * + * @return float|int + * @psalm-suppress InvalidReturnType + * + * @throws TypeError + */ + function RandomCompat_intval($number, $fail_open = false) + { + if (is_int($number) || is_float($number)) { + $number += 0; + } elseif (is_numeric($number)) { + /** @psalm-suppress InvalidOperand */ + $number += 0; + } + /** @var int|float $number */ + + if ( + is_float($number) + && + $number > ~PHP_INT_MAX + && + $number < PHP_INT_MAX + ) { + $number = (int) $number; + } + + if (is_int($number)) { + return (int) $number; + } elseif (!$fail_open) { + throw new TypeError( + 'Expected an integer.' + ); + } + return $number; + } +} diff --git a/vendor/paragonie/random_compat/lib/error_polyfill.php b/vendor/paragonie/random_compat/lib/error_polyfill.php new file mode 100644 index 00000000..c02c5c8b --- /dev/null +++ b/vendor/paragonie/random_compat/lib/error_polyfill.php @@ -0,0 +1,49 @@ += 70000) { + return; +} + +if (!defined('RANDOM_COMPAT_READ_BUFFER')) { + define('RANDOM_COMPAT_READ_BUFFER', 8); +} + +$RandomCompatDIR = dirname(__FILE__); + +require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'byte_safe_strings.php'; +require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'cast_to_int.php'; +require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'error_polyfill.php'; + +if (!is_callable('random_bytes')) { + /** + * PHP 5.2.0 - 5.6.x way to implement random_bytes() + * + * We use conditional statements here to define the function in accordance + * to the operating environment. It's a micro-optimization. + * + * In order of preference: + * 1. Use libsodium if available. + * 2. fread() /dev/urandom if available (never on Windows) + * 3. mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM) + * 4. COM('CAPICOM.Utilities.1')->GetRandom() + * + * See RATIONALE.md for our reasoning behind this particular order + */ + if (extension_loaded('libsodium')) { + // See random_bytes_libsodium.php + if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) { + require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'random_bytes_libsodium.php'; + } elseif (method_exists('Sodium', 'randombytes_buf')) { + require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'random_bytes_libsodium_legacy.php'; + } + } + + /** + * Reading directly from /dev/urandom: + */ + if (DIRECTORY_SEPARATOR === '/') { + // DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast + // way to exclude Windows. + $RandomCompatUrandom = true; + $RandomCompat_basedir = ini_get('open_basedir'); + + if (!empty($RandomCompat_basedir)) { + $RandomCompat_open_basedir = explode( + PATH_SEPARATOR, + strtolower($RandomCompat_basedir) + ); + $RandomCompatUrandom = (array() !== array_intersect( + array('/dev', '/dev/', '/dev/urandom'), + $RandomCompat_open_basedir + )); + $RandomCompat_open_basedir = null; + } + + if ( + !is_callable('random_bytes') + && + $RandomCompatUrandom + && + @is_readable('/dev/urandom') + ) { + // Error suppression on is_readable() in case of an open_basedir + // or safe_mode failure. All we care about is whether or not we + // can read it at this point. If the PHP environment is going to + // panic over trying to see if the file can be read in the first + // place, that is not helpful to us here. + + // See random_bytes_dev_urandom.php + require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'random_bytes_dev_urandom.php'; + } + // Unset variables after use + $RandomCompat_basedir = null; + } else { + $RandomCompatUrandom = false; + } + + /** + * mcrypt_create_iv() + * + * We only want to use mcypt_create_iv() if: + * + * - random_bytes() hasn't already been defined + * - the mcrypt extensions is loaded + * - One of these two conditions is true: + * - We're on Windows (DIRECTORY_SEPARATOR !== '/') + * - We're not on Windows and /dev/urandom is readabale + * (i.e. we're not in a chroot jail) + * - Special case: + * - If we're not on Windows, but the PHP version is between + * 5.6.10 and 5.6.12, we don't want to use mcrypt. It will + * hang indefinitely. This is bad. + * - If we're on Windows, we want to use PHP >= 5.3.7 or else + * we get insufficient entropy errors. + */ + if ( + !is_callable('random_bytes') + && + // Windows on PHP < 5.3.7 is broken, but non-Windows is not known to be. + (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307) + && + // Prevent this code from hanging indefinitely on non-Windows; + // see https://bugs.php.net/bug.php?id=69833 + ( + DIRECTORY_SEPARATOR !== '/' || + (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613) + ) + && + extension_loaded('mcrypt') + ) { + // See random_bytes_mcrypt.php + require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'random_bytes_mcrypt.php'; + } + $RandomCompatUrandom = null; + + /** + * This is a Windows-specific fallback, for when the mcrypt extension + * isn't loaded. + */ + if ( + !is_callable('random_bytes') + && + extension_loaded('com_dotnet') + && + class_exists('COM') + ) { + $RandomCompat_disabled_classes = preg_split( + '#\s*,\s*#', + strtolower(ini_get('disable_classes')) + ); + + if (!in_array('com', $RandomCompat_disabled_classes)) { + try { + $RandomCompatCOMtest = new COM('CAPICOM.Utilities.1'); + /** @psalm-suppress TypeDoesNotContainType */ + if (is_callable(array($RandomCompatCOMtest, 'GetRandom'))) { + // See random_bytes_com_dotnet.php + require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'random_bytes_com_dotnet.php'; + } + } catch (com_exception $e) { + // Don't try to use it. + } + } + $RandomCompat_disabled_classes = null; + $RandomCompatCOMtest = null; + } + + /** + * throw new Exception + */ + if (!is_callable('random_bytes')) { + /** + * We don't have any more options, so let's throw an exception right now + * and hope the developer won't let it fail silently. + * + * @param mixed $length + * @psalm-suppress InvalidReturnType + * @throws Exception + * @return string + */ + function random_bytes($length) + { + unset($length); // Suppress "variable not used" warnings. + throw new Exception( + 'There is no suitable CSPRNG installed on your system' + ); + return ''; + } + } +} + +if (!is_callable('random_int')) { + require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'random_int.php'; +} + +$RandomCompatDIR = null; diff --git a/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php b/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php new file mode 100644 index 00000000..537d02b2 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php @@ -0,0 +1,91 @@ +GetRandom($bytes, 0)); + if (RandomCompat_strlen($buf) >= $bytes) { + /** + * Return our random entropy buffer here: + */ + return (string) RandomCompat_substr($buf, 0, $bytes); + } + ++$execCount; + } while ($execCount < $bytes); + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php b/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php new file mode 100644 index 00000000..c4e31ccb --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php @@ -0,0 +1,190 @@ + $st */ + $st = fstat($fp); + if (($st['mode'] & 0170000) !== 020000) { + fclose($fp); + $fp = false; + } + } + } + + if (is_resource($fp)) { + /** + * stream_set_read_buffer() does not exist in HHVM + * + * If we don't set the stream's read buffer to 0, PHP will + * internally buffer 8192 bytes, which can waste entropy + * + * stream_set_read_buffer returns 0 on success + */ + if (is_callable('stream_set_read_buffer')) { + stream_set_read_buffer($fp, RANDOM_COMPAT_READ_BUFFER); + } + if (is_callable('stream_set_chunk_size')) { + stream_set_chunk_size($fp, RANDOM_COMPAT_READ_BUFFER); + } + } + } + + try { + /** @var int $bytes */ + $bytes = RandomCompat_intval($bytes); + } catch (TypeError $ex) { + throw new TypeError( + 'random_bytes(): $bytes must be an integer' + ); + } + + if ($bytes < 1) { + throw new Error( + 'Length must be greater than 0' + ); + } + + /** + * This if() block only runs if we managed to open a file handle + * + * It does not belong in an else {} block, because the above + * if (empty($fp)) line is logic that should only be run once per + * page load. + */ + if (is_resource($fp)) { + /** + * @var int + */ + $remaining = $bytes; + + /** + * @var string|bool + */ + $buf = ''; + + /** + * We use fread() in a loop to protect against partial reads + */ + do { + /** + * @var string|bool + */ + $read = fread($fp, $remaining); + if (!is_string($read)) { + /** + * We cannot safely read from the file. Exit the + * do-while loop and trigger the exception condition + * + * @var string|bool + */ + $buf = false; + break; + } + /** + * Decrease the number of bytes returned from remaining + */ + $remaining -= RandomCompat_strlen($read); + /** + * @var string $buf + */ + $buf .= $read; + } while ($remaining > 0); + + /** + * Is our result valid? + * @var string|bool $buf + */ + if (is_string($buf)) { + if (RandomCompat_strlen($buf) === $bytes) { + /** + * Return our random entropy buffer here: + */ + return $buf; + } + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Error reading from source device' + ); + } +} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php new file mode 100644 index 00000000..2e562901 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php @@ -0,0 +1,91 @@ + 2147483647) { + $buf = ''; + for ($i = 0; $i < $bytes; $i += 1073741824) { + $n = ($bytes - $i) > 1073741824 + ? 1073741824 + : $bytes - $i; + $buf .= \Sodium\randombytes_buf($n); + } + } else { + /** @var string|bool $buf */ + $buf = \Sodium\randombytes_buf($bytes); + } + + if (is_string($buf)) { + if (RandomCompat_strlen($buf) === $bytes) { + return $buf; + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php new file mode 100644 index 00000000..f78b2199 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php @@ -0,0 +1,93 @@ + 2147483647) { + for ($i = 0; $i < $bytes; $i += 1073741824) { + $n = ($bytes - $i) > 1073741824 + ? 1073741824 + : $bytes - $i; + $buf .= Sodium::randombytes_buf((int) $n); + } + } else { + $buf .= Sodium::randombytes_buf((int) $bytes); + } + + if (is_string($buf)) { + if (RandomCompat_strlen($buf) === $bytes) { + return $buf; + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php b/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php new file mode 100644 index 00000000..0b13fa73 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php @@ -0,0 +1,79 @@ + operators might accidentally let a float + * through. + */ + + try { + /** @var int $min */ + $min = RandomCompat_intval($min); + } catch (TypeError $ex) { + throw new TypeError( + 'random_int(): $min must be an integer' + ); + } + + try { + /** @var int $max */ + $max = RandomCompat_intval($max); + } catch (TypeError $ex) { + throw new TypeError( + 'random_int(): $max must be an integer' + ); + } + + /** + * Now that we've verified our weak typing system has given us an integer, + * let's validate the logic then we can move forward with generating random + * integers along a given range. + */ + if ($min > $max) { + throw new Error( + 'Minimum value must be less than or equal to the maximum value' + ); + } + + if ($max === $min) { + return (int) $min; + } + + /** + * Initialize variables to 0 + * + * We want to store: + * $bytes => the number of random bytes we need + * $mask => an integer bitmask (for use with the &) operator + * so we can minimize the number of discards + */ + $attempts = $bits = $bytes = $mask = $valueShift = 0; + /** @var int $attempts */ + /** @var int $bits */ + /** @var int $bytes */ + /** @var int $mask */ + /** @var int $valueShift */ + + /** + * At this point, $range is a positive number greater than 0. It might + * overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to + * a float and we will lose some precision. + * + * @var int|float $range + */ + $range = $max - $min; + + /** + * Test for integer overflow: + */ + if (!is_int($range)) { + + /** + * Still safely calculate wider ranges. + * Provided by @CodesInChaos, @oittaa + * + * @ref https://gist.github.com/CodesInChaos/03f9ea0b58e8b2b8d435 + * + * We use ~0 as a mask in this case because it generates all 1s + * + * @ref https://eval.in/400356 (32-bit) + * @ref http://3v4l.org/XX9r5 (64-bit) + */ + $bytes = PHP_INT_SIZE; + /** @var int $mask */ + $mask = ~0; + + } else { + + /** + * $bits is effectively ceil(log($range, 2)) without dealing with + * type juggling + */ + while ($range > 0) { + if ($bits % 8 === 0) { + ++$bytes; + } + ++$bits; + $range >>= 1; + /** @var int $mask */ + $mask = $mask << 1 | 1; + } + $valueShift = $min; + } + + /** @var int $val */ + $val = 0; + /** + * Now that we have our parameters set up, let's begin generating + * random integers until one falls between $min and $max + */ + /** @psalm-suppress RedundantCondition */ + do { + /** + * The rejection probability is at most 0.5, so this corresponds + * to a failure probability of 2^-128 for a working RNG + */ + if ($attempts > 128) { + throw new Exception( + 'random_int: RNG is broken - too many rejections' + ); + } + + /** + * Let's grab the necessary number of random bytes + */ + $randomByteString = random_bytes($bytes); + + /** + * Let's turn $randomByteString into an integer + * + * This uses bitwise operators (<< and |) to build an integer + * out of the values extracted from ord() + * + * Example: [9F] | [6D] | [32] | [0C] => + * 159 + 27904 + 3276800 + 201326592 => + * 204631455 + */ + $val &= 0; + for ($i = 0; $i < $bytes; ++$i) { + $val |= ord($randomByteString[$i]) << ($i * 8); + } + /** @var int $val */ + + /** + * Apply mask + */ + $val &= $mask; + $val += $valueShift; + + ++$attempts; + /** + * If $val overflows to a floating point number, + * ... or is larger than $max, + * ... or smaller than $min, + * then try again. + */ + } while (!is_int($val) || $val > $max || $val < $min); + + return (int) $val; + } +} diff --git a/vendor/pear/console_getopt/.gitignore b/vendor/pear/console_getopt/.gitignore new file mode 100644 index 00000000..78358281 --- /dev/null +++ b/vendor/pear/console_getopt/.gitignore @@ -0,0 +1,6 @@ +# composer related +composer.lock +composer.phar +vendor +README.html +dist/ diff --git a/vendor/pear/console_getopt/.travis.yml b/vendor/pear/console_getopt/.travis.yml new file mode 100644 index 00000000..2711415f --- /dev/null +++ b/vendor/pear/console_getopt/.travis.yml @@ -0,0 +1,9 @@ +language: php +php: + - 7 + - 5.6 + - 5.5 + - 5.4 +sudo: false +script: + - pear run-tests -r tests/ diff --git a/vendor/pear/console_getopt/Console/Getopt.php b/vendor/pear/console_getopt/Console/Getopt.php new file mode 100644 index 00000000..e5793bbb --- /dev/null +++ b/vendor/pear/console_getopt/Console/Getopt.php @@ -0,0 +1,365 @@ + + * @license http://opensource.org/licenses/bsd-license.php BSD-2-Clause + * @version CVS: $Id$ + * @link http://pear.php.net/package/Console_Getopt + */ + +require_once 'PEAR.php'; + +/** + * Command-line options parsing class. + * + * @category Console + * @package Console_Getopt + * @author Andrei Zmievski + * @license http://opensource.org/licenses/bsd-license.php BSD-2-Clause + * @link http://pear.php.net/package/Console_Getopt + */ +class Console_Getopt +{ + + /** + * Parses the command-line options. + * + * The first parameter to this function should be the list of command-line + * arguments without the leading reference to the running program. + * + * The second parameter is a string of allowed short options. Each of the + * option letters can be followed by a colon ':' to specify that the option + * requires an argument, or a double colon '::' to specify that the option + * takes an optional argument. + * + * The third argument is an optional array of allowed long options. The + * leading '--' should not be included in the option name. Options that + * require an argument should be followed by '=', and options that take an + * option argument should be followed by '=='. + * + * The return value is an array of two elements: the list of parsed + * options and the list of non-option command-line arguments. Each entry in + * the list of parsed options is a pair of elements - the first one + * specifies the option, and the second one specifies the option argument, + * if there was one. + * + * Long and short options can be mixed. + * + * Most of the semantics of this function are based on GNU getopt_long(). + * + * @param array $args an array of command-line arguments + * @param string $short_options specifies the list of allowed short options + * @param array $long_options specifies the list of allowed long options + * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option + * + * @return array two-element array containing the list of parsed options and + * the non-option arguments + */ + public static function getopt2($args, $short_options, $long_options = null, $skip_unknown = false) + { + return Console_Getopt::doGetopt(2, $args, $short_options, $long_options, $skip_unknown); + } + + /** + * This function expects $args to start with the script name (POSIX-style). + * Preserved for backwards compatibility. + * + * @param array $args an array of command-line arguments + * @param string $short_options specifies the list of allowed short options + * @param array $long_options specifies the list of allowed long options + * + * @see getopt2() + * @return array two-element array containing the list of parsed options and + * the non-option arguments + */ + public static function getopt($args, $short_options, $long_options = null, $skip_unknown = false) + { + return Console_Getopt::doGetopt(1, $args, $short_options, $long_options, $skip_unknown); + } + + /** + * The actual implementation of the argument parsing code. + * + * @param int $version Version to use + * @param array $args an array of command-line arguments + * @param string $short_options specifies the list of allowed short options + * @param array $long_options specifies the list of allowed long options + * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option + * + * @return array + */ + public static function doGetopt($version, $args, $short_options, $long_options = null, $skip_unknown = false) + { + // in case you pass directly readPHPArgv() as the first arg + if (PEAR::isError($args)) { + return $args; + } + + if (empty($args)) { + return array(array(), array()); + } + + $non_opts = $opts = array(); + + settype($args, 'array'); + + if ($long_options) { + sort($long_options); + } + + /* + * Preserve backwards compatibility with callers that relied on + * erroneous POSIX fix. + */ + if ($version < 2) { + if (isset($args[0][0]) && $args[0][0] != '-') { + array_shift($args); + } + } + + for ($i = 0; $i < count($args); $i++) { + $arg = $args[$i]; + /* The special element '--' means explicit end of + options. Treat the rest of the arguments as non-options + and end the loop. */ + if ($arg == '--') { + $non_opts = array_merge($non_opts, array_slice($args, $i + 1)); + break; + } + + if ($arg[0] != '-' || (strlen($arg) > 1 && $arg[1] == '-' && !$long_options)) { + $non_opts = array_merge($non_opts, array_slice($args, $i)); + break; + } elseif (strlen($arg) > 1 && $arg[1] == '-') { + $error = Console_Getopt::_parseLongOption(substr($arg, 2), + $long_options, + $opts, + $i, + $args, + $skip_unknown); + if (PEAR::isError($error)) { + return $error; + } + } elseif ($arg == '-') { + // - is stdin + $non_opts = array_merge($non_opts, array_slice($args, $i)); + break; + } else { + $error = Console_Getopt::_parseShortOption(substr($arg, 1), + $short_options, + $opts, + $i, + $args, + $skip_unknown); + if (PEAR::isError($error)) { + return $error; + } + } + } + + return array($opts, $non_opts); + } + + /** + * Parse short option + * + * @param string $arg Argument + * @param string[] $short_options Available short options + * @param string[][] &$opts + * @param int &$argIdx + * @param string[] $args + * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option + * + * @return void + */ + protected static function _parseShortOption($arg, $short_options, &$opts, &$argIdx, $args, $skip_unknown) + { + for ($i = 0; $i < strlen($arg); $i++) { + $opt = $arg[$i]; + $opt_arg = null; + + /* Try to find the short option in the specifier string. */ + if (($spec = strstr($short_options, $opt)) === false || $arg[$i] == ':') { + if ($skip_unknown === true) { + break; + } + + $msg = "Console_Getopt: unrecognized option -- $opt"; + return PEAR::raiseError($msg); + } + + if (strlen($spec) > 1 && $spec[1] == ':') { + if (strlen($spec) > 2 && $spec[2] == ':') { + if ($i + 1 < strlen($arg)) { + /* Option takes an optional argument. Use the remainder of + the arg string if there is anything left. */ + $opts[] = array($opt, substr($arg, $i + 1)); + break; + } + } else { + /* Option requires an argument. Use the remainder of the arg + string if there is anything left. */ + if ($i + 1 < strlen($arg)) { + $opts[] = array($opt, substr($arg, $i + 1)); + break; + } else if (isset($args[++$argIdx])) { + $opt_arg = $args[$argIdx]; + /* Else use the next argument. */; + if (Console_Getopt::_isShortOpt($opt_arg) + || Console_Getopt::_isLongOpt($opt_arg)) { + $msg = "option requires an argument --$opt"; + return PEAR::raiseError("Console_Getopt: " . $msg); + } + } else { + $msg = "option requires an argument --$opt"; + return PEAR::raiseError("Console_Getopt: " . $msg); + } + } + } + + $opts[] = array($opt, $opt_arg); + } + } + + /** + * Checks if an argument is a short option + * + * @param string $arg Argument to check + * + * @return bool + */ + protected static function _isShortOpt($arg) + { + return strlen($arg) == 2 && $arg[0] == '-' + && preg_match('/[a-zA-Z]/', $arg[1]); + } + + /** + * Checks if an argument is a long option + * + * @param string $arg Argument to check + * + * @return bool + */ + protected static function _isLongOpt($arg) + { + return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' && + preg_match('/[a-zA-Z]+$/', substr($arg, 2)); + } + + /** + * Parse long option + * + * @param string $arg Argument + * @param string[] $long_options Available long options + * @param string[][] &$opts + * @param int &$argIdx + * @param string[] $args + * + * @return void|PEAR_Error + */ + protected static function _parseLongOption($arg, $long_options, &$opts, &$argIdx, $args, $skip_unknown) + { + @list($opt, $opt_arg) = explode('=', $arg, 2); + + $opt_len = strlen($opt); + + for ($i = 0; $i < count($long_options); $i++) { + $long_opt = $long_options[$i]; + $opt_start = substr($long_opt, 0, $opt_len); + + $long_opt_name = str_replace('=', '', $long_opt); + + /* Option doesn't match. Go on to the next one. */ + if ($long_opt_name != $opt) { + continue; + } + + $opt_rest = substr($long_opt, $opt_len); + + /* Check that the options uniquely matches one of the allowed + options. */ + if ($i + 1 < count($long_options)) { + $next_option_rest = substr($long_options[$i + 1], $opt_len); + } else { + $next_option_rest = ''; + } + + if ($opt_rest != '' && $opt[0] != '=' && + $i + 1 < count($long_options) && + $opt == substr($long_options[$i+1], 0, $opt_len) && + $next_option_rest != '' && + $next_option_rest[0] != '=') { + + $msg = "Console_Getopt: option --$opt is ambiguous"; + return PEAR::raiseError($msg); + } + + if (substr($long_opt, -1) == '=') { + if (substr($long_opt, -2) != '==') { + /* Long option requires an argument. + Take the next argument if one wasn't specified. */; + if (!strlen($opt_arg)) { + if (!isset($args[++$argIdx])) { + $msg = "Console_Getopt: option requires an argument --$opt"; + return PEAR::raiseError($msg); + } + $opt_arg = $args[$argIdx]; + } + + if (Console_Getopt::_isShortOpt($opt_arg) + || Console_Getopt::_isLongOpt($opt_arg)) { + $msg = "Console_Getopt: option requires an argument --$opt"; + return PEAR::raiseError($msg); + } + } + } else if ($opt_arg) { + $msg = "Console_Getopt: option --$opt doesn't allow an argument"; + return PEAR::raiseError($msg); + } + + $opts[] = array('--' . $opt, $opt_arg); + return; + } + + if ($skip_unknown === true) { + return; + } + + return PEAR::raiseError("Console_Getopt: unrecognized option --$opt"); + } + + /** + * Safely read the $argv PHP array across different PHP configurations. + * Will take care on register_globals and register_argc_argv ini directives + * + * @return mixed the $argv PHP array or PEAR error if not registered + */ + public static function readPHPArgv() + { + global $argv; + if (!is_array($argv)) { + if (!@is_array($_SERVER['argv'])) { + if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) { + $msg = "Could not read cmd args (register_argc_argv=Off?)"; + return PEAR::raiseError("Console_Getopt: " . $msg); + } + return $GLOBALS['HTTP_SERVER_VARS']['argv']; + } + return $_SERVER['argv']; + } + return $argv; + } + +} diff --git a/vendor/pear/console_getopt/LICENSE b/vendor/pear/console_getopt/LICENSE new file mode 100644 index 00000000..452b0883 --- /dev/null +++ b/vendor/pear/console_getopt/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2001-2015, The PEAR developers +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/pear/console_getopt/README.rst b/vendor/pear/console_getopt/README.rst new file mode 100644 index 00000000..64e5b41b --- /dev/null +++ b/vendor/pear/console_getopt/README.rst @@ -0,0 +1,26 @@ +******************************************* +Console_Getopt - Command-line option parser +******************************************* + +This is a PHP implementation of "getopt" supporting both short and long options. +It helps parsing command line options in your PHP script. + +Homepage: http://pear.php.net/package/Console_Getopt + +.. image:: https://travis-ci.org/pear/Console_Getopt.svg?branch=master + :target: https://travis-ci.org/pear/Console_Getopt + + +Alternatives +============ + +* Console_CommandLine__ (recommended) +* Console_GetoptPlus__ + +__ http://pear.php.net/package/Console_CommandLine +__ http://pear.php.net/package/Console_GetoptPlus + + +License +======= +BSD-2-Clause diff --git a/vendor/pear/console_getopt/composer.json b/vendor/pear/console_getopt/composer.json new file mode 100644 index 00000000..4dc7e7cc --- /dev/null +++ b/vendor/pear/console_getopt/composer.json @@ -0,0 +1,35 @@ +{ + "authors": [ + { + "email": "andrei@php.net", + "name": "Andrei Zmievski", + "role": "Lead" + }, + { + "email": "stig@php.net", + "name": "Stig Bakken", + "role": "Developer" + }, + { + "email": "cellog@php.net", + "name": "Greg Beaver", + "role": "Helper" + } + ], + "autoload": { + "psr-0": { + "Console": "./" + } + }, + "description": "More info available on: http://pear.php.net/package/Console_Getopt", + "include-path": [ + "./" + ], + "license": "BSD-2-Clause", + "name": "pear/console_getopt", + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=Console_Getopt", + "source": "https://github.com/pear/Console_Getopt" + }, + "type": "library" +} diff --git a/vendor/pear/console_getopt/package.xml b/vendor/pear/console_getopt/package.xml new file mode 100644 index 00000000..d3fd7840 --- /dev/null +++ b/vendor/pear/console_getopt/package.xml @@ -0,0 +1,302 @@ + + + Console_Getopt + pear.php.net + Command-line option parser + This is a PHP implementation of "getopt" supporting both +short and long options. + + Andrei Zmievski + andrei + andrei@php.net + no + + + Stig Bakken + ssb + stig@php.net + no + + + Greg Beaver + cellog + cellog@php.net + no + + + 2019-11-20 + + 1.4.3 + 1.4.0 + + + stable + stable + + BSD-2-Clause + + +* PR #4: Fix PHP 7.4 deprecation: array/string curly braces access +* PR #5: fix phplint warnings + + + + + + + + + + + + + + + + + + PEAR + pear.php.net + 1.4.0 + 1.999.999 + + + + + + 5.4.0 + + + 1.8.0 + + + + + + + + + + 2019-11-20 + + 1.4.3 + 1.4.0 + + + stable + stable + + BSD-2-Clause + + * PR #4: Fix PHP 7.4 deprecation: array/string curly braces access + * PR #5: fix phplint warnings + + + + + 2019-02-06 + + 1.4.2 + 1.4.0 + + + stable + stable + + BSD-2-Clause + + * Remove use of each(), which is removed in PHP 8 + + + + + 2015-07-20 + + 1.4.1 + 1.4.0 + + + stable + stable + + BSD-2-Clause + + * Fix unit test on PHP 7 [cweiske] + + + + + 2015-02-22 + + 1.4.0 + 1.4.0 + + + stable + stable + + BSD-2-Clause + + * Change license to BSD-2-Clause + * Set minimum PHP version to 5.4.0 + * Mark static methods with "static" keyword + + + + + 2011-03-07 + + 1.3.1 + 1.3.0 + + + stable + stable + + PHP License + + * Change the minimum PEAR installer dep to be lower + + + + + 2010-12-11 + + + 1.3.0 + 1.3.0 + + + stable + stable + + PHP License + + * Implement Request #13140: [PATCH] to skip unknown parameters. [patch by rquadling, improved on by dufuz] + + + + + 2007-06-12 + + 1.2.3 + 1.2.1 + + + stable + stable + + PHP License + +* fix Bug #11068: No way to read plain "-" option [cardoe] + + + + + 1.2.2 + 1.2.1 + + + stable + stable + + 2007-02-17 + PHP License + +* fix Bug #4475: An ambiguous error occurred when specifying similar longoption name. +* fix Bug #10055: Not failing properly on short options missing required values + + + + + 1.2.1 + 1.2.1 + + + stable + stable + + 2006-12-08 + PHP License + +Fixed bugs #4448 (Long parameter values truncated with longoption parameter) and #7444 (Trailing spaces after php closing tag) + + + + + 1.2 + 1.2 + + + stable + stable + + 2003-12-11 + PHP License + +Fix to preserve BC with 1.0 and allow correct behaviour for new users + + + + + 1.0 + 1.0 + + + stable + stable + + 2002-09-13 + PHP License + +Stable release + + + + + 0.11 + 0.11 + + + beta + beta + + 2002-05-26 + PHP License + +POSIX getopt compatibility fix: treat first element of args + array as command name + + + + + 0.10 + 0.10 + + + beta + beta + + 2002-05-12 + PHP License + +Packaging fix + + + + + 0.9 + 0.9 + + + beta + beta + + 2002-05-12 + PHP License + +Initial release + + + + diff --git a/vendor/pear/console_getopt/tests/001-getopt.phpt b/vendor/pear/console_getopt/tests/001-getopt.phpt new file mode 100644 index 00000000..75ae8481 --- /dev/null +++ b/vendor/pear/console_getopt/tests/001-getopt.phpt @@ -0,0 +1,63 @@ +--TEST-- +Console_Getopt +--FILE-- + $d) { + if ($i++ > 0) { + print ", "; + } + print $d[0] . '=' . $d[1]; + } + print "\n"; + print "params: " . implode(", ", $non_opts) . "\n"; + print "\n"; +} + +test("-abc", "abc"); +test("-abc foo", "abc"); +test("-abc foo", "abc:"); +test("-abc foo bar gazonk", "abc"); +test("-abc foo bar gazonk", "abc:"); +test("-a -b -c", "abc"); +test("-a -b -c", "abc:"); +test("-abc", "ab:c"); +test("-abc foo -bar gazonk", "abc"); +?> +--EXPECT-- +options: a=, b=, c= +params: + +options: a=, b=, c= +params: foo + +options: a=, b=, c=foo +params: + +options: a=, b=, c= +params: foo, bar, gazonk + +options: a=, b=, c=foo +params: bar, gazonk + +options: a=, b=, c= +params: + +Console_Getopt: option requires an argument --c + +options: a=, b=c +params: + +options: a=, b=, c= +params: foo, -bar, gazonk diff --git a/vendor/pear/console_getopt/tests/bug10557.phpt b/vendor/pear/console_getopt/tests/bug10557.phpt new file mode 100644 index 00000000..08b72ac8 --- /dev/null +++ b/vendor/pear/console_getopt/tests/bug10557.phpt @@ -0,0 +1,22 @@ +--TEST-- +Console_Getopt [bug 10557] +--SKIPIF-- +--FILE-- +getMessage()."\n"; + echo 'FATAL'; + exit; +} + +print_r($ret); +?> +--EXPECT-- +Console_Getopt: option requires an argument --to +FATAL \ No newline at end of file diff --git a/vendor/pear/console_getopt/tests/bug11068.phpt b/vendor/pear/console_getopt/tests/bug11068.phpt new file mode 100644 index 00000000..8bbe4bfc --- /dev/null +++ b/vendor/pear/console_getopt/tests/bug11068.phpt @@ -0,0 +1,44 @@ +--TEST-- +Console_Getopt [bug 11068] +--SKIPIF-- +--FILE-- +getMessage()."\n"; + echo 'FATAL'; + exit; +} + +print_r($ret); +?> +--EXPECT-- +Array +( + [0] => Array + ( + [0] => Array + ( + [0] => f + [1] => jjohnston@mail.com + ) + + [1] => Array + ( + [0] => --to + [1] => hi + ) + + ) + + [1] => Array + ( + [0] => - + ) + +) \ No newline at end of file diff --git a/vendor/pear/console_getopt/tests/bug13140.phpt b/vendor/pear/console_getopt/tests/bug13140.phpt new file mode 100644 index 00000000..4ce13bbf --- /dev/null +++ b/vendor/pear/console_getopt/tests/bug13140.phpt @@ -0,0 +1,75 @@ +--TEST-- +Console_Getopt [bug 13140] +--SKIPIF-- +--FILE-- +getopt2($cg->readPHPArgv(), 't', array('test'), true)); +print_r($cg->getopt2($cg->readPHPArgv(), 'bar', array('foo'), true)); +?> +--EXPECT-- +Array +( + [0] => Array + ( + [0] => Array + ( + [0] => --test + [1] => + ) + + ) + + [1] => Array + ( + [0] => thisshouldbehere + ) + +) +Array +( + [0] => Array + ( + [0] => Array + ( + [0] => --foo + [1] => + ) + + [1] => Array + ( + [0] => b + [1] => + ) + + [2] => Array + ( + [0] => a + [1] => + ) + + [3] => Array + ( + [0] => r + [1] => + ) + + [4] => Array + ( + [0] => r + [1] => + ) + + ) + + [1] => Array + ( + [0] => thisshouldbehere + ) + +) diff --git a/vendor/pear/ole/.gitattributes b/vendor/pear/ole/.gitattributes new file mode 100644 index 00000000..d147983b --- /dev/null +++ b/vendor/pear/ole/.gitattributes @@ -0,0 +1,3 @@ +# Debug with: git archive --format=tar HEAD | tar t + +/tests export-ignore diff --git a/vendor/pear/ole/.github/workflows/ci.yaml b/vendor/pear/ole/.github/workflows/ci.yaml new file mode 100644 index 00000000..8dd2970b --- /dev/null +++ b/vendor/pear/ole/.github/workflows/ci.yaml @@ -0,0 +1,60 @@ +# yamllint disable rule:line-length +# yamllint disable rule:braces + +name: Continuous Integration + +on: + pull_request: + push: + branches: + - main + - master + +jobs: + tests: + runs-on: ${{ matrix.operating-system }} + + strategy: + matrix: + operating-system: ['ubuntu-latest'] + php-version: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0'] + + name: CI on ${{ matrix.operating-system }} with PHP ${{ matrix.php-version }} + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + tools: composer:v2 + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: composer-${{ runner.os }}-${{ matrix.php-version }}-${{ hashFiles('composer.*') }}-${{ matrix.composer-flags }} + restore-keys: | + composer-${{ runner.os }}-${{ matrix.php-version }}-${{ hashFiles('composer.*') }}- + composer-${{ runner.os }}-${{ matrix.php-version }}- + composer-${{ runner.os }}- + composer- + + - name: Install dependencies + run: | + composer update --no-interaction --prefer-dist --no-progress ${{ matrix.composer-flags }} + + - name: Run tests + run: | + vendor/bin/phpunit + + - name: Lint code + run: | + find OLE* -type f -name \*.php | xargs -n1 php -l diff --git a/vendor/pear/ole/.github/workflows/cs.yaml b/vendor/pear/ole/.github/workflows/cs.yaml new file mode 100644 index 00000000..1c13a4ac --- /dev/null +++ b/vendor/pear/ole/.github/workflows/cs.yaml @@ -0,0 +1,38 @@ +name: Coding Standards + +on: + pull_request: + push: + branches: + - main + - master + +jobs: + coding-standards: + name: Coding Standards + runs-on: ubuntu-latest + + env: + PHP_CS_FIXER_VERSION: v2.17.3 + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + coverage: none + tools: php-cs-fixer:${{ env.PHP_CS_FIXER_VERSION }} + + - name: Restore PHP-CS-Fixer cache + uses: actions/cache@v2 + with: + path: .php_cs.cache + key: "php-cs-fixer" + restore-keys: "php-cs-fixer" + + - name: Run PHP-CS-Fixer, version ${{ env.PHP_CS_FIXER_VERSION }} + run: | + php-cs-fixer fix --diff --diff-format=udiff --dry-run --verbose diff --git a/vendor/pear/ole/.gitignore b/vendor/pear/ole/.gitignore new file mode 100644 index 00000000..869f4985 --- /dev/null +++ b/vendor/pear/ole/.gitignore @@ -0,0 +1,4 @@ +# composer related +composer.lock +composer.phar +vendor diff --git a/vendor/pear/ole/.php_cs.dist b/vendor/pear/ole/.php_cs.dist new file mode 100644 index 00000000..68e3ed1a --- /dev/null +++ b/vendor/pear/ole/.php_cs.dist @@ -0,0 +1,11 @@ +setRules([ + '@PSR1' => true, + ]) + ->setFinder( + PhpCsFixer\Finder::create() + ->in(__DIR__) + ) +; diff --git a/vendor/pear/ole/.travis.yml b/vendor/pear/ole/.travis.yml new file mode 100644 index 00000000..c65b7214 --- /dev/null +++ b/vendor/pear/ole/.travis.yml @@ -0,0 +1,43 @@ +sudo: false + +language: php +php: + - 5.6 + - 7.0 + - 7.1 + - 7.2 + - 7.3 + - 7.4 + - 8.0 + - nightly + +stages: + - analyze + - test + +jobs: + fast_finish: true + allow_failures: + - php: nightly + include: + - stage: analyze + php: 7.4 + install: + - composer install --prefer-dist + script: + - php vendor/bin/php-cs-fixer fix --dry-run --diff + - composer validate + - find OLE* -type f -name \*.php | xargs -n1 php -l + +cache: + directories: + - $HOME/.composer/cache + - $HOME/.cache/cache + +install: + - composer remove --no-update --dev + friendsofphp/php-cs-fixer + - composer install --prefer-dist + +script: + - vendor/bin/phpunit --verbose diff --git a/vendor/pear/ole/OLE.php b/vendor/pear/ole/OLE.php new file mode 100644 index 00000000..dba5d5e4 --- /dev/null +++ b/vendor/pear/ole/OLE.php @@ -0,0 +1,616 @@ + | +// | Based on OLE::Storage_Lite by Kawai, Takanori | +// +----------------------------------------------------------------------+ +// +// $Id$ + + +/** +* Constants for OLE package +*/ +define('OLE_PPS_TYPE_ROOT', 0x05); +define('OLE_PPS_TYPE_DIR', 0x01); +define('OLE_PPS_TYPE_FILE', 0x02); +define('OLE_DATA_SIZE_SMALL', 0x1000); +define('OLE_LONG_INT_SIZE', 4); +define('OLE_PPS_SIZE', 0x80); +define('OLE_DIFSECT', 0xFFFFFFFC); +define('OLE_FATSECT', 0xFFFFFFFD); +define('OLE_ENDOFCHAIN', 0xFFFFFFFE); +define('OLE_FREESECT', 0xFFFFFFFF); +define('OLE_LITTLE_ENDIAN', 0xFFFE); +define('OLE_VERSION_MAJOR_3', 0x0003); +define('OLE_VERSION_MINOR', 0x003E); +define('OLE_SECTOR_SHIFT_3', 0x0009); +define('OLE_MINI_SECTOR_SHIFT', 0x0006); +define('OLE_CFB_SIGNATURE', "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"); + +if (!class_exists('PEAR')) { + require_once 'PEAR.php'; +} + +/** +* Array for storing OLE instances that are accessed from +* OLE_ChainedBlockStream::stream_open(). +* @var array +*/ +$GLOBALS['_OLE_INSTANCES'] = array(); + +/** +* OLE package base class. +* +* @category Structures +* @package OLE +* @author Xavier Noguer +* @author Christian Schmidt +*/ +class OLE extends PEAR +{ + + /** + * The file handle for reading an OLE container + * @var resource + */ + var $_file_handle; + + /** + * Reference to the sbat stream + * @var resource + */ + var $_small_handle; + + /** + * Array of PPS's found on the OLE container + * @var array + */ + var $_list; + + /** + * Root directory of OLE container + * @var OLE_PPS_Root + */ + var $root; + + /** + * Big Block Allocation Table + * @var array (blockId => nextBlockId) + */ + var $bbat; + + /** + * Short Block Allocation Table + * @var array (blockId => nextBlockId) + */ + var $sbat; + + /** + * Size of big blocks. This is usually 512. + * @var int number of octets per block. + */ + var $bigBlockSize; + + /** + * Size of small blocks. This is usually 64. + * @var int number of octets per block + */ + var $smallBlockSize; + + /** + * Creates a new OLE object + * @access public + */ + function __construct() + { + $this->_list = array(); + } + + /** + * Destructor (using PEAR) + * Just closes the file handle on the OLE file. + * + * @access private + */ + function _OLE() + { + fclose($this->_file_handle); + } + + /** + * Reads an OLE container from the contents of the file given. + * + * @access public + * @param string $file + * @return mixed true on success, PEAR_Error on failure + */ + function read($file) + { + $fh = @fopen($file, "r"); + if (!$fh) { + return $this->raiseError("Can't open file $file"); + } + + return $this->readStream($fh); + } + + /** + * Reads an OLE container from the contents of the stream given. + * + * @access public + * @param resource $fh + * @return mixed true on success, PEAR_Error on failure + */ + function readStream($fh) + { + $this->_file_handle = $fh; + + $signature = fread($fh, 8); + if (OLE_CFB_SIGNATURE != $signature) { + return $this->raiseError("File doesn't seem to be an OLE container."); + } + fseek($fh, 28); + if ($this->_readInt2($fh) != OLE_LITTLE_ENDIAN) { + // This shouldn't be a problem in practice + return $this->raiseError("Only Little-Endian encoding is supported."); + } + // Size of blocks and short blocks in bytes + $this->bigBlockSize = pow(2, $this->_readInt2($fh)); + $this->smallBlockSize = pow(2, $this->_readInt2($fh)); + + // Skip UID, revision number and version number + fseek($fh, 44); + // Number of blocks in Big Block Allocation Table + $bbatBlockCount = $this->_readInt4($fh); + + // Root chain 1st block + $directoryFirstBlockId = $this->_readInt4($fh); + + // Skip unused bytes + fseek($fh, 56); + // Streams shorter than this are stored using small blocks + $this->bigBlockThreshold = $this->_readInt4($fh); + // Block id of first sector in Short Block Allocation Table + $sbatFirstBlockId = $this->_readInt4($fh); + // Number of blocks in Short Block Allocation Table + $sbbatBlockCount = $this->_readInt4($fh); + // Block id of first sector in Master Block Allocation Table + $mbatFirstBlockId = $this->_readInt4($fh); + // Number of blocks in Master Block Allocation Table + $mbbatBlockCount = $this->_readInt4($fh); + $this->bbat = array(); + + // Remaining 4 * 109 bytes of current block is beginning of Master + // Block Allocation Table + $mbatBlocks = array(); + for ($i = 0; $i < 109; $i++) { + $mbatBlocks[] = $this->_readInt4($fh); + } + + // Read rest of Master Block Allocation Table (if any is left) + $pos = $this->_getBlockOffset($mbatFirstBlockId); + for ($i = 0; $i < $mbbatBlockCount; $i++) { + fseek($fh, $pos); + for ($j = 0; $j < $this->bigBlockSize / 4 - 1; $j++) { + $mbatBlocks[] = $this->_readInt4($fh); // ffix - invalid block address check + } + // Last block id in each block points to next block + $chainBlock = $this->_readInt4($fh); + if ($chainBlock === OLE_ENDOFCHAIN) { // ENDOFCHAIN + break; + } + $pos = $this->_getBlockOffset($chainBlock); + } + + + // Read Big Block Allocation Table according to chain specified by + // $mbatBlocks + for ($i = 0; $i < $bbatBlockCount; $i++) { + $pos = $this->_getBlockOffset($mbatBlocks[$i]); + fseek($fh, $pos); + for ($j = 0 ; $j < $this->bigBlockSize / 4; $j++) { + $this->bbat[] = $this->_readInt4($fh); + } + } + + // Read short block allocation table (SBAT) + $this->sbat = array(); + $shortBlockCount = $sbbatBlockCount * $this->bigBlockSize / 4; + $sbatFh = $this->getStream($sbatFirstBlockId); + if (!$sbatFh) { + // Avoid an infinite loop if ChainedBlockStream.php somehow is + // missing + return false; + } + + for ($blockId = 0; $blockId < $shortBlockCount; $blockId++) { + $this->sbat[$blockId] = $this->_readInt4($sbatFh); + } + fclose($sbatFh); + + $this->_readPpsWks($directoryFirstBlockId); + + return true; + } + + /** + * @param int $blockId block id + * @return int byte offset from beginning of file + * @access private + */ + function _getBlockOffset($blockId) + { + return 512 + $blockId * $this->bigBlockSize; + } + + /** + * Returns a stream for use with fread() etc. External callers should + * use OLE_PPS_File::getStream(). + * @param int|PPS $blockIdOrPps block id or PPS + * @return resource read-only stream + */ + function getStream($blockIdOrPps) + { + include_once 'OLE/ChainedBlockStream.php'; + static $isRegistered = false; + if (!$isRegistered) { + stream_wrapper_register('ole-chainedblockstream', + 'OLE_ChainedBlockStream'); + $isRegistered = true; + } + + // Store current instance in global array, so that it can be accessed + // in OLE_ChainedBlockStream::stream_open(). + // Object is removed from self::$instances in OLE_Stream::close(). + $GLOBALS['_OLE_INSTANCES'][] = $this; + $keys = array_keys($GLOBALS['_OLE_INSTANCES']); + $instanceId = end($keys); + + $path = 'ole-chainedblockstream://oleInstanceId=' . $instanceId; + if (is_a($blockIdOrPps, 'OLE_PPS')) { + $path .= '&blockId=' . $blockIdOrPps->_StartBlock; + $path .= '&size=' . $blockIdOrPps->Size; + } else { + $path .= '&blockId=' . $blockIdOrPps; + } + return fopen($path, 'r'); + } + + /** + * Reads a signed char. + * @param resource $fh file handle + * @return int + * @access private + */ + function _readInt1($fh) + { + list(, $tmp) = unpack("c", fread($fh, 1)); + return $tmp; + } + + /** + * Reads an unsigned short (2 octets). + * @param resource $fh file handle + * @return int + * @access private + */ + function _readInt2($fh) + { + list(, $tmp) = unpack("v", fread($fh, 2)); + return $tmp; + } + + /** + * Reads an unsigned long (4 octets). + * @param resource file handle + * @return int + * @access private + */ + function _readInt4($fh) + { + list(, $tmp) = unpack("V", fread($fh, 4)); + return $tmp; + } + + /** + * Gets information about all PPS's on the OLE container from the PPS WK's + * creates an OLE_PPS object for each one. + * + * @access private + * @param integer $blockId the block id of the first block + * @return mixed true on success, PEAR_Error on failure + */ + function _readPpsWks($blockId) + { + $fh = $this->getStream($blockId); + for ($pos = 0; ; $pos += 128) { + fseek($fh, $pos, SEEK_SET); + $nameUtf16 = fread($fh, 64); + $nameLength = $this->_readInt2($fh); + $nameUtf16 = substr($nameUtf16, 0, $nameLength - 2); + // Simple conversion from UTF-16LE to ISO-8859-1 + $name = str_replace("\x00", "", $nameUtf16); + $type = $this->_readInt1($fh); + switch ($type) { + case OLE_PPS_TYPE_ROOT: + require_once 'OLE/PPS/Root.php'; + $pps = new OLE_PPS_Root(null, null, array()); + $this->root = $pps; + break; + case OLE_PPS_TYPE_DIR: + $pps = new OLE_PPS(null, null, null, null, null, + null, null, null, null, array()); + break; + case OLE_PPS_TYPE_FILE: + require_once 'OLE/PPS/File.php'; + $pps = new OLE_PPS_File($name); + break; + default: + continue 2; + } + fseek($fh, 1, SEEK_CUR); // skip Color Flag + $pps->Type = $type; + $pps->Name = $name; + $pps->PrevPps = $this->_readInt4($fh); // Left Sibling ID + $pps->NextPps = $this->_readInt4($fh); // Right Sibling ID + $pps->DirPps = $this->_readInt4($fh); // Child ID + fseek($fh, 20, SEEK_CUR); // skip CLSID (16 bytes) + State Bits + $pps->Time1st = OLE::OLE2LocalDate(fread($fh, 8)); + $pps->Time2nd = OLE::OLE2LocalDate(fread($fh, 8)); + $pps->_StartBlock = $this->_readInt4($fh); + $pps->Size = $this->_readInt4($fh); + $pps->No = count($this->_list); + $this->_list[] = $pps; + + if ($type == OLE_PPS_TYPE_ROOT) { + $this->_small_handle = $this->getStream($pps->_StartBlock); + } + + // check if the PPS tree (starting from root) is complete + if (isset($this->root) && + $this->_ppsTreeComplete($this->root->No)) { + + break; + } + } + fclose($fh); + + // Initialize $pps->children on directories + foreach ($this->_list as $pps) { + if ($pps->Type == OLE_PPS_TYPE_DIR || $pps->Type == OLE_PPS_TYPE_ROOT) { + $nos = array($pps->DirPps); + $pps->children = array(); + while ($nos) { + $no = array_pop($nos); + if ($no != OLE_FREESECT) { + $childPps = $this->_list[$no]; + $nos[] = $childPps->PrevPps; + $nos[] = $childPps->NextPps; + $pps->children[] = $childPps; + } + } + } + } + + return true; + } + + /** + * It checks whether the PPS tree is complete (all PPS's read) + * starting with the given PPS (not necessarily root) + * + * @access private + * @param integer $index The index of the PPS from which we are checking + * @return boolean Whether the PPS tree for the given PPS is complete + */ + function _ppsTreeComplete($index) + { + return isset($this->_list[$index]) && + ($pps = $this->_list[$index]) && + ($pps->PrevPps == OLE_FREESECT || + $this->_ppsTreeComplete($pps->PrevPps)) && + ($pps->NextPps == OLE_FREESECT || + $this->_ppsTreeComplete($pps->NextPps)) && + ($pps->DirPps == OLE_FREESECT || + $this->_ppsTreeComplete($pps->DirPps)); + } + + /** + * Checks whether a PPS is a File PPS or not. + * If there is no PPS for the index given, it will return false. + * @param integer $index The index for the PPS + * @return bool true if it's a File PPS, false otherwise + * @access public + */ + function isFile($index) + { + if (isset($this->_list[$index])) { + return ($this->_list[$index]->Type == OLE_PPS_TYPE_FILE); + } + return false; + } + + /** + * Checks whether a PPS is a Root PPS or not. + * If there is no PPS for the index given, it will return false. + * @param integer $index The index for the PPS. + * @return bool true if it's a Root PPS, false otherwise + * @access public + */ + function isRoot($index) + { + if (isset($this->_list[$index])) { + return ($this->_list[$index]->Type == OLE_PPS_TYPE_ROOT); + } + return false; + } + + /** + * Gives the total number of PPS's found in the OLE container. + * @return integer The total number of PPS's found in the OLE container + * @access public + */ + function ppsTotal() + { + return count($this->_list); + } + + /** + * Gets data from a PPS + * If there is no PPS for the index given, it will return an empty string. + * @param integer $index The index for the PPS + * @param integer $position The position from which to start reading + * (relative to the PPS) + * @param integer $length The amount of bytes to read (at most) + * @return string The binary string containing the data requested + * @access public + * @see OLE_PPS_File::getStream() + */ + function getData($index, $position, $length) + { + // if position is not valid return empty string + if (!isset($this->_list[$index]) || + $position >= $this->_list[$index]->Size || + $position < 0) { + + return ''; + } + $fh = $this->getStream($this->_list[$index]); + $data = stream_get_contents($fh, $length, $position); + fclose($fh); + return $data; + } + + /** + * Gets the data length from a PPS + * If there is no PPS for the index given, it will return 0. + * @param integer $index The index for the PPS + * @return integer The amount of bytes in data the PPS has + * @access public + */ + function getDataLength($index) + { + if (isset($this->_list[$index])) { + return $this->_list[$index]->Size; + } + return 0; + } + + /** + * Utility function to transform ASCII text to Unicode + * + * @access public + * @static + * @param string $ascii The ASCII string to transform + * @return string The string in Unicode + */ + static function Asc2Ucs($ascii) + { + $rawname = ''; + for ($i = 0; $i < strlen($ascii); $i++) { + $rawname .= $ascii[$i] . "\x00"; + } + return $rawname; + } + + /** + * Utility function + * Returns a string for the OLE container with the date given + * + * @access public + * @static + * @param integer $date A timestamp + * @return string The string for the OLE container + */ + static function LocalDate2OLE($date = null) + { + if (!isset($date)) { + return "\x00\x00\x00\x00\x00\x00\x00\x00"; + } + + // factor used for separating numbers into 4 bytes parts + $factor = pow(2, 32); + + // days from 1-1-1601 until the beggining of UNIX era + $days = 134774; + // calculate seconds + $big_date = $days * 24 * 3600 + + gmmktime(date("H",$date),date("i",$date),date("s",$date), + date("m",$date),date("d",$date),date("Y",$date)); + // multiply just to make MS happy + $big_date *= 10000000; + + $high_part = floor($big_date / $factor); + // lower 4 bytes + $low_part = floor((($big_date / $factor) - $high_part) * $factor); + + // Make HEX string + $res = ''; + + for ($i = 0; $i < 4; $i++) { + $hex = $low_part % 0x100; + $res .= pack('c', $hex); + $low_part /= 0x100; + } + for ($i = 0; $i < 4; $i++) { + $hex = $high_part % 0x100; + $res .= pack('c', $hex); + $high_part /= 0x100; + } + return $res; + } + + /** + * Returns a timestamp from an OLE container's date + * @param integer $string A binary string with the encoded date + * @return string The timestamp corresponding to the string + * @access public + * @static + */ + static function OLE2LocalDate($string) + { + if (strlen($string) != 8) { + return new PEAR_Error("Expecting 8 byte string"); + } + + // factor used for separating numbers into 4 bytes parts + $factor = pow(2,32); + $high_part = 0; + for ($i = 0; $i < 4; $i++) { + list(, $high_part) = unpack('C', $string[(7 - $i)]); + if ($i < 3) { + $high_part *= 0x100; + } + } + $low_part = 0; + for ($i = 4; $i < 8; $i++) { + list(, $low_part) = unpack('C', $string[(7 - $i)]); + if ($i < 7) { + $low_part *= 0x100; + } + } + $big_date = ($high_part * $factor) + $low_part; + // translate to seconds + $big_date /= 10000000; + + // days from 1-1-1601 until the beggining of UNIX era + $days = 134774; + + // translate to seconds from beggining of UNIX era + $big_date -= $days * 24 * 3600; + return floor($big_date); + } +} diff --git a/vendor/pear/ole/OLE/ChainedBlockStream.php b/vendor/pear/ole/OLE/ChainedBlockStream.php new file mode 100644 index 00000000..353f36d5 --- /dev/null +++ b/vendor/pear/ole/OLE/ChainedBlockStream.php @@ -0,0 +1,246 @@ + + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id$ + * @link http://pear.php.net/package/OLE + * @since File available since Release 0.6.0 + */ + +if (!class_exists('PEAR')) { + require_once 'PEAR.php'; +} + +if (!class_exists('OLE')) { + require_once 'OLE.php'; +} + + +/** + * Stream wrapper for reading data stored in an OLE file. Implements methods + * for PHP's stream_wrapper_register(). For creating streams using this + * wrapper, use OLE_PPS_File::getStream(). + * + * @category Structures + * @package OLE + * @author Christian Schmidt + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: @package_version@ + * @link http://pear.php.net/package/OLE + * @since Class available since Release 0.6.0 + */ +class OLE_ChainedBlockStream extends PEAR +{ + /** + * The OLE container of the file that is being read. + * @var OLE + */ + var $ole; + + /** + * Parameters specified by fopen(). + * @var array + */ + var $params; + + /** + * The binary data of the file. + * @var string + */ + var $data; + + /** + * The file pointer. + * @var int byte offset + */ + var $pos; + + /** + * Implements support for fopen(). + * For creating streams using this wrapper, use OLE_PPS_File::getStream(). + * @param string resource name including scheme, e.g. + * ole-chainedblockstream://oleInstanceId=1 + * @param string only "r" is supported + * @param int mask of STREAM_REPORT_ERRORS and STREAM_USE_PATH + * @param string absolute path of the opened stream (out parameter) + * @return bool true on success + */ + function stream_open($path, $mode, $options, &$openedPath) + { + if ($mode != 'r') { + if ($options & STREAM_REPORT_ERRORS) { + trigger_error('Only reading is supported', E_USER_WARNING); + } + return false; + } + + // 25 is length of "ole-chainedblockstream://" + parse_str(substr($path, 25), $this->params); + if (!isset($this->params['oleInstanceId'], + $this->params['blockId'], + $GLOBALS['_OLE_INSTANCES'][$this->params['oleInstanceId']])) { + + if ($options & STREAM_REPORT_ERRORS) { + trigger_error('OLE stream not found', E_USER_WARNING); + } + return false; + } + $this->ole = $GLOBALS['_OLE_INSTANCES'][$this->params['oleInstanceId']]; + + $blockId = $this->params['blockId']; + $this->data = ''; + if (isset($this->params['size']) && + $this->params['size'] < $this->ole->bigBlockThreshold && + $blockId != $this->ole->root->_StartBlock) { + + // Block id refers to small blocks + $rootPos = 0; + while ($blockId != OLE_ENDOFCHAIN) { + $pos = $rootPos + $blockId * $this->ole->smallBlockSize; + + $blockId = $this->ole->sbat[$blockId]; + fseek($this->ole->_small_handle, $pos); + $this->data .= fread($this->ole->_small_handle, $this->ole->smallBlockSize); + } + } else { + // Block id refers to big blocks + while ($blockId != OLE_ENDOFCHAIN) { + $pos = $this->ole->_getBlockOffset($blockId); + fseek($this->ole->_file_handle, $pos); + $this->data .= fread($this->ole->_file_handle, $this->ole->bigBlockSize); + $blockId = $this->ole->bbat[$blockId]; + } + } + if (isset($this->params['size'])) { + $this->data = substr($this->data, 0, $this->params['size']); + } + + if ($options & STREAM_USE_PATH) { + $openedPath = $path; + } + + return true; + } + + /** + * Implements support for fclose(). + */ + function stream_close() + { + $this->ole = null; + + // $GLOBALS is not always defined in stream_close + if (isset($GLOBALS['_OLE_INSTANCES'])) { + unset($GLOBALS['_OLE_INSTANCES']); + } + } + + /** + * Implements support for fread(), fgets() etc. + * @param int maximum number of bytes to read + * @return string + */ + function stream_read($count) + { + if ($this->stream_eof()) { + return false; + } + $s = substr($this->data, $this->pos, $count); + $this->pos += $count; + return $s; + } + + /** + * Implements support for feof(). + * @return bool TRUE if the file pointer is at EOF; otherwise FALSE + */ + function stream_eof() + { + $eof = $this->pos >= strlen($this->data); + // Workaround for bug in PHP 5.0.x: http://bugs.php.net/27508 + if (version_compare(PHP_VERSION, '5.0', '>=') && + version_compare(PHP_VERSION, '5.1', '<')) { + + $eof = !$eof; + } + return $eof; + } + + /** + * Returns the position of the file pointer, i.e. its offset into the file + * stream. Implements support for ftell(). + * @return int + */ + function stream_tell() + { + return $this->pos; + } + + /** + * Implements support for fseek(). + * @param int byte offset + * @param int SEEK_SET, SEEK_CUR or SEEK_END + * @return bool + */ + function stream_seek($offset, $whence) + { + if ($whence == SEEK_SET && $offset >= 0) { + $this->pos = $offset; + } elseif ($whence == SEEK_CUR && -$offset <= $this->pos) { + $this->pos += $offset; + } elseif ($whence == SEEK_END && -$offset <= strlen($this->data)) { + $this->pos = strlen($this->data) + $offset; + } else { + return false; + } + return true; + } + + /** + * Implements support for fstat(). Currently the only supported field is + * "size". + * @return array + */ + function stream_stat() + { + return array( + 'size' => strlen($this->data), + ); + } + + /** + * PHP 5.6 for some reason wants this to be implemented. Currently returning false as if it wasn't implemented. + * @return boolean + */ + function stream_flush() + { + // If not implemented, FALSE is assumed as the return value. + return false; + } + + // Methods used by stream_wrapper_register() that are not implemented: + // int stream_write ( string data ) + // bool rename ( string path_from, string path_to ) + // bool mkdir ( string path, int mode, int options ) + // bool rmdir ( string path, int options ) + // bool dir_opendir ( string path, int options ) + // array url_stat ( string path, int flags ) + // string dir_readdir ( void ) + // bool dir_rewinddir ( void ) + // bool dir_closedir ( void ) +} diff --git a/vendor/pear/ole/OLE/PPS.php b/vendor/pear/ole/OLE/PPS.php new file mode 100644 index 00000000..e83719e4 --- /dev/null +++ b/vendor/pear/ole/OLE/PPS.php @@ -0,0 +1,244 @@ + | +// | Based on OLE::Storage_Lite by Kawai, Takanori | +// +----------------------------------------------------------------------+ +// +// $Id$ + + +if (!class_exists('PEAR')) { + require_once 'PEAR.php'; +} + +if (!class_exists('OLE')) { + require_once 'OLE.php'; +} + +/** +* Class for creating PPS's for OLE containers +* +* @author Xavier Noguer +* @category Structures +* @package OLE +*/ +class OLE_PPS extends PEAR +{ + /** + * The PPS index + * @var integer + */ + var $No; + + /** + * The PPS name (in Unicode) + * @var string + */ + var $Name; + + /** + * The PPS type. Dir, Root or File + * @var integer + */ + var $Type; + + /** + * The index of the previous PPS + * @var integer + */ + var $PrevPps; + + /** + * The index of the next PPS + * @var integer + */ + var $NextPps; + + /** + * The index of it's first child if this is a Dir or Root PPS + * @var integer + */ + var $DirPps; + + /** + * A timestamp + * @var integer + */ + var $Time1st; + + /** + * A timestamp + * @var integer + */ + var $Time2nd; + + /** + * Starting block (small or big) for this PPS's data inside the container + * @var integer + */ + var $_StartBlock; + + /** + * The size of the PPS's data (in bytes) + * @var integer + */ + var $Size; + + /** + * The PPS's data (only used if it's not using a temporary file) + * @var string + */ + var $_data; + + /** + * Array of child PPS's (only used by Root and Dir PPS's) + * @var array + */ + var $children = array(); + + /** + * Pointer to OLE container + * @var OLE + */ + var $ole; + + /** + * The constructor + * + * @access public + * @param integer $No The PPS index + * @param string $name The PPS name + * @param integer $type The PPS type. Dir, Root or File + * @param integer $prev The index of the previous PPS + * @param integer $next The index of the next PPS + * @param integer $dir The index of it's first child if this is a Dir or Root PPS + * @param integer $time_1st A timestamp + * @param integer $time_2nd A timestamp + * @param string $data The (usually binary) source data of the PPS + * @param array $children Array containing children PPS for this PPS + */ + function __construct($No, $name, $type, $prev, $next, $dir, $time_1st, $time_2nd, $data, $children) + { + $this->No = $No; + $this->Name = $name; + $this->Type = $type; + $this->PrevPps = $prev; + $this->NextPps = $next; + $this->DirPps = $dir; + $this->Time1st = $time_1st; + $this->Time2nd = $time_2nd; + $this->_data = $data; + $this->children = $children; + if ($data != '') { + $this->Size = strlen($data); + } else { + $this->Size = 0; + } + } + + /** + * Returns the amount of data saved for this PPS + * + * @access private + * @return integer The amount of data (in bytes) + */ + function _DataLen() + { + if (!isset($this->_data)) { + return 0; + } + if (isset($this->_PPS_FILE)) { + fseek($this->_PPS_FILE, 0); + $stats = fstat($this->_PPS_FILE); + return $stats[7]; + } else { + return strlen($this->_data); + } + } + + /** + * Returns a string with the PPS's WK (What is a WK?) + * + * @access private + * @return string The binary string + */ + function _getPpsWk() + { + $ret = $this->Name; + for ($i = 0; $i < (64 - strlen($this->Name)); $i++) { + $ret .= "\x00"; + } + $ret .= pack("v", strlen($this->Name) + 2) // 66 + . pack("c", $this->Type) // 67 + . pack("c", 0x00) //UK // 68 + . pack("V", $this->PrevPps) //Prev // 72 + . pack("V", $this->NextPps) //Next // 76 + . pack("V", $this->DirPps) //Dir // 80 + . "\x00\x09\x02\x00" // 84 + . "\x00\x00\x00\x00" // 88 + . "\xc0\x00\x00\x00" // 92 + . "\x00\x00\x00\x46" // 96 // Seems to be ok only for Root + . "\x00\x00\x00\x00" // 100 + . OLE::LocalDate2OLE($this->Time1st) // 108 + . OLE::LocalDate2OLE($this->Time2nd) // 116 + . pack("V", isset($this->_StartBlock)? + $this->_StartBlock:0) // 120 + . pack("V", $this->Size) // 124 + . pack("V", 0); // 128 + return $ret; + } + + /** + * Updates index and pointers to previous, next and children PPS's for this + * PPS. I don't think it'll work with Dir PPS's. + * + * @access private + * @param array &$pps_array Reference to the array of PPS's for the whole OLE + * container + * @return integer The index for this PPS + */ + static function _savePpsSetPnt(&$raList, $to_save, $depth = 0) + { + if ( !is_array($to_save) || (count($to_save) == 0) ) { + return OLE_FREESECT; + } + elseif( count($to_save) == 1 ) { + $cnt = count($raList); + // If the first entry, it's the root... Don't clone it! + $raList[$cnt] = ( $depth == 0 ) ? $to_save[0] : clone $to_save[0]; + $raList[$cnt]->No = $cnt; + $raList[$cnt]->PrevPps = OLE_FREESECT; + $raList[$cnt]->NextPps = OLE_FREESECT; + $raList[$cnt]->DirPps = self::_savePpsSetPnt($raList, @$raList[$cnt]->children, $depth++); + return $cnt; + } + else { + $iPos = floor(count($to_save) / 2); + $aPrev = array_slice($to_save, 0, $iPos); + $aNext = array_slice($to_save, $iPos + 1); + + $cnt = count($raList); + // If the first entry, it's the root... Don't clone it! + $raList[$cnt] = ( $depth == 0 ) ? $to_save[$iPos] : clone $to_save[$iPos]; + $raList[$cnt]->No = $cnt; + $raList[$cnt]->PrevPps = self::_savePpsSetPnt($raList, $aPrev, $depth++); + $raList[$cnt]->NextPps = self::_savePpsSetPnt($raList, $aNext, $depth++); + $raList[$cnt]->DirPps = self::_savePpsSetPnt($raList, @$raList[$cnt]->children, $depth++); + + return $cnt; + } + } +} diff --git a/vendor/pear/ole/OLE/PPS/File.php b/vendor/pear/ole/OLE/PPS/File.php new file mode 100644 index 00000000..a08856b3 --- /dev/null +++ b/vendor/pear/ole/OLE/PPS/File.php @@ -0,0 +1,130 @@ + | +// | Based on OLE::Storage_Lite by Kawai, Takanori | +// +----------------------------------------------------------------------+ +// +// $Id$ + + +if (!class_exists('OLE_PPS')) { + require_once 'OLE/PPS.php'; +} + +if (!class_exists('System')) { + require_once 'System.php'; +} + +/** +* Class for creating File PPS's for OLE containers +* +* @author Xavier Noguer +* @category Structures +* @package OLE +*/ +class OLE_PPS_File extends OLE_PPS +{ + /** + * The temporary dir for storing the OLE file + * @var string + */ + var $_tmp_dir; + + /** + * The constructor + * + * @access public + * @param string $name The name of the file (in Unicode) + * @see OLE::Asc2Ucs() + */ + function __construct($name) + { + $system = new System(); + $this->_tmp_dir = $system->tmpdir(); + parent::__construct( + null, + $name, + OLE_PPS_TYPE_FILE, + null, + null, + null, + null, + null, + '', + array()); + } + + /** + * Sets the temp dir used for storing the OLE file + * + * @access public + * @param string $dir The dir to be used as temp dir + * @return boolean true if given dir is valid, false otherwise + */ + function setTempDir($dir) + { + if (is_dir($dir)) { + $this->_tmp_dir = $dir; + return true; + } + return false; + } + + /** + * Initialization method. Has to be called right after OLE_PPS_File(). + * + * @access public + * @return mixed true on success. PEAR_Error on failure + */ + function init() + { + $this->_tmp_filename = tempnam($this->_tmp_dir, "OLE_PPS_File"); + $fh = @fopen($this->_tmp_filename, "w+b"); + if ($fh == false) { + return $this->raiseError("Can't create temporary file"); + } + $this->_PPS_FILE = $fh; + if ($this->_PPS_FILE) { + fseek($this->_PPS_FILE, 0); + } + + return true; + } + + /** + * Append data to PPS + * + * @access public + * @param string $data The data to append + */ + function append($data) + { + if ($this->_PPS_FILE) { + fwrite($this->_PPS_FILE, $data); + } else { + $this->_data .= $data; + } + } + + /** + * Returns a stream for reading this file using fread() etc. + * @return resource a read-only stream + */ + function getStream() + { + $this->ole->getStream($this); + } +} diff --git a/vendor/pear/ole/OLE/PPS/Root.php b/vendor/pear/ole/OLE/PPS/Root.php new file mode 100644 index 00000000..a2e423ff --- /dev/null +++ b/vendor/pear/ole/OLE/PPS/Root.php @@ -0,0 +1,724 @@ + | +// | Based on OLE::Storage_Lite by Kawai, Takanori | +// +----------------------------------------------------------------------+ +// +// $Id$ + +if (!class_exists('OLE_PPS')) { + require_once 'OLE/PPS.php'; +} + +if (!class_exists('System')) { + require_once 'System.php'; +} + +/** +* Class for creating Root PPS's for OLE containers +* +* @author Xavier Noguer +* @category Structures +* @package OLE +*/ +class OLE_PPS_Root extends OLE_PPS +{ + /** + * Flag to enable new logic + * @var bool + */ + var $new_func = true; + + /** + * The temporary dir for storing the OLE file + * @var string + */ + var $_tmp_dir; + + /** + * Constructor + * + * @access public + * @param integer $time_1st A timestamp + * @param integer $time_2nd A timestamp + */ + function __construct($time_1st, $time_2nd, $raChild) + { + $system = new System(); + $this->_tmp_dir = $system->tmpdir(); + parent::__construct( + null, + OLE::Asc2Ucs('Root Entry'), + OLE_PPS_TYPE_ROOT, + null, + null, + null, + $time_1st, + $time_2nd, + null, + $raChild); + } + + /** + * Sets the temp dir used for storing the OLE file + * + * @access public + * @param string $dir The dir to be used as temp dir + * @return true if given dir is valid, false otherwise + */ + function setTempDir($dir) + { + if (is_dir($dir)) { + $this->_tmp_dir = $dir; + return true; + } + return false; + } + + /** + * Method for saving the whole OLE container (including files). + * In fact, if called with an empty argument (or '-'), it saves to a + * temporary file and then outputs it's contents to stdout. + * + * @param string $filename The name of the file where to save the OLE container + * @access public + * @return mixed true on success, PEAR_Error on failure + */ + function save($filename) + { + // Initial Setting for saving + $this->_BIG_BLOCK_SIZE = pow(2, + ((isset($this->_BIG_BLOCK_SIZE))? $this->_adjust2($this->_BIG_BLOCK_SIZE) : 9)); + $this->_SMALL_BLOCK_SIZE= pow(2, + ((isset($this->_SMALL_BLOCK_SIZE))? $this->_adjust2($this->_SMALL_BLOCK_SIZE): 6)); + + // Open temp file if we are sending output to stdout + if (($filename == '-') || ($filename == '')) { + $this->_tmp_filename = tempnam($this->_tmp_dir, "OLE_PPS_Root"); + $this->_FILEH_ = @fopen($this->_tmp_filename,"w+b"); + if ($this->_FILEH_ == false) { + return $this->raiseError("Can't create temporary file."); + } + } else { + $this->_FILEH_ = @fopen($filename, "wb"); + if ($this->_FILEH_ == false) { + return $this->raiseError("Can't open $filename. It may be in use or protected."); + } + } + // Make an array of PPS's (for Save) + $aList = array(); + OLE_PPS_Root::_savePpsSetPnt($aList, array($this)); + // calculate values for header + list($iSBDcnt, $iBBcnt, $iPPScnt) = $this->_calcSize($aList); //, $rhInfo); + // Save Header + $this->_saveHeader($iSBDcnt, $iBBcnt, $iPPScnt); + + // Make Small Data string (write SBD) + $this->_data = $this->_makeSmallData($aList); + + // Write BB + $this->_saveBigData($iSBDcnt, $aList); + // Write PPS + $this->_savePps($aList); + // Write Big Block Depot and BDList and Adding Header informations + $this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt); + // Close File, send it to stdout if necessary + if (($filename == '-') || ($filename == '')) { + fseek($this->_FILEH_, 0); + fpassthru($this->_FILEH_); + @fclose($this->_FILEH_); + // Delete the temporary file. + @unlink($this->_tmp_filename); + } else { + @fclose($this->_FILEH_); + } + + return true; + } + + /** + * Calculate some numbers + * + * @access private + * @param array $raList Reference to an array of PPS's + * @return array The array of numbers + */ + function _calcSize(&$raList) + { + // Calculate Basic Setting + $iBBcnt = 0; + $iSBcnt = 0; + for ($i = 0; $i < count($raList); $i++) { + if ($raList[$i]->Type == OLE_PPS_TYPE_FILE) { + $raList[$i]->Size = $raList[$i]->_DataLen(); + if ($raList[$i]->Size < OLE_DATA_SIZE_SMALL) { + $iSBcnt += floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE) + + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0); + } else { + $iBBcnt += (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) + + (($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0)); + } + } + } + $iSmallLen = $iSBcnt * $this->_SMALL_BLOCK_SIZE; + $iSlCnt = floor($this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE); + $iSBDcnt = floor($iSBcnt / $iSlCnt) + (($iSBcnt % $iSlCnt)? 1:0); + $iBBcnt += (floor($iSmallLen / $this->_BIG_BLOCK_SIZE) + + (( $iSmallLen % $this->_BIG_BLOCK_SIZE)? 1: 0)); + $iCnt = count($raList); + $iBdCnt = $this->_BIG_BLOCK_SIZE / OLE_PPS_SIZE; + $iPPScnt = (floor($iCnt/$iBdCnt) + (($iCnt % $iBdCnt)? 1: 0)); + + return array($iSBDcnt, $iBBcnt, $iPPScnt); + } + + /** + * Helper function for caculating a magic value for block sizes + * + * @access private + * @param integer $i2 The argument + * @see save() + * @return integer + */ + function _adjust2($i2) + { + $iWk = log($i2)/log(2); + return ($iWk > floor($iWk))? floor($iWk)+1:$iWk; + } + + /** + * Save OLE header + * + * @access private + * @param integer $iSBDcnt + * @param integer $iBBcnt + * @param integer $iPPScnt + */ + function _saveHeader($iSBDcnt, $iBBcnt, $iPPScnt) + { + $FILE = $this->_FILEH_; + + if($this->new_func) + return $this->_create_header($iSBDcnt, $iBBcnt, $iPPScnt); + + // Calculate Basic Setting + $iBlCnt = $this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE; + $i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / OLE_LONG_INT_SIZE; + + $iBdExL = 0; + $iAll = $iBBcnt + $iPPScnt + $iSBDcnt; + $iAllW = $iAll; + $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0); + $iBdCnt = floor(($iAll + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0); + + // Calculate BD count + if ($iBdCnt > $i1stBdL) { + while (1) { + $iBdExL++; + $iAllW++; + $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0); + $iBdCnt = floor(($iAllW + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0); + if ($iBdCnt <= ($iBdExL*$iBlCnt+ $i1stBdL)) { + break; + } + } + } + + // Save Header + fwrite($FILE, + OLE_CFB_SIGNATURE // Header Signature (8 bytes) + . "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // Header CLSID (16 bytes) + . pack("v", OLE_VERSION_MINOR) // Minor Version (2 bytes) + . pack("v", OLE_VERSION_MAJOR_3) // Major Version (2 bytes) + . pack("v", OLE_LITTLE_ENDIAN) // Byte Order (2 bytes) + . pack("v", OLE_SECTOR_SHIFT_3) // Sector Shift (2 bytes) + . pack("v", OLE_MINI_SECTOR_SHIFT) // Mini Sector Shift (2 bytes) + . "\x00\x00\x00\x00\x00\x00" // Reserved (6 bytes) + . "\x00\x00\x00\x00" // Number of Directory Sectors (4 bytes) + . pack("V", $iBdCnt) // Number of FAT Sectors (4 bytes) + . pack("V", $iBBcnt+$iSBDcnt) //ROOT START, First Directory Sector Location (4 bytes) + . pack("V", 0) // Transaction Signature Number (4 bytes) + . pack("V", 0x00001000) // Mini Stream Cutoff Size (4 bytes) + . pack("V", $iSBDcnt ? 0 : OLE_ENDOFCHAIN) // First Mini FAT Sector Location (4 bytes) + . pack("V", $iSBDcnt) // Number of Mini FAT Sectors (4 bytes) + ); + // Extra BDList Start, Count + if ($iBdCnt < $i1stBdL) { + fwrite($FILE, + pack("V", OLE_ENDOFCHAIN). // Extra BDList Start + pack("V", 0) // Extra BDList Count + ); + } else { + fwrite($FILE, pack("V", $iAll+$iBdCnt) . pack("V", $iBdExL)); + } + + // BDList + for ($i = 0; $i < $i1stBdL && $i < $iBdCnt; $i++) { + fwrite($FILE, pack("V", $iAll+$i)); + } + if ($i < $i1stBdL) { // free sectors + for ($j = 0; $j < ($i1stBdL-$i); $j++) { + fwrite($FILE, (pack("V", OLE_FREESECT))); + } + } + } + + /** + * Saving big data (PPS's with data bigger than OLE_DATA_SIZE_SMALL) + * + * @access private + * @param integer $iStBlk + * @param array &$raList Reference to array of PPS's + */ + function _saveBigData($iStBlk, &$raList) + { + $FILE = $this->_FILEH_; + + // cycle through PPS's + for ($i = 0; $i < count($raList); $i++) { + if ($raList[$i]->Type != OLE_PPS_TYPE_DIR) { + $raList[$i]->Size = $raList[$i]->_DataLen(); + if (($raList[$i]->Size >= OLE_DATA_SIZE_SMALL) || + (($raList[$i]->Type == OLE_PPS_TYPE_ROOT) && isset($raList[$i]->_data))) + { + // Write Data + if (isset($raList[$i]->_PPS_FILE)) { + $iLen = 0; + fseek($raList[$i]->_PPS_FILE, 0); // To The Top + while($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) { + $iLen += strlen($sBuff); + fwrite($FILE, $sBuff); + } + } else { + fwrite($FILE, $raList[$i]->_data); + } + + if ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE) { + for ($j = 0; $j < ($this->_BIG_BLOCK_SIZE - ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)); $j++) { + fwrite($FILE, "\x00"); + } + } + // Set For PPS + $raList[$i]->_StartBlock = $iStBlk; + $iStBlk += + (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) + + (($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0)); + } + // Close file for each PPS, and unlink it + if (isset($raList[$i]->_PPS_FILE)) { + @fclose($raList[$i]->_PPS_FILE); + $raList[$i]->_PPS_FILE = null; + @unlink($raList[$i]->_tmp_filename); + } + } + } + } + + /** + * get small data (PPS's with data smaller than OLE_DATA_SIZE_SMALL) + * + * @access private + * @param array &$raList Reference to array of PPS's + */ + function _makeSmallData(&$raList) + { + $sRes = ''; + $FILE = $this->_FILEH_; + $iSmBlk = 0; + + for ($i = 0; $i < count($raList); $i++) { + // Make SBD, small data string + if ($raList[$i]->Type == OLE_PPS_TYPE_FILE) { + if ($raList[$i]->Size <= 0) { + continue; + } + if ($raList[$i]->Size < OLE_DATA_SIZE_SMALL) { + $iSmbCnt = floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE) + + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0); + // Add to SBD + for ($j = 0; $j < ($iSmbCnt-1); $j++) { + fwrite($FILE, pack("V", $j+$iSmBlk+1)); + } + fwrite($FILE, pack("V", OLE_ENDOFCHAIN)); + + // Add to Data String(this will be written for RootEntry) + if ($raList[$i]->_PPS_FILE) { + fseek($raList[$i]->_PPS_FILE, 0); // To The Top + while ($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) { + $sRes .= $sBuff; + } + } else { + $sRes .= $raList[$i]->_data; + } + if ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE) { + for ($j = 0; $j < ($this->_SMALL_BLOCK_SIZE - ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)); $j++) { + $sRes .= "\x00"; + } + } + // Set for PPS + $raList[$i]->_StartBlock = $iSmBlk; + $iSmBlk += $iSmbCnt; + } + } + } + $iSbCnt = floor($this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE); + if ($iSmBlk % $iSbCnt) { + for ($i = 0; $i < ($iSbCnt - ($iSmBlk % $iSbCnt)); $i++) { + fwrite($FILE, pack("V", OLE_FREESECT)); + } + } + return $sRes; + } + + /** + * Saves all the PPS's WKs + * + * @access private + * @param array $raList Reference to an array with all PPS's + */ + function _savePps(&$raList) + { + // Save each PPS WK + for ($i = 0; $i < count($raList); $i++) { + fwrite($this->_FILEH_, $raList[$i]->_getPpsWk()); + } + // Adjust for Block + $iCnt = count($raList); + $iBCnt = $this->_BIG_BLOCK_SIZE / OLE_PPS_SIZE; + if ($iCnt % $iBCnt) { + for ($i = 0; $i < (($iBCnt - ($iCnt % $iBCnt)) * OLE_PPS_SIZE); $i++) { + fwrite($this->_FILEH_, "\x00"); + } + } + } + + /** + * Saving Big Block Depot + * + * @access private + * @param integer $iSbdSize + * @param integer $iBsize + * @param integer $iPpsCnt + */ + function _saveBbd($iSbdSize, $iBsize, $iPpsCnt) + { + if($this->new_func) + return $this->_create_big_block_chain($iSbdSize, $iBsize, $iPpsCnt); + + $FILE = $this->_FILEH_; + // Calculate Basic Setting + $iBbCnt = $this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE; + $i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / OLE_LONG_INT_SIZE; + + $iBdExL = 0; + $iAll = $iBsize + $iPpsCnt + $iSbdSize; + $iAllW = $iAll; + $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0); + $iBdCnt = floor(($iAll + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0); + // Calculate BD count + if ($iBdCnt >$i1stBdL) { + while (1) { + $iBdExL++; + $iAllW++; + $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0); + $iBdCnt = floor(($iAllW + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0); + if ($iBdCnt <= ($iBdExL*$iBbCnt+ $i1stBdL)) { + break; + } + } + } + + // Making BD + // Set for SBD + if ($iSbdSize > 0) { + for ($i = 0; $i < ($iSbdSize - 1); $i++) { + fwrite($FILE, pack("V", $i+1)); + } + fwrite($FILE, pack("V", OLE_ENDOFCHAIN)); + } + // Set for B + for ($i = 0; $i < ($iBsize - 1); $i++) { + fwrite($FILE, pack("V", $i+$iSbdSize+1)); + } + fwrite($FILE, pack("V", OLE_ENDOFCHAIN)); + + // Set for PPS + for ($i = 0; $i < ($iPpsCnt - 1); $i++) { + fwrite($FILE, pack("V", $i+$iSbdSize+$iBsize+1)); + } + fwrite($FILE, pack("V", OLE_ENDOFCHAIN)); + // Set for BBD itself ( 0xFFFFFFFD : BBD) + for ($i = 0; $i < $iBdCnt; $i++) { + fwrite($FILE, pack("V", OLE_FATSECT)); + } + // Set for ExtraBDList + for ($i = 0; $i < $iBdExL; $i++) { + fwrite($FILE, pack("V", OLE_DIFSECT)); + } + // Adjust for Block + if (($iAllW + $iBdCnt) % $iBbCnt) { + for ($i = 0; $i < ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt)); $i++) { + fwrite($FILE, pack("V", OLE_FREESECT)); + } + } + // Extra BDList + if ($iBdCnt > $i1stBdL) { + $iN=0; + $iNb=0; + for ($i = $i1stBdL;$i < $iBdCnt; $i++, $iN++) { + if ($iN >= ($iBbCnt - 1)) { + $iN = 0; + $iNb++; + fwrite($FILE, pack("V", $iAll+$iBdCnt+$iNb)); + } + fwrite($FILE, pack("V", $iBsize+$iSbdSize+$iPpsCnt+$i)); + } + if (($iBdCnt-$i1stBdL) % ($iBbCnt-1)) { + for ($i = 0; $i < (($iBbCnt - 1) - (($iBdCnt - $i1stBdL) % ($iBbCnt - 1))); $i++) { + fwrite($FILE, pack("V", OLE_FREESECT)); + } + } + fwrite($FILE, pack("V", OLE_ENDOFCHAIN)); + } + } + + + + /** + * New method to store Bigblock chain + * + * @access private + * @param integer $num_sb_blocks - number of Smallblock depot blocks + * @param integer $num_bb_blocks - number of Bigblock depot blocks + * @param integer $num_pps_blocks - number of PropertySetStorage blocks + */ + function _create_big_block_chain($num_sb_blocks, $num_bb_blocks, $num_pps_blocks) + { + $FILE = $this->_FILEH_; + + $bbd_info = $this->_calculate_big_block_chain($num_sb_blocks, $num_bb_blocks, $num_pps_blocks); + + $data = ""; + + if($num_sb_blocks > 0) + { + for($i = 0; $i<($num_sb_blocks-1); $i++) + $data .= pack("V", $i+1); + $data .= pack("V", OLE_ENDOFCHAIN); + } + + for($i = 0; $i<($num_bb_blocks-1); $i++) + $data .= pack("V", $i + $num_sb_blocks + 1); + $data .= pack("V", OLE_ENDOFCHAIN); + + for($i = 0; $i<($num_pps_blocks-1); $i++) + $data .= pack("V", $i + $num_sb_blocks + $num_bb_blocks + 1); + $data .= pack("V", OLE_ENDOFCHAIN); + + for($i = 0; $i < $bbd_info["0xFFFFFFFD_blockchain_entries"]; $i++) + $data .= pack("V", OLE_FATSECT); + + for($i = 0; $i < $bbd_info["0xFFFFFFFC_blockchain_entries"]; $i++) + $data .= pack("V", OLE_DIFSECT); + + // Adjust for Block + $all_entries = $num_sb_blocks + $num_bb_blocks + $num_pps_blocks + $bbd_info["0xFFFFFFFD_blockchain_entries"] + $bbd_info["0xFFFFFFFC_blockchain_entries"]; + if($all_entries % $bbd_info["entries_per_block"]) + { + $rest = $bbd_info["entries_per_block"] - ($all_entries % $bbd_info["entries_per_block"]); + for($i = 0; $i < $rest; $i++) + $data .= pack("V", OLE_FREESECT); + } + + // Extra BDList + if($bbd_info["blockchain_list_entries"] > $bbd_info["header_blockchain_list_entries"]) + { + $iN=0; + $iNb=0; + for($i = $bbd_info["header_blockchain_list_entries"]; $i < $bbd_info["blockchain_list_entries"]; $i++, $iN++) + { + if($iN >= ($bbd_info["entries_per_block"]-1)) + { + $iN = 0; + $iNb++; + $data .= pack("V", $num_sb_blocks + $num_bb_blocks + $num_pps_blocks + $bbd_info["0xFFFFFFFD_blockchain_entries"] + $iNb); + } + + $data .= pack("V", $num_bb_blocks + $num_sb_blocks + $num_pps_blocks + $i); + } + + $all_entries = $bbd_info["blockchain_list_entries"] - $bbd_info["header_blockchain_list_entries"]; + if(($all_entries % ($bbd_info["entries_per_block"] - 1))) + { + $rest = ($bbd_info["entries_per_block"] - 1) - ($all_entries % ($bbd_info["entries_per_block"] - 1)); + for($i = 0; $i < $rest; $i++) + $data .= pack("V", OLE_FREESECT); + } + + $data .= pack("V", OLE_ENDOFCHAIN); + } + + /* + $this->dump($data, 0, strlen($data)); + die; + */ + + fwrite($FILE, $data); + } + + /** + * New method to store Header + * + * @access private + * @param integer $num_sb_blocks - number of Smallblock depot blocks + * @param integer $num_bb_blocks - number of Bigblock depot blocks + * @param integer $num_pps_blocks - number of PropertySetStorage blocks + */ + function _create_header($num_sb_blocks, $num_bb_blocks, $num_pps_blocks) + { + $FILE = $this->_FILEH_; + + $bbd_info = $this->_calculate_big_block_chain($num_sb_blocks, $num_bb_blocks, $num_pps_blocks); + + // Save Header + fwrite($FILE, + OLE_CFB_SIGNATURE // Header Signature (8 bytes) + . "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // Header CLSID (16 bytes) + . pack("v", OLE_VERSION_MINOR) // Minor Version (2 bytes) + . pack("v", OLE_VERSION_MAJOR_3) // Major Version (2 bytes) + . pack("v", OLE_LITTLE_ENDIAN) // Byte Order (2 bytes) + . pack("v", OLE_SECTOR_SHIFT_3) // Sector Shift (2 bytes) + . pack("v", OLE_MINI_SECTOR_SHIFT) // Mini Sector Shift (2 bytes) + . "\x00\x00\x00\x00\x00\x00" // Reserved (6 bytes) + . "\x00\x00\x00\x00" // Number of Directory Sectors (4 bytes) + . pack("V", $bbd_info["blockchain_list_entries"]) // Number of FAT Sectors (4 bytes) + . pack("V", $num_sb_blocks + $num_bb_blocks) //ROOT START, First Directory Sector Location (4 bytes) + . pack("V", 0) // Transaction Signature Number (4 bytes) + . pack("V", 0x00001000) // Mini Stream Cutoff Size (4 bytes) + . pack("V", $num_sb_blocks > 0 ? 0 : OLE_ENDOFCHAIN) // First Mini FAT Sector Location (4 bytes) + . pack("V", $num_sb_blocks) // Number of Mini FAT Sectors (4 bytes) + ); + + // Extra BDList Start, Count + if($bbd_info["blockchain_list_entries"] < $bbd_info["header_blockchain_list_entries"]) + { + fwrite($FILE, + pack("V", OLE_ENDOFCHAIN). // Extra BDList Start + pack("V", 0) // Extra BDList Count + ); + } + else + { + fwrite($FILE, pack("V", $num_sb_blocks + $num_bb_blocks + $num_pps_blocks + $bbd_info["0xFFFFFFFD_blockchain_entries"]) . pack("V", $bbd_info["0xFFFFFFFC_blockchain_entries"])); + } + + // BDList + for ($i=0; $i < $bbd_info["header_blockchain_list_entries"] and $i < $bbd_info["blockchain_list_entries"]; $i++) + { + fwrite($FILE, pack("V", $num_bb_blocks + $num_sb_blocks + $num_pps_blocks + $i)); + } + + if($i < $bbd_info["header_blockchain_list_entries"]) + { + for($j = 0; $j < ($bbd_info["header_blockchain_list_entries"]-$i); $j++) + { + fwrite($FILE, (pack("V", OLE_FREESECT))); + } + } + } + + /** + * New method to calculate Bigblock chain + * + * @access private + * @param integer $num_sb_blocks - number of Smallblock depot blocks + * @param integer $num_bb_blocks - number of Bigblock depot blocks + * @param integer $num_pps_blocks - number of PropertySetStorage blocks + */ + function _calculate_big_block_chain($num_sb_blocks, $num_bb_blocks, $num_pps_blocks) + { + $bbd_info["entries_per_block"] = $this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE; + $bbd_info["header_blockchain_list_entries"] = ($this->_BIG_BLOCK_SIZE - 0x4C) / OLE_LONG_INT_SIZE; + $bbd_info["blockchain_entries"] = $num_sb_blocks + $num_bb_blocks + $num_pps_blocks; + $bbd_info["0xFFFFFFFD_blockchain_entries"] = $this->get_number_of_pointer_blocks($bbd_info["blockchain_entries"]); + $bbd_info["blockchain_list_entries"] = $this->get_number_of_pointer_blocks($bbd_info["blockchain_entries"] + $bbd_info["0xFFFFFFFD_blockchain_entries"]); + + // do some magic + $bbd_info["ext_blockchain_list_entries"] = 0; + $bbd_info["0xFFFFFFFC_blockchain_entries"] = 0; + if($bbd_info["blockchain_list_entries"] > $bbd_info["header_blockchain_list_entries"]) + { + do + { + $bbd_info["blockchain_list_entries"] = $this->get_number_of_pointer_blocks($bbd_info["blockchain_entries"] + $bbd_info["0xFFFFFFFD_blockchain_entries"] + $bbd_info["0xFFFFFFFC_blockchain_entries"]); + $bbd_info["ext_blockchain_list_entries"] = $bbd_info["blockchain_list_entries"] - $bbd_info["header_blockchain_list_entries"]; + $bbd_info["0xFFFFFFFC_blockchain_entries"] = $this->get_number_of_pointer_blocks($bbd_info["ext_blockchain_list_entries"]); + $bbd_info["0xFFFFFFFD_blockchain_entries"] = $this->get_number_of_pointer_blocks($num_sb_blocks + $num_bb_blocks + $num_pps_blocks + $bbd_info["0xFFFFFFFD_blockchain_entries"] + $bbd_info["0xFFFFFFFC_blockchain_entries"]); + } + while($bbd_info["blockchain_list_entries"] < $this->get_number_of_pointer_blocks($bbd_info["blockchain_entries"] + $bbd_info["0xFFFFFFFD_blockchain_entries"] + $bbd_info["0xFFFFFFFC_blockchain_entries"])); + } + + return $bbd_info; + } + + /** + * Calculates number of pointer blocks + * + * @access public + * @param integer $num_pointers - number of pointers + */ + function get_number_of_pointer_blocks($num_pointers) + { + $pointers_per_block = $this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE; + + return floor($num_pointers / $pointers_per_block) + (($num_pointers % $pointers_per_block)? 1: 0); + } + + /** + * Support method for some hexdumping + * + * @access public + * @param string $data - Binary data + * @param integer $from - Start offset of data to dump + * @param integer $to - Target offset of data to dump + */ + function dump($data, $from, $to) + { + $chars = array(); + for($i = $from; $i < $to; $i++) + { + if(sizeof($chars) == 16) + { + printf("%08X (% 12d) |", $i-16, $i-16); + foreach($chars as $char) + printf(" %02X", $char); + print " |\n"; + + $chars = array(); + } + + $chars[] = ord($data[$i]); + } + + if(sizeof($chars)) + { + printf("%08X (% 12d) |", $i-sizeof($chars), $i-sizeof($chars)); + foreach($chars as $char) + printf(" %02X", $char); + print " |\n"; + } + } +} diff --git a/vendor/pear/ole/README.md b/vendor/pear/ole/README.md new file mode 100644 index 00000000..3e961ee8 --- /dev/null +++ b/vendor/pear/ole/README.md @@ -0,0 +1,25 @@ +[![Build Status](https://travis-ci.org/pear/OLE.svg?branch=master)](https://travis-ci.org/pear/OLE) +[![Latest Stable Version](https://poser.pugx.org/pear/ole/v/stable)](https://packagist.org/packages/pear/ole) + +This package is http://pear.php.net/package/OLE and has been migrated from https://svn.php.net/repository/pear/packages/OLE + +Please report all new issues via the PEAR bug tracker. + +If this package is marked as unmaintained and you have fixes, please submit your pull requests and start discussion on the pear-qa mailing list. + +To test, run + + $ composer install + $ vendor/bin/phpunit + +To build, simply + + $ pear package + +To install from scratch + + $ pear install package.xml + +To upgrade + + $ pear upgrade -f package.xml diff --git a/vendor/pear/ole/composer.json b/vendor/pear/ole/composer.json new file mode 100644 index 00000000..64de9afa --- /dev/null +++ b/vendor/pear/ole/composer.json @@ -0,0 +1,45 @@ +{ + "name": "pear/ole", + "type": "library", + "description": "This package allows reading and writing of OLE (Object Linking and Embedding) compound documents. This format is used as container for Excel (.xls), Word (.doc) and other Microsoft file formats.", + "license": "PHP-3.01", + "authors": [ + { + "name": "Christian Schmidt", + "email": "schmidt@php.net", + "role": "Lead" + }, + { + "name": "Xavier Noguer", + "email": "xnoguer@php.net", + "role": "Lead" + } + ], + "require": { + "php": ">=5.6", + "pear/pear_exception": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2", + "pear/pear-core-minimal": "^1.10", + "phpunit/phpunit": ">=5 <10", + "sanmai/phpunit-legacy-adapter": "^6 || ^8" + }, + "autoload": { + "psr-0": { + "OLE": "./" + } + }, + "autoload-dev": { + "psr-0": { + "OLE": "tests/" + } + }, + "include-path": [ + "./" + ], + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=OLE", + "source": "https://github.com/pear/OLE" + } +} diff --git a/vendor/pear/ole/package.xml b/vendor/pear/ole/package.xml new file mode 100644 index 00000000..1f8d8d8a --- /dev/null +++ b/vendor/pear/ole/package.xml @@ -0,0 +1,212 @@ + + + OLE + pear.php.net + Package for reading and writing OLE containers + This package allows reading and writing of OLE (Object Linking and Embedding) compound documents. This format is used as container for Excel (.xls), Word (.doc) and other Microsoft file formats. + + Christian Schmidt + schmidt + schmidt@php.net + yes + + + Xavier Noguer + xnoguer + xnoguer@php.net + no + + 2017-06-20 + + 1.0.0RC3 + 1.0.0RC3 + + + beta + beta + + PHP + +Bug #19284: RC2 breaks header in excel files from Spreadsheet_Excel_Writer +Bug #21216: Call to undefined method PEAR::OLE_PPS() + + + + + + + + + + + + + + 5.0.0 + + + 1.4.0b1 + + + + + + + + 0.2.1 + 0.2.1 + + + alpha + alpha + + 2003-05-12 + PHP + +Fixing install dir + + + + + 0.3 + 0.3 + + + beta + beta + + 2003-08-21 + PHP + +-added OLE_PPS_File::init() initialization method. +-better error handling. + + + + + 0.4 + 0.4 + + + beta + beta + + 2003-09-25 + PHP + +-deleting tmp files (Herman Kuiper). +-fixed hardcoded tmp dir (Herman Kuiper). +-fixed pass by reference warning (Herman Kuiper). + + + + + 0.5 + 0.5 + + + beta + beta + + 2003-12-14 + PHP + +- BC break!!! OLE/OLE.php file moved to OLE.php to comply with PEAR + standards. You will have to change your require('OLE/OLE.php')'s + for require('OLE.php')'s +- If you are using Spreadsheet_Excel_Writer, do not upgrade to this + version yet. A new version of Spreadsheet_Excel_Writer will be + released soon so the BC break won't affect you. +- allowing setting of temp dir for OLE_PPS_File and OLE_PPS_Root objects +- fixed problem when reading files (not reading the whole OLE tree) + + + + + 0.6.0 + 0.6.0 + + + beta + beta + + 2007-12-09 + PHP + +Rewrite of parser (no change to writer): +- Files inside OLE container are now saved in directory structure. +- Parser now properly uses Big Block, Small Block and Master Block Allocation Tables. +- Added stream interface for reading files inside OLE container. + +- Bug #6516. Fix "PPS at 1 has unknown type" errors. (Christian Schmidt) +- Coding Standard cleanups (by helgi) +- Bug #3951 OLE_PPS_File::init() does not return true on success (by helgi) +- Bug #3955 OLE::_readPpsWks() does not return true on success (by helgi) + + + + + 0.6.1 + 0.6.1 + + + beta + beta + + 2007-12-18 + PHP + +- fixed bug #12693: wrong order of require_once +- added missing file to package: ChainedBlockStream.php + + + + + 0.6.2 + 0.6.2 + + + beta + beta + + 2012-01-26 + PHP + +- fixed bug #12944: Incompatibility open_basedir restriction. + + + + + 1.0.0RC2 + 1.0.0RC2 + + + beta + beta + + 2012-01-26 + PHP + +QA release +Bug #15904 Invalid Bigblock chain with files > 200MB +Bug #17685 OLE doesn't save multistreams + + + + + 1.0.0RC3 + 1.0.0RC3 + + + beta + beta + + 2017-06-20 + PHP + +Bug #19284: RC2 breaks header in excel files from Spreadsheet_Excel_Writer +Bug #21216: Call to undefined method PEAR::OLE_PPS() + + + + diff --git a/vendor/pear/ole/phpunit.xml.dist b/vendor/pear/ole/phpunit.xml.dist new file mode 100644 index 00000000..43219132 --- /dev/null +++ b/vendor/pear/ole/phpunit.xml.dist @@ -0,0 +1,22 @@ + + + + + tests/ + + + + + + OLE/ + OLE.php + + + + + + + + diff --git a/vendor/pear/pear-core-minimal/README.rst b/vendor/pear/pear-core-minimal/README.rst new file mode 100644 index 00000000..9e412fbd --- /dev/null +++ b/vendor/pear/pear-core-minimal/README.rst @@ -0,0 +1,26 @@ +****************************** +Minimal set of PEAR core files +****************************** + +This repository provides a set of files from ``pear-core`` +that are often used in PEAR packages. + +It follows the `pear-core`__ repository and gets updated whenever a new +PEAR version is released. + +It's meant to be used as dependency for composer packages. + +__ https://github.com/pear/pear-core + +============== +Included files +============== +- ``OS/Guess.php`` +- ``PEAR.php`` +- ``PEAR/Error.php`` +- ``PEAR/ErrorStack.php`` +- ``System.php`` + + +``PEAR/Error.php`` is a dummy file that only includes ``PEAR.php``, +to make autoloaders work without problems. diff --git a/vendor/pear/pear-core-minimal/composer.json b/vendor/pear/pear-core-minimal/composer.json new file mode 100644 index 00000000..d805f56a --- /dev/null +++ b/vendor/pear/pear-core-minimal/composer.json @@ -0,0 +1,32 @@ +{ + "name": "pear/pear-core-minimal", + "description": "Minimal set of PEAR core files to be used as composer dependency", + "license": "BSD-3-Clause", + "authors": [ + { + "email": "cweiske@php.net", + "name": "Christian Weiske", + "role": "Lead" + } + ], + "autoload": { + "psr-0": { + "": "src/" + } + }, + "include-path": [ + "src/" + ], + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=PEAR", + "source": "https://github.com/pear/pear-core-minimal" + }, + "type": "library", + "require": { + "pear/console_getopt": "~1.4", + "pear/pear_exception": "~1.0" + }, + "replace": { + "rsky/pear-core-min": "self.version" + } +} diff --git a/vendor/pear/pear-core-minimal/src/OS/Guess.php b/vendor/pear/pear-core-minimal/src/OS/Guess.php new file mode 100644 index 00000000..88cd6591 --- /dev/null +++ b/vendor/pear/pear-core-minimal/src/OS/Guess.php @@ -0,0 +1,395 @@ + + * @author Gregory Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @link http://pear.php.net/package/PEAR + * @since File available since PEAR 0.1 + */ + +// {{{ uname examples + +// php_uname() without args returns the same as 'uname -a', or a PHP-custom +// string for Windows. +// PHP versions prior to 4.3 return the uname of the host where PHP was built, +// as of 4.3 it returns the uname of the host running the PHP code. +// +// PC RedHat Linux 7.1: +// Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown +// +// PC Debian Potato: +// Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown +// +// PC FreeBSD 3.3: +// FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000 root@example.com:/usr/src/sys/compile/CONFIG i386 +// +// PC FreeBSD 4.3: +// FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001 root@example.com:/usr/src/sys/compile/CONFIG i386 +// +// PC FreeBSD 4.5: +// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb 6 23:59:23 CET 2002 root@example.com:/usr/src/sys/compile/CONFIG i386 +// +// PC FreeBSD 4.5 w/uname from GNU shellutils: +// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb i386 unknown +// +// HP 9000/712 HP-UX 10: +// HP-UX iq B.10.10 A 9000/712 2008429113 two-user license +// +// HP 9000/712 HP-UX 10 w/uname from GNU shellutils: +// HP-UX host B.10.10 A 9000/712 unknown +// +// IBM RS6000/550 AIX 4.3: +// AIX host 3 4 000003531C00 +// +// AIX 4.3 w/uname from GNU shellutils: +// AIX host 3 4 000003531C00 unknown +// +// SGI Onyx IRIX 6.5 w/uname from GNU shellutils: +// IRIX64 host 6.5 01091820 IP19 mips +// +// SGI Onyx IRIX 6.5: +// IRIX64 host 6.5 01091820 IP19 +// +// SparcStation 20 Solaris 8 w/uname from GNU shellutils: +// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc +// +// SparcStation 20 Solaris 8: +// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20 +// +// Mac OS X (Darwin) +// Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug 5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC Power Macintosh +// +// Mac OS X early versions +// + +// }}} + +/* TODO: + * - define endianness, to allow matchSignature("bigend") etc. + */ + +/** + * Retrieves information about the current operating system + * + * This class uses php_uname() to grok information about the current OS + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Gregory Beaver + * @copyright 1997-2020 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class OS_Guess +{ + var $sysname; + var $nodename; + var $cpu; + var $release; + var $extra; + + function __construct($uname = null) + { + list($this->sysname, + $this->release, + $this->cpu, + $this->extra, + $this->nodename) = $this->parseSignature($uname); + } + + function parseSignature($uname = null) + { + static $sysmap = array( + 'HP-UX' => 'hpux', + 'IRIX64' => 'irix', + ); + static $cpumap = array( + 'i586' => 'i386', + 'i686' => 'i386', + 'ppc' => 'powerpc', + ); + if ($uname === null) { + $uname = php_uname(); + } + $parts = preg_split('/\s+/', trim($uname)); + $n = count($parts); + + $release = $machine = $cpu = ''; + $sysname = $parts[0]; + $nodename = $parts[1]; + $cpu = $parts[$n-1]; + $extra = ''; + if ($cpu == 'unknown') { + $cpu = $parts[$n - 2]; + } + + switch ($sysname) { + case 'AIX' : + $release = "$parts[3].$parts[2]"; + break; + case 'Windows' : + $release = $parts[1]; + if ($release == '95/98') { + $release = '9x'; + } + $cpu = 'i386'; + break; + case 'Linux' : + $extra = $this->_detectGlibcVersion(); + // use only the first two digits from the kernel version + $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]); + break; + case 'Mac' : + $sysname = 'darwin'; + $nodename = $parts[2]; + $release = $parts[3]; + $cpu = $this->_determineIfPowerpc($cpu, $parts); + break; + case 'Darwin' : + $cpu = $this->_determineIfPowerpc($cpu, $parts); + $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]); + break; + default: + $release = preg_replace('/-.*/', '', $parts[2]); + break; + } + + if (isset($sysmap[$sysname])) { + $sysname = $sysmap[$sysname]; + } else { + $sysname = strtolower($sysname); + } + if (isset($cpumap[$cpu])) { + $cpu = $cpumap[$cpu]; + } + return array($sysname, $release, $cpu, $extra, $nodename); + } + + function _determineIfPowerpc($cpu, $parts) + { + $n = count($parts); + if ($cpu == 'Macintosh' && $parts[$n - 2] == 'Power') { + $cpu = 'powerpc'; + } + return $cpu; + } + + function _detectGlibcVersion() + { + static $glibc = false; + if ($glibc !== false) { + return $glibc; // no need to run this multiple times + } + $major = $minor = 0; + include_once "System.php"; + + // Let's try reading possible libc.so.6 symlinks + $libcs = array( + '/lib64/libc.so.6', + '/lib/libc.so.6', + '/lib/i386-linux-gnu/libc.so.6' + ); + $versions = array(); + foreach ($libcs as $file) { + $versions = $this->_readGlibCVersionFromSymlink($file); + if ($versions != []) { + list($major, $minor) = $versions; + break; + } + } + + // Use glibc's header file to + // get major and minor version number: + if (!($major && $minor)) { + $versions = $this->_readGlibCVersionFromFeaturesHeaderFile(); + } + if (is_array($versions) && $versions != []) { + list($major, $minor) = $versions; + } + + if (!($major && $minor)) { + return $glibc = ''; + } + + return $glibc = "glibc{$major}.{$minor}"; + } + + function _readGlibCVersionFromSymlink($file) + { + $versions = array(); + if (@is_link($file) + && (preg_match('/^libc-(.*)\.so$/', basename(readlink($file)), $matches)) + ) { + $versions = explode('.', $matches[1]); + } + return $versions; + } + + + function _readGlibCVersionFromFeaturesHeaderFile() + { + $features_header_file = '/usr/include/features.h'; + if (!(@file_exists($features_header_file) + && @is_readable($features_header_file)) + ) { + return array(); + } + if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) { + return $this-_parseFeaturesHeaderFile($features_header_file); + } // no cpp + + return $this->_fromGlibCTest(); + } + + function _parseFeaturesHeaderFile($features_header_file) + { + $features_file = fopen($features_header_file, 'rb'); + while (!feof($features_file)) { + $line = fgets($features_file, 8192); + if (!$this->_IsADefinition($line)) { + continue; + } + if (strpos($line, '__GLIBC__')) { + // major version number #define __GLIBC__ version + $line = preg_split('/\s+/', $line); + $glibc_major = trim($line[2]); + if (isset($glibc_minor)) { + break; + } + continue; + } + + if (strpos($line, '__GLIBC_MINOR__')) { + // got the minor version number + // #define __GLIBC_MINOR__ version + $line = preg_split('/\s+/', $line); + $glibc_minor = trim($line[2]); + if (isset($glibc_major)) { + break; + } + } + } + fclose($features_file); + if (!isset($glibc_major) || !isset($glibc_minor)) { + return array(); + } + return array(trim($glibc_major), trim($glibc_minor)); + } + + function _IsADefinition($line) + { + if ($line === false) { + return false; + } + return strpos(trim($line), '#define') !== false; + } + + function _fromGlibCTest() + { + $major = null; + $minor = null; + + $tmpfile = System::mktemp("glibctest"); + $fp = fopen($tmpfile, "w"); + fwrite($fp, "#include \n__GLIBC__ __GLIBC_MINOR__\n"); + fclose($fp); + $cpp = popen("/usr/bin/cpp $tmpfile", "r"); + while ($line = fgets($cpp, 1024)) { + if ($line[0] == '#' || trim($line) == '') { + continue; + } + + if (list($major, $minor) = explode(' ', trim($line))) { + break; + } + } + pclose($cpp); + unlink($tmpfile); + if ($major !== null && $minor !== null) { + return [$major, $minor]; + } + } + + function getSignature() + { + if (empty($this->extra)) { + return "{$this->sysname}-{$this->release}-{$this->cpu}"; + } + return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}"; + } + + function getSysname() + { + return $this->sysname; + } + + function getNodename() + { + return $this->nodename; + } + + function getCpu() + { + return $this->cpu; + } + + function getRelease() + { + return $this->release; + } + + function getExtra() + { + return $this->extra; + } + + function matchSignature($match) + { + $fragments = is_array($match) ? $match : explode('-', $match); + $n = count($fragments); + $matches = 0; + if ($n > 0) { + $matches += $this->_matchFragment($fragments[0], $this->sysname); + } + if ($n > 1) { + $matches += $this->_matchFragment($fragments[1], $this->release); + } + if ($n > 2) { + $matches += $this->_matchFragment($fragments[2], $this->cpu); + } + if ($n > 3) { + $matches += $this->_matchFragment($fragments[3], $this->extra); + } + return ($matches == $n); + } + + function _matchFragment($fragment, $value) + { + if (strcspn($fragment, '*?') < strlen($fragment)) { + $expression = str_replace( + array('*', '?', '/'), + array('.*', '.', '\\/'), + $fragment + ); + $reg = '/^' . $expression . '\\z/'; + return preg_match($reg, $value); + } + return ($fragment == '*' || !strcasecmp($fragment, $value)); + } +} +/* + * Local Variables: + * indent-tabs-mode: nil + * c-basic-offset: 4 + * End: + */ diff --git a/vendor/pear/pear-core-minimal/src/PEAR.php b/vendor/pear/pear-core-minimal/src/PEAR.php new file mode 100644 index 00000000..fee6638f --- /dev/null +++ b/vendor/pear/pear-core-minimal/src/PEAR.php @@ -0,0 +1,1135 @@ + + * @author Stig Bakken + * @author Tomas V.V.Cox + * @author Greg Beaver + * @copyright 1997-2010 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/**#@+ + * ERROR constants + */ +define('PEAR_ERROR_RETURN', 1); +define('PEAR_ERROR_PRINT', 2); +define('PEAR_ERROR_TRIGGER', 4); +define('PEAR_ERROR_DIE', 8); +define('PEAR_ERROR_CALLBACK', 16); +/** + * WARNING: obsolete + * @deprecated + */ +define('PEAR_ERROR_EXCEPTION', 32); +/**#@-*/ + +if (substr(PHP_OS, 0, 3) == 'WIN') { + define('OS_WINDOWS', true); + define('OS_UNIX', false); + define('PEAR_OS', 'Windows'); +} else { + define('OS_WINDOWS', false); + define('OS_UNIX', true); + define('PEAR_OS', 'Unix'); // blatant assumption +} + +$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; +$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; +$GLOBALS['_PEAR_destructor_object_list'] = array(); +$GLOBALS['_PEAR_shutdown_funcs'] = array(); +$GLOBALS['_PEAR_error_handler_stack'] = array(); + +@ini_set('track_errors', true); + +/** + * Base class for other PEAR classes. Provides rudimentary + * emulation of destructors. + * + * If you want a destructor in your class, inherit PEAR and make a + * destructor method called _yourclassname (same name as the + * constructor, but with a "_" prefix). Also, in your constructor you + * have to call the PEAR constructor: $this->PEAR();. + * The destructor method will be called without parameters. Note that + * at in some SAPI implementations (such as Apache), any output during + * the request shutdown (in which destructors are called) seems to be + * discarded. If you need to get any debug information from your + * destructor, use error_log(), syslog() or something similar. + * + * IMPORTANT! To use the emulated destructors you need to create the + * objects by reference: $obj =& new PEAR_child; + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V. Cox + * @author Greg Beaver + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PEAR + * @see PEAR_Error + * @since Class available since PHP 4.0.2 + * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear + */ +class PEAR +{ + /** + * Whether to enable internal debug messages. + * + * @var bool + * @access private + */ + var $_debug = false; + + /** + * Default error mode for this object. + * + * @var int + * @access private + */ + var $_default_error_mode = null; + + /** + * Default error options used for this object when error mode + * is PEAR_ERROR_TRIGGER. + * + * @var int + * @access private + */ + var $_default_error_options = null; + + /** + * Default error handler (callback) for this object, if error mode is + * PEAR_ERROR_CALLBACK. + * + * @var string + * @access private + */ + var $_default_error_handler = ''; + + /** + * Which class to use for error objects. + * + * @var string + * @access private + */ + var $_error_class = 'PEAR_Error'; + + /** + * An array of expected errors. + * + * @var array + * @access private + */ + var $_expected_errors = array(); + + /** + * List of methods that can be called both statically and non-statically. + * @var array + */ + protected static $bivalentMethods = array( + 'setErrorHandling' => true, + 'raiseError' => true, + 'throwError' => true, + 'pushErrorHandling' => true, + 'popErrorHandling' => true, + ); + + /** + * Constructor. Registers this object in + * $_PEAR_destructor_object_list for destructor emulation if a + * destructor object exists. + * + * @param string $error_class (optional) which class to use for + * error objects, defaults to PEAR_Error. + * @access public + * @return void + */ + function __construct($error_class = null) + { + $classname = strtolower(get_class($this)); + if ($this->_debug) { + print "PEAR constructor called, class=$classname\n"; + } + + if ($error_class !== null) { + $this->_error_class = $error_class; + } + + while ($classname && strcasecmp($classname, "pear")) { + $destructor = "_$classname"; + if (method_exists($this, $destructor)) { + global $_PEAR_destructor_object_list; + $_PEAR_destructor_object_list[] = $this; + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + break; + } else { + $classname = get_parent_class($classname); + } + } + } + + /** + * Only here for backwards compatibility. + * E.g. Archive_Tar calls $this->PEAR() in its constructor. + * + * @param string $error_class Which class to use for error objects, + * defaults to PEAR_Error. + */ + public function PEAR($error_class = null) + { + self::__construct($error_class); + } + + /** + * Destructor (the emulated type of...). Does nothing right now, + * but is included for forward compatibility, so subclass + * destructors should always call it. + * + * See the note in the class desciption about output from + * destructors. + * + * @access public + * @return void + */ + function _PEAR() { + if ($this->_debug) { + printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); + } + } + + public function __call($method, $arguments) + { + if (!isset(self::$bivalentMethods[$method])) { + trigger_error( + 'Call to undefined method PEAR::' . $method . '()', E_USER_ERROR + ); + } + return call_user_func_array( + array(get_class(), '_' . $method), + array_merge(array($this), $arguments) + ); + } + + public static function __callStatic($method, $arguments) + { + if (!isset(self::$bivalentMethods[$method])) { + trigger_error( + 'Call to undefined method PEAR::' . $method . '()', E_USER_ERROR + ); + } + return call_user_func_array( + array(get_class(), '_' . $method), + array_merge(array(null), $arguments) + ); + } + + /** + * If you have a class that's mostly/entirely static, and you need static + * properties, you can use this method to simulate them. Eg. in your method(s) + * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); + * You MUST use a reference, or they will not persist! + * + * @param string $class The calling classname, to prevent clashes + * @param string $var The variable to retrieve. + * @return mixed A reference to the variable. If not set it will be + * auto initialised to NULL. + */ + public static function &getStaticProperty($class, $var) + { + static $properties; + if (!isset($properties[$class])) { + $properties[$class] = array(); + } + + if (!array_key_exists($var, $properties[$class])) { + $properties[$class][$var] = null; + } + + return $properties[$class][$var]; + } + + /** + * Use this function to register a shutdown method for static + * classes. + * + * @param mixed $func The function name (or array of class/method) to call + * @param mixed $args The arguments to pass to the function + * + * @return void + */ + public static function registerShutdownFunc($func, $args = array()) + { + // if we are called statically, there is a potential + // that no shutdown func is registered. Bug #6445 + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); + } + + /** + * Tell whether a value is a PEAR error. + * + * @param mixed $data the value to test + * @param int $code if $data is an error object, return true + * only if $code is a string and + * $obj->getMessage() == $code or + * $code is an integer and $obj->getCode() == $code + * + * @return bool true if parameter is an error + */ + public static function isError($data, $code = null) + { + if (!is_a($data, 'PEAR_Error')) { + return false; + } + + if (is_null($code)) { + return true; + } elseif (is_string($code)) { + return $data->getMessage() == $code; + } + + return $data->getCode() == $code; + } + + /** + * Sets how errors generated by this object should be handled. + * Can be invoked both in objects and statically. If called + * statically, setErrorHandling sets the default behaviour for all + * PEAR objects. If called in an object, setErrorHandling sets + * the default behaviour for that object. + * + * @param object $object + * Object the method was called on (non-static mode) + * + * @param int $mode + * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. + * + * @param mixed $options + * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one + * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * + * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected + * to be the callback function or method. A callback + * function is a string with the name of the function, a + * callback method is an array of two elements: the element + * at index 0 is the object, and the element at index 1 is + * the name of the method to call in the object. + * + * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is + * a printf format string used when printing the error + * message. + * + * @access public + * @return void + * @see PEAR_ERROR_RETURN + * @see PEAR_ERROR_PRINT + * @see PEAR_ERROR_TRIGGER + * @see PEAR_ERROR_DIE + * @see PEAR_ERROR_CALLBACK + * @see PEAR_ERROR_EXCEPTION + * + * @since PHP 4.0.5 + */ + protected static function _setErrorHandling( + $object, $mode = null, $options = null + ) { + if ($object !== null) { + $setmode = &$object->_default_error_mode; + $setoptions = &$object->_default_error_options; + } else { + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + } + + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + } + + /** + * This method is used to tell which errors you expect to get. + * Expected errors are always returned with error mode + * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, + * and this method pushes a new element onto it. The list of + * expected errors are in effect until they are popped off the + * stack with the popExpect() method. + * + * Note that this method can not be called statically + * + * @param mixed $code a single error code or an array of error codes to expect + * + * @return int the new depth of the "expected errors" stack + * @access public + */ + function expectError($code = '*') + { + if (is_array($code)) { + array_push($this->_expected_errors, $code); + } else { + array_push($this->_expected_errors, array($code)); + } + return count($this->_expected_errors); + } + + /** + * This method pops one element off the expected error codes + * stack. + * + * @return array the list of error codes that were popped + */ + function popExpect() + { + return array_pop($this->_expected_errors); + } + + /** + * This method checks unsets an error code if available + * + * @param mixed error code + * @return bool true if the error code was unset, false otherwise + * @access private + * @since PHP 4.3.0 + */ + function _checkDelExpect($error_code) + { + $deleted = false; + foreach ($this->_expected_errors as $key => $error_array) { + if (in_array($error_code, $error_array)) { + unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); + $deleted = true; + } + + // clean up empty arrays + if (0 == count($this->_expected_errors[$key])) { + unset($this->_expected_errors[$key]); + } + } + + return $deleted; + } + + /** + * This method deletes all occurrences of the specified element from + * the expected error codes stack. + * + * @param mixed $error_code error code that should be deleted + * @return mixed list of error codes that were deleted or error + * @access public + * @since PHP 4.3.0 + */ + function delExpect($error_code) + { + $deleted = false; + if ((is_array($error_code) && (0 != count($error_code)))) { + // $error_code is a non-empty array here; we walk through it trying + // to unset all values + foreach ($error_code as $key => $error) { + $deleted = $this->_checkDelExpect($error) ? true : false; + } + + return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } elseif (!empty($error_code)) { + // $error_code comes alone, trying to unset it + if ($this->_checkDelExpect($error_code)) { + return true; + } + + return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } + + // $error_code is empty + return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME + } + + /** + * This method is a wrapper that returns an instance of the + * configured error class with this object's default error + * handling applied. If the $mode and $options parameters are not + * specified, the object's defaults are used. + * + * @param mixed $message a text error message or a PEAR error object + * + * @param int $code a numeric error code (it is up to your class + * to define these if you want to use codes) + * + * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. + * + * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter + * specifies the PHP-internal error level (one of + * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * If $mode is PEAR_ERROR_CALLBACK, this + * parameter specifies the callback function or + * method. In other error modes this parameter + * is ignored. + * + * @param string $userinfo If you need to pass along for example debug + * information, this parameter is meant for that. + * + * @param string $error_class The returned error object will be + * instantiated from this class, if specified. + * + * @param bool $skipmsg If true, raiseError will only pass error codes, + * the error message parameter will be dropped. + * + * @return object a PEAR error object + * @see PEAR::setErrorHandling + * @since PHP 4.0.5 + */ + protected static function _raiseError($object, + $message = null, + $code = null, + $mode = null, + $options = null, + $userinfo = null, + $error_class = null, + $skipmsg = false) + { + // The error is yet a PEAR error object + if (is_object($message)) { + $code = $message->getCode(); + $userinfo = $message->getUserInfo(); + $error_class = $message->getType(); + $message->error_message_prefix = ''; + $message = $message->getMessage(); + } + + if ( + $object !== null && + isset($object->_expected_errors) && + count($object->_expected_errors) > 0 && + count($exp = end($object->_expected_errors)) + ) { + if ($exp[0] === "*" || + (is_int(reset($exp)) && in_array($code, $exp)) || + (is_string(reset($exp)) && in_array($message, $exp)) + ) { + $mode = PEAR_ERROR_RETURN; + } + } + + // No mode given, try global ones + if ($mode === null) { + // Class error handler + if ($object !== null && isset($object->_default_error_mode)) { + $mode = $object->_default_error_mode; + $options = $object->_default_error_options; + // Global error handler + } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { + $mode = $GLOBALS['_PEAR_default_error_mode']; + $options = $GLOBALS['_PEAR_default_error_options']; + } + } + + if ($error_class !== null) { + $ec = $error_class; + } elseif ($object !== null && isset($object->_error_class)) { + $ec = $object->_error_class; + } else { + $ec = 'PEAR_Error'; + } + + if ($skipmsg) { + $a = new $ec($code, $mode, $options, $userinfo); + } else { + $a = new $ec($message, $code, $mode, $options, $userinfo); + } + + return $a; + } + + /** + * Simpler form of raiseError with fewer options. In most cases + * message, code and userinfo are enough. + * + * @param mixed $message a text error message or a PEAR error object + * + * @param int $code a numeric error code (it is up to your class + * to define these if you want to use codes) + * + * @param string $userinfo If you need to pass along for example debug + * information, this parameter is meant for that. + * + * @return object a PEAR error object + * @see PEAR::raiseError + */ + protected static function _throwError($object, $message = null, $code = null, $userinfo = null) + { + if ($object !== null) { + $a = $object->raiseError($message, $code, null, null, $userinfo); + return $a; + } + + $a = PEAR::raiseError($message, $code, null, null, $userinfo); + return $a; + } + + public static function staticPushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + $stack[] = array($def_mode, $def_options); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $def_mode = $mode; + $def_options = $options; + break; + + case PEAR_ERROR_CALLBACK: + $def_mode = $mode; + // class/object method callback + if (is_callable($options)) { + $def_options = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + $stack[] = array($mode, $options); + return true; + } + + public static function staticPopErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + return true; + } + + /** + * Push a new error handler on top of the error handler options stack. With this + * you can easily override the actual error handler for some code and restore + * it later with popErrorHandling. + * + * @param mixed $mode (same as setErrorHandling) + * @param mixed $options (same as setErrorHandling) + * + * @return bool Always true + * + * @see PEAR::setErrorHandling + */ + protected static function _pushErrorHandling($object, $mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + if ($object !== null) { + $def_mode = &$object->_default_error_mode; + $def_options = &$object->_default_error_options; + } else { + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + } + $stack[] = array($def_mode, $def_options); + + if ($object !== null) { + $object->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + $stack[] = array($mode, $options); + return true; + } + + /** + * Pop the last error handler used + * + * @return bool Always true + * + * @see PEAR::pushErrorHandling + */ + protected static function _popErrorHandling($object) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + if ($object !== null) { + $object->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + return true; + } + + /** + * OS independent PHP extension load. Remember to take care + * on the correct extension name for case sensitive OSes. + * + * @param string $ext The extension name + * @return bool Success or not on the dl() call + */ + public static function loadExtension($ext) + { + if (extension_loaded($ext)) { + return true; + } + + // if either returns true dl() will produce a FATAL error, stop that + if ( + function_exists('dl') === false || + ini_get('enable_dl') != 1 + ) { + return false; + } + + if (OS_WINDOWS) { + $suffix = '.dll'; + } elseif (PHP_OS == 'HP-UX') { + $suffix = '.sl'; + } elseif (PHP_OS == 'AIX') { + $suffix = '.a'; + } elseif (PHP_OS == 'OSX') { + $suffix = '.bundle'; + } else { + $suffix = '.so'; + } + + return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); + } + + /** + * Get SOURCE_DATE_EPOCH environment variable + * See https://reproducible-builds.org/specs/source-date-epoch/ + * + * @return int + * @access public + */ + static function getSourceDateEpoch() + { + if ($source_date_epoch = getenv('SOURCE_DATE_EPOCH')) { + if (preg_match('/^\d+$/', $source_date_epoch)) { + return (int) $source_date_epoch; + } else { + // "If the value is malformed, the build process SHOULD exit with a non-zero error code." + self::raiseError("Invalid SOURCE_DATE_EPOCH: $source_date_epoch"); + exit(1); + } + } else { + return time(); + } + } +} + +function _PEAR_call_destructors() +{ + global $_PEAR_destructor_object_list; + if (is_array($_PEAR_destructor_object_list) && + sizeof($_PEAR_destructor_object_list)) + { + reset($_PEAR_destructor_object_list); + + $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo'); + + if ($destructLifoExists) { + $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); + } + + foreach ($_PEAR_destructor_object_list as $k => $objref) { + $classname = get_class($objref); + while ($classname) { + $destructor = "_$classname"; + if (method_exists($objref, $destructor)) { + $objref->$destructor(); + break; + } else { + $classname = get_parent_class($classname); + } + } + } + // Empty the object list to ensure that destructors are + // not called more than once. + $_PEAR_destructor_object_list = array(); + } + + // Now call the shutdown functions + if ( + isset($GLOBALS['_PEAR_shutdown_funcs']) && + is_array($GLOBALS['_PEAR_shutdown_funcs']) && + !empty($GLOBALS['_PEAR_shutdown_funcs']) + ) { + foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { + call_user_func_array($value[0], $value[1]); + } + } +} + +/** + * Standard PEAR error class for PHP 4 + * + * This class is supserseded by {@link PEAR_Exception} in PHP 5 + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V. Cox + * @author Gregory Beaver + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/manual/en/core.pear.pear-error.php + * @see PEAR::raiseError(), PEAR::throwError() + * @since Class available since PHP 4.0.2 + */ +class PEAR_Error +{ + var $error_message_prefix = ''; + var $mode = PEAR_ERROR_RETURN; + var $level = E_USER_NOTICE; + var $code = -1; + var $message = ''; + var $userinfo = ''; + var $backtrace = null; + + /** + * PEAR_Error constructor + * + * @param string $message message + * + * @param int $code (optional) error code + * + * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, + * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION + * + * @param mixed $options (optional) error level, _OR_ in the case of + * PEAR_ERROR_CALLBACK, the callback function or object/method + * tuple. + * + * @param string $userinfo (optional) additional user/debug info + * + * @access public + * + */ + function __construct($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + if ($mode === null) { + $mode = PEAR_ERROR_RETURN; + } + $this->message = $message; + $this->code = $code; + $this->mode = $mode; + $this->userinfo = $userinfo; + + $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace'); + + if (!$skiptrace) { + $this->backtrace = debug_backtrace(); + if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) { + unset($this->backtrace[0]['object']); + } + } + + if ($mode & PEAR_ERROR_CALLBACK) { + $this->level = E_USER_NOTICE; + $this->callback = $options; + } else { + if ($options === null) { + $options = E_USER_NOTICE; + } + + $this->level = $options; + $this->callback = null; + } + + if ($this->mode & PEAR_ERROR_PRINT) { + if (is_null($options) || is_int($options)) { + $format = "%s"; + } else { + $format = $options; + } + + printf($format, $this->getMessage()); + } + + if ($this->mode & PEAR_ERROR_TRIGGER) { + trigger_error($this->getMessage(), $this->level); + } + + if ($this->mode & PEAR_ERROR_DIE) { + $msg = $this->getMessage(); + if (is_null($options) || is_int($options)) { + $format = "%s"; + if (substr($msg, -1) != "\n") { + $msg .= "\n"; + } + } else { + $format = $options; + } + printf($format, $msg); + exit($code); + } + + if ($this->mode & PEAR_ERROR_CALLBACK && is_callable($this->callback)) { + call_user_func($this->callback, $this); + } + + if ($this->mode & PEAR_ERROR_EXCEPTION) { + trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); + eval('$e = new Exception($this->message, $this->code);throw($e);'); + } + } + + /** + * Only here for backwards compatibility. + * + * Class "Cache_Error" still uses it, among others. + * + * @param string $message Message + * @param int $code Error code + * @param int $mode Error mode + * @param mixed $options See __construct() + * @param string $userinfo Additional user/debug info + */ + public function PEAR_Error( + $message = 'unknown error', $code = null, $mode = null, + $options = null, $userinfo = null + ) { + self::__construct($message, $code, $mode, $options, $userinfo); + } + + /** + * Get the error mode from an error object. + * + * @return int error mode + * @access public + */ + function getMode() + { + return $this->mode; + } + + /** + * Get the callback function/method from an error object. + * + * @return mixed callback function or object/method array + * @access public + */ + function getCallback() + { + return $this->callback; + } + + /** + * Get the error message from an error object. + * + * @return string full error message + * @access public + */ + function getMessage() + { + return ($this->error_message_prefix . $this->message); + } + + /** + * Get error code from an error object + * + * @return int error code + * @access public + */ + function getCode() + { + return $this->code; + } + + /** + * Get the name of this error/exception. + * + * @return string error/exception name (type) + * @access public + */ + function getType() + { + return get_class($this); + } + + /** + * Get additional user-supplied information. + * + * @return string user-supplied information + * @access public + */ + function getUserInfo() + { + return $this->userinfo; + } + + /** + * Get additional debug information supplied by the application. + * + * @return string debug information + * @access public + */ + function getDebugInfo() + { + return $this->getUserInfo(); + } + + /** + * Get the call backtrace from where the error was generated. + * Supported with PHP 4.3.0 or newer. + * + * @param int $frame (optional) what frame to fetch + * @return array Backtrace, or NULL if not available. + * @access public + */ + function getBacktrace($frame = null) + { + if (defined('PEAR_IGNORE_BACKTRACE')) { + return null; + } + if ($frame === null) { + return $this->backtrace; + } + return $this->backtrace[$frame]; + } + + function addUserInfo($info) + { + if (empty($this->userinfo)) { + $this->userinfo = $info; + } else { + $this->userinfo .= " ** $info"; + } + } + + function __toString() + { + return $this->getMessage(); + } + + /** + * Make a string representation of this object. + * + * @return string a string with an object summary + * @access public + */ + function toString() + { + $modes = array(); + $levels = array(E_USER_NOTICE => 'notice', + E_USER_WARNING => 'warning', + E_USER_ERROR => 'error'); + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_array($this->callback)) { + $callback = (is_object($this->callback[0]) ? + strtolower(get_class($this->callback[0])) : + $this->callback[0]) . '::' . + $this->callback[1]; + } else { + $callback = $this->callback; + } + return sprintf('[%s: message="%s" code=%d mode=callback '. + 'callback=%s prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + $callback, $this->error_message_prefix, + $this->userinfo); + } + if ($this->mode & PEAR_ERROR_PRINT) { + $modes[] = 'print'; + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + $modes[] = 'trigger'; + } + if ($this->mode & PEAR_ERROR_DIE) { + $modes[] = 'die'; + } + if ($this->mode & PEAR_ERROR_RETURN) { + $modes[] = 'return'; + } + return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. + 'prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + implode("|", $modes), $levels[$this->level], + $this->error_message_prefix, + $this->userinfo); + } +} + +/* + * Local Variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/vendor/pear/pear-core-minimal/src/PEAR/Error.php b/vendor/pear/pear-core-minimal/src/PEAR/Error.php new file mode 100644 index 00000000..96efff75 --- /dev/null +++ b/vendor/pear/pear-core-minimal/src/PEAR/Error.php @@ -0,0 +1,14 @@ + + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @link http://pear.php.net/package/PEAR + */ +require_once __DIR__ . '/../PEAR.php'; +?> \ No newline at end of file diff --git a/vendor/pear/pear-core-minimal/src/PEAR/ErrorStack.php b/vendor/pear/pear-core-minimal/src/PEAR/ErrorStack.php new file mode 100644 index 00000000..6619fbb1 --- /dev/null +++ b/vendor/pear/pear-core-minimal/src/PEAR/ErrorStack.php @@ -0,0 +1,979 @@ + + * @copyright 2004-2008 Greg Beaver + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @link http://pear.php.net/package/PEAR_ErrorStack + */ + +/** + * Singleton storage + * + * Format: + *
+ * array(
+ *  'package1' => PEAR_ErrorStack object,
+ *  'package2' => PEAR_ErrorStack object,
+ *  ...
+ * )
+ * 
+ * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] + */ +$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array(); + +/** + * Global error callback (default) + * + * This is only used if set to non-false. * is the default callback for + * all packages, whereas specific packages may set a default callback + * for all instances, regardless of whether they are a singleton or not. + * + * To exclude non-singletons, only set the local callback for the singleton + * @see PEAR_ErrorStack::setDefaultCallback() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] + */ +$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array( + '*' => false, +); + +/** + * Global Log object (default) + * + * This is only used if set to non-false. Use to set a default log object for + * all stacks, regardless of instantiation order or location + * @see PEAR_ErrorStack::setDefaultLogger() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] + */ +$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false; + +/** + * Global Overriding Callback + * + * This callback will override any error callbacks that specific loggers have set. + * Use with EXTREME caution + * @see PEAR_ErrorStack::staticPushCallback() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] + */ +$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); + +/**#@+ + * One of four possible return values from the error Callback + * @see PEAR_ErrorStack::_errorCallback() + */ +/** + * If this is returned, then the error will be both pushed onto the stack + * and logged. + */ +define('PEAR_ERRORSTACK_PUSHANDLOG', 1); +/** + * If this is returned, then the error will only be pushed onto the stack, + * and not logged. + */ +define('PEAR_ERRORSTACK_PUSH', 2); +/** + * If this is returned, then the error will only be logged, but not pushed + * onto the error stack. + */ +define('PEAR_ERRORSTACK_LOG', 3); +/** + * If this is returned, then the error is completely ignored. + */ +define('PEAR_ERRORSTACK_IGNORE', 4); +/** + * If this is returned, then the error is logged and die() is called. + */ +define('PEAR_ERRORSTACK_DIE', 5); +/**#@-*/ + +/** + * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in + * the singleton method. + */ +define('PEAR_ERRORSTACK_ERR_NONCLASS', 1); + +/** + * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()} + * that has no __toString() method + */ +define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2); +/** + * Error Stack Implementation + * + * Usage: + * + * // global error stack + * $global_stack = &PEAR_ErrorStack::singleton('MyPackage'); + * // local error stack + * $local_stack = new PEAR_ErrorStack('MyPackage'); + * + * @author Greg Beaver + * @version @package_version@ + * @package PEAR_ErrorStack + * @category Debugging + * @copyright 2004-2008 Greg Beaver + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @link http://pear.php.net/package/PEAR_ErrorStack + */ +class PEAR_ErrorStack { + /** + * Errors are stored in the order that they are pushed on the stack. + * @since 0.4alpha Errors are no longer organized by error level. + * This renders pop() nearly unusable, and levels could be more easily + * handled in a callback anyway + * @var array + * @access private + */ + var $_errors = array(); + + /** + * Storage of errors by level. + * + * Allows easy retrieval and deletion of only errors from a particular level + * @since PEAR 1.4.0dev + * @var array + * @access private + */ + var $_errorsByLevel = array(); + + /** + * Package name this error stack represents + * @var string + * @access protected + */ + var $_package; + + /** + * Determines whether a PEAR_Error is thrown upon every error addition + * @var boolean + * @access private + */ + var $_compat = false; + + /** + * If set to a valid callback, this will be used to generate the error + * message from the error code, otherwise the message passed in will be + * used + * @var false|string|array + * @access private + */ + var $_msgCallback = false; + + /** + * If set to a valid callback, this will be used to generate the error + * context for an error. For PHP-related errors, this will be a file + * and line number as retrieved from debug_backtrace(), but can be + * customized for other purposes. The error might actually be in a separate + * configuration file, or in a database query. + * @var false|string|array + * @access protected + */ + var $_contextCallback = false; + + /** + * If set to a valid callback, this will be called every time an error + * is pushed onto the stack. The return value will be used to determine + * whether to allow an error to be pushed or logged. + * + * The return value must be one an PEAR_ERRORSTACK_* constant + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @var false|string|array + * @access protected + */ + var $_errorCallback = array(); + + /** + * PEAR::Log object for logging errors + * @var false|Log + * @access protected + */ + var $_logger = false; + + /** + * Error messages - designed to be overridden + * @var array + * @abstract + */ + var $_errorMsgs = array(); + + /** + * Set up a new error stack + * + * @param string $package name of the package this error stack represents + * @param callback $msgCallback callback used for error message generation + * @param callback $contextCallback callback used for context generation, + * defaults to {@link getFileLine()} + * @param boolean $throwPEAR_Error + */ + function __construct($package, $msgCallback = false, $contextCallback = false, + $throwPEAR_Error = false) + { + $this->_package = $package; + $this->setMessageCallback($msgCallback); + $this->setContextCallback($contextCallback); + $this->_compat = $throwPEAR_Error; + } + + /** + * Return a single error stack for this package. + * + * Note that all parameters are ignored if the stack for package $package + * has already been instantiated + * @param string $package name of the package this error stack represents + * @param callback $msgCallback callback used for error message generation + * @param callback $contextCallback callback used for context generation, + * defaults to {@link getFileLine()} + * @param boolean $throwPEAR_Error + * @param string $stackClass class to instantiate + * + * @return PEAR_ErrorStack + */ + public static function &singleton( + $package, $msgCallback = false, $contextCallback = false, + $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack' + ) { + if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; + } + if (!class_exists($stackClass)) { + if (function_exists('debug_backtrace')) { + $trace = debug_backtrace(); + } + PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS, + 'exception', array('stackclass' => $stackClass), + 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)', + false, $trace); + } + $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] = + new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error); + + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; + } + + /** + * Internal error handler for PEAR_ErrorStack class + * + * Dies if the error is an exception (and would have died anyway) + * @access private + */ + function _handleError($err) + { + if ($err['level'] == 'exception') { + $message = $err['message']; + if (isset($_SERVER['REQUEST_URI'])) { + echo '
'; + } else { + echo "\n"; + } + var_dump($err['context']); + die($message); + } + } + + /** + * Set up a PEAR::Log object for all error stacks that don't have one + * @param Log $log + */ + public static function setDefaultLogger(&$log) + { + if (is_object($log) && method_exists($log, 'log') ) { + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; + } elseif (is_callable($log)) { + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; + } + } + + /** + * Set up a PEAR::Log object for this error stack + * @param Log $log + */ + function setLogger(&$log) + { + if (is_object($log) && method_exists($log, 'log') ) { + $this->_logger = &$log; + } elseif (is_callable($log)) { + $this->_logger = &$log; + } + } + + /** + * Set an error code => error message mapping callback + * + * This method sets the callback that can be used to generate error + * messages for any instance + * @param array|string Callback function/method + */ + function setMessageCallback($msgCallback) + { + if (!$msgCallback) { + $this->_msgCallback = array(&$this, 'getErrorMessage'); + } else { + if (is_callable($msgCallback)) { + $this->_msgCallback = $msgCallback; + } + } + } + + /** + * Get an error code => error message mapping callback + * + * This method returns the current callback that can be used to generate error + * messages + * @return array|string|false Callback function/method or false if none + */ + function getMessageCallback() + { + return $this->_msgCallback; + } + + /** + * Sets a default callback to be used by all error stacks + * + * This method sets the callback that can be used to generate error + * messages for a singleton + * @param array|string Callback function/method + * @param string Package name, or false for all packages + */ + public static function setDefaultCallback($callback = false, $package = false) + { + if (!is_callable($callback)) { + $callback = false; + } + $package = $package ? $package : '*'; + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback; + } + + /** + * Set a callback that generates context information (location of error) for an error stack + * + * This method sets the callback that can be used to generate context + * information for an error. Passing in NULL will disable context generation + * and remove the expensive call to debug_backtrace() + * @param array|string|null Callback function/method + */ + function setContextCallback($contextCallback) + { + if ($contextCallback === null) { + return $this->_contextCallback = false; + } + if (!$contextCallback) { + $this->_contextCallback = array(&$this, 'getFileLine'); + } else { + if (is_callable($contextCallback)) { + $this->_contextCallback = $contextCallback; + } + } + } + + /** + * Set an error Callback + * If set to a valid callback, this will be called every time an error + * is pushed onto the stack. The return value will be used to determine + * whether to allow an error to be pushed or logged. + * + * The return value must be one of the ERRORSTACK_* constants. + * + * This functionality can be used to emulate PEAR's pushErrorHandling, and + * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of + * the error stack or logging + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @see popCallback() + * @param string|array $cb + */ + function pushCallback($cb) + { + array_push($this->_errorCallback, $cb); + } + + /** + * Remove a callback from the error callback stack + * @see pushCallback() + * @return array|string|false + */ + function popCallback() + { + if (!count($this->_errorCallback)) { + return false; + } + return array_pop($this->_errorCallback); + } + + /** + * Set a temporary overriding error callback for every package error stack + * + * Use this to temporarily disable all existing callbacks (can be used + * to emulate the @ operator, for instance) + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @see staticPopCallback(), pushCallback() + * @param string|array $cb + */ + public static function staticPushCallback($cb) + { + array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb); + } + + /** + * Remove a temporary overriding error callback + * @see staticPushCallback() + * @return array|string|false + */ + public static function staticPopCallback() + { + $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']); + if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) { + $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); + } + return $ret; + } + + /** + * Add an error to the stack + * + * If the message generator exists, it is called with 2 parameters. + * - the current Error Stack object + * - an array that is in the same format as an error. Available indices + * are 'code', 'package', 'time', 'params', 'level', and 'context' + * + * Next, if the error should contain context information, this is + * handled by the context grabbing method. + * Finally, the error is pushed onto the proper error stack + * @param int $code Package-specific error code + * @param string $level Error level. This is NOT spell-checked + * @param array $params associative array of error parameters + * @param string $msg Error message, or a portion of it if the message + * is to be generated + * @param array $repackage If this error re-packages an error pushed by + * another package, place the array returned from + * {@link pop()} in this parameter + * @param array $backtrace Protected parameter: use this to pass in the + * {@link debug_backtrace()} that should be used + * to find error context + * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also + * thrown. If a PEAR_Error is returned, the userinfo + * property is set to the following array: + * + * + * array( + * 'code' => $code, + * 'params' => $params, + * 'package' => $this->_package, + * 'level' => $level, + * 'time' => time(), + * 'context' => $context, + * 'message' => $msg, + * //['repackage' => $err] repackaged error array/Exception class + * ); + * + * + * Normally, the previous array is returned. + */ + function push($code, $level = 'error', $params = array(), $msg = false, + $repackage = false, $backtrace = false) + { + $context = false; + // grab error context + if ($this->_contextCallback) { + if (!$backtrace) { + $backtrace = debug_backtrace(); + } + $context = call_user_func($this->_contextCallback, $code, $params, $backtrace); + } + + // save error + $time = explode(' ', microtime()); + $time = $time[1] + $time[0]; + $err = array( + 'code' => $code, + 'params' => $params, + 'package' => $this->_package, + 'level' => $level, + 'time' => $time, + 'context' => $context, + 'message' => $msg, + ); + + if ($repackage) { + $err['repackage'] = $repackage; + } + + // set up the error message, if necessary + if ($this->_msgCallback) { + $msg = call_user_func_array($this->_msgCallback, + array(&$this, $err)); + $err['message'] = $msg; + } + $push = $log = true; + $die = false; + // try the overriding callback first + $callback = $this->staticPopCallback(); + if ($callback) { + $this->staticPushCallback($callback); + } + if (!is_callable($callback)) { + // try the local callback next + $callback = $this->popCallback(); + if (is_callable($callback)) { + $this->pushCallback($callback); + } else { + // try the default callback + $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ? + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] : + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*']; + } + } + if (is_callable($callback)) { + switch(call_user_func($callback, $err)){ + case PEAR_ERRORSTACK_IGNORE: + return $err; + break; + case PEAR_ERRORSTACK_PUSH: + $log = false; + break; + case PEAR_ERRORSTACK_LOG: + $push = false; + break; + case PEAR_ERRORSTACK_DIE: + $die = true; + break; + // anything else returned has the same effect as pushandlog + } + } + if ($push) { + array_unshift($this->_errors, $err); + if (!isset($this->_errorsByLevel[$err['level']])) { + $this->_errorsByLevel[$err['level']] = array(); + } + $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; + } + if ($log) { + if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) { + $this->_log($err); + } + } + if ($die) { + die(); + } + if ($this->_compat && $push) { + return $this->raiseError($msg, $code, null, null, $err); + } + return $err; + } + + /** + * Static version of {@link push()} + * + * @param string $package Package name this error belongs to + * @param int $code Package-specific error code + * @param string $level Error level. This is NOT spell-checked + * @param array $params associative array of error parameters + * @param string $msg Error message, or a portion of it if the message + * is to be generated + * @param array $repackage If this error re-packages an error pushed by + * another package, place the array returned from + * {@link pop()} in this parameter + * @param array $backtrace Protected parameter: use this to pass in the + * {@link debug_backtrace()} that should be used + * to find error context + * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also + * thrown. see docs for {@link push()} + */ + public static function staticPush( + $package, $code, $level = 'error', $params = array(), + $msg = false, $repackage = false, $backtrace = false + ) { + $s = &PEAR_ErrorStack::singleton($package); + if ($s->_contextCallback) { + if (!$backtrace) { + if (function_exists('debug_backtrace')) { + $backtrace = debug_backtrace(); + } + } + } + return $s->push($code, $level, $params, $msg, $repackage, $backtrace); + } + + /** + * Log an error using PEAR::Log + * @param array $err Error array + * @param array $levels Error level => Log constant map + * @access protected + */ + function _log($err) + { + if ($this->_logger) { + $logger = &$this->_logger; + } else { + $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']; + } + if (is_a($logger, 'Log')) { + $levels = array( + 'exception' => PEAR_LOG_CRIT, + 'alert' => PEAR_LOG_ALERT, + 'critical' => PEAR_LOG_CRIT, + 'error' => PEAR_LOG_ERR, + 'warning' => PEAR_LOG_WARNING, + 'notice' => PEAR_LOG_NOTICE, + 'info' => PEAR_LOG_INFO, + 'debug' => PEAR_LOG_DEBUG); + if (isset($levels[$err['level']])) { + $level = $levels[$err['level']]; + } else { + $level = PEAR_LOG_INFO; + } + $logger->log($err['message'], $level, $err); + } else { // support non-standard logs + call_user_func($logger, $err); + } + } + + + /** + * Pop an error off of the error stack + * + * @return false|array + * @since 0.4alpha it is no longer possible to specify a specific error + * level to return - the last error pushed will be returned, instead + */ + function pop() + { + $err = @array_shift($this->_errors); + if (!is_null($err)) { + @array_pop($this->_errorsByLevel[$err['level']]); + if (!count($this->_errorsByLevel[$err['level']])) { + unset($this->_errorsByLevel[$err['level']]); + } + } + return $err; + } + + /** + * Pop an error off of the error stack, static method + * + * @param string package name + * @return boolean + * @since PEAR1.5.0a1 + */ + static function staticPop($package) + { + if ($package) { + if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return false; + } + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop(); + } + } + + /** + * Determine whether there are any errors on the stack + * @param string|array Level name. Use to determine if any errors + * of level (string), or levels (array) have been pushed + * @return boolean + */ + function hasErrors($level = false) + { + if ($level) { + return isset($this->_errorsByLevel[$level]); + } + return count($this->_errors); + } + + /** + * Retrieve all errors since last purge + * + * @param boolean set in order to empty the error stack + * @param string level name, to return only errors of a particular severity + * @return array + */ + function getErrors($purge = false, $level = false) + { + if (!$purge) { + if ($level) { + if (!isset($this->_errorsByLevel[$level])) { + return array(); + } else { + return $this->_errorsByLevel[$level]; + } + } else { + return $this->_errors; + } + } + if ($level) { + $ret = $this->_errorsByLevel[$level]; + foreach ($this->_errorsByLevel[$level] as $i => $unused) { + // entries are references to the $_errors array + $this->_errorsByLevel[$level][$i] = false; + } + // array_filter removes all entries === false + $this->_errors = array_filter($this->_errors); + unset($this->_errorsByLevel[$level]); + return $ret; + } + $ret = $this->_errors; + $this->_errors = array(); + $this->_errorsByLevel = array(); + return $ret; + } + + /** + * Determine whether there are any errors on a single error stack, or on any error stack + * + * The optional parameter can be used to test the existence of any errors without the need of + * singleton instantiation + * @param string|false Package name to check for errors + * @param string Level name to check for a particular severity + * @return boolean + */ + public static function staticHasErrors($package = false, $level = false) + { + if ($package) { + if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return false; + } + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level); + } + foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { + if ($obj->hasErrors($level)) { + return true; + } + } + return false; + } + + /** + * Get a list of all errors since last purge, organized by package + * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be + * @param boolean $purge Set to purge the error stack of existing errors + * @param string $level Set to a level name in order to retrieve only errors of a particular level + * @param boolean $merge Set to return a flat array, not organized by package + * @param array $sortfunc Function used to sort a merged array - default + * sorts by time, and should be good for most cases + * + * @return array + */ + public static function staticGetErrors( + $purge = false, $level = false, $merge = false, + $sortfunc = array('PEAR_ErrorStack', '_sortErrors') + ) { + $ret = array(); + if (!is_callable($sortfunc)) { + $sortfunc = array('PEAR_ErrorStack', '_sortErrors'); + } + foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { + $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level); + if ($test) { + if ($merge) { + $ret = array_merge($ret, $test); + } else { + $ret[$package] = $test; + } + } + } + if ($merge) { + usort($ret, $sortfunc); + } + return $ret; + } + + /** + * Error sorting function, sorts by time + * @access private + */ + public static function _sortErrors($a, $b) + { + if ($a['time'] == $b['time']) { + return 0; + } + if ($a['time'] < $b['time']) { + return 1; + } + return -1; + } + + /** + * Standard file/line number/function/class context callback + * + * This function uses a backtrace generated from {@link debug_backtrace()} + * and so will not work at all in PHP < 4.3.0. The frame should + * reference the frame that contains the source of the error. + * @return array|false either array('file' => file, 'line' => line, + * 'function' => function name, 'class' => class name) or + * if this doesn't work, then false + * @param unused + * @param integer backtrace frame. + * @param array Results of debug_backtrace() + */ + public static function getFileLine($code, $params, $backtrace = null) + { + if ($backtrace === null) { + return false; + } + $frame = 0; + $functionframe = 1; + if (!isset($backtrace[1])) { + $functionframe = 0; + } else { + while (isset($backtrace[$functionframe]['function']) && + $backtrace[$functionframe]['function'] == 'eval' && + isset($backtrace[$functionframe + 1])) { + $functionframe++; + } + } + if (isset($backtrace[$frame])) { + if (!isset($backtrace[$frame]['file'])) { + $frame++; + } + $funcbacktrace = $backtrace[$functionframe]; + $filebacktrace = $backtrace[$frame]; + $ret = array('file' => $filebacktrace['file'], + 'line' => $filebacktrace['line']); + // rearrange for eval'd code or create function errors + if (strpos($filebacktrace['file'], '(') && + preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'], + $matches)) { + $ret['file'] = $matches[1]; + $ret['line'] = $matches[2] + 0; + } + if (isset($funcbacktrace['function']) && isset($backtrace[1])) { + if ($funcbacktrace['function'] != 'eval') { + if ($funcbacktrace['function'] == '__lambda_func') { + $ret['function'] = 'create_function() code'; + } else { + $ret['function'] = $funcbacktrace['function']; + } + } + } + if (isset($funcbacktrace['class']) && isset($backtrace[1])) { + $ret['class'] = $funcbacktrace['class']; + } + return $ret; + } + return false; + } + + /** + * Standard error message generation callback + * + * This method may also be called by a custom error message generator + * to fill in template values from the params array, simply + * set the third parameter to the error message template string to use + * + * The special variable %__msg% is reserved: use it only to specify + * where a message passed in by the user should be placed in the template, + * like so: + * + * Error message: %msg% - internal error + * + * If the message passed like so: + * + * + * $stack->push(ERROR_CODE, 'error', array(), 'server error 500'); + * + * + * The returned error message will be "Error message: server error 500 - + * internal error" + * @param PEAR_ErrorStack + * @param array + * @param string|false Pre-generated error message template + * + * @return string + */ + public static function getErrorMessage(&$stack, $err, $template = false) + { + if ($template) { + $mainmsg = $template; + } else { + $mainmsg = $stack->getErrorMessageTemplate($err['code']); + } + $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg); + if (is_array($err['params']) && count($err['params'])) { + foreach ($err['params'] as $name => $val) { + if (is_array($val)) { + // @ is needed in case $val is a multi-dimensional array + $val = @implode(', ', $val); + } + if (is_object($val)) { + if (method_exists($val, '__toString')) { + $val = $val->__toString(); + } else { + PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING, + 'warning', array('obj' => get_class($val)), + 'object %obj% passed into getErrorMessage, but has no __toString() method'); + $val = 'Object'; + } + } + $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg); + } + } + return $mainmsg; + } + + /** + * Standard Error Message Template generator from code + * @return string + */ + function getErrorMessageTemplate($code) + { + if (!isset($this->_errorMsgs[$code])) { + return '%__msg%'; + } + return $this->_errorMsgs[$code]; + } + + /** + * Set the Error Message Template array + * + * The array format must be: + *
+     * array(error code => 'message template',...)
+     * 
+ * + * Error message parameters passed into {@link push()} will be used as input + * for the error message. If the template is 'message %foo% was %bar%', and the + * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will + * be 'message one was six' + * @return string + */ + function setErrorMessageTemplate($template) + { + $this->_errorMsgs = $template; + } + + + /** + * emulate PEAR::raiseError() + * + * @return PEAR_Error + */ + function raiseError() + { + require_once 'PEAR.php'; + $args = func_get_args(); + return call_user_func_array(array('PEAR', 'raiseError'), $args); + } +} +$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack'); +$stack->pushCallback(array('PEAR_ErrorStack', '_handleError')); +?> diff --git a/vendor/pear/pear-core-minimal/src/System.php b/vendor/pear/pear-core-minimal/src/System.php new file mode 100644 index 00000000..a7ef4659 --- /dev/null +++ b/vendor/pear/pear-core-minimal/src/System.php @@ -0,0 +1,630 @@ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR.php'; +require_once 'Console/Getopt.php'; + +$GLOBALS['_System_temp_files'] = array(); + +/** +* System offers cross platform compatible system functions +* +* Static functions for different operations. Should work under +* Unix and Windows. The names and usage has been taken from its respectively +* GNU commands. The functions will return (bool) false on error and will +* trigger the error with the PHP trigger_error() function (you can silence +* the error by prefixing a '@' sign after the function call, but this +* is not recommended practice. Instead use an error handler with +* {@link set_error_handler()}). +* +* Documentation on this class you can find in: +* http://pear.php.net/manual/ +* +* Example usage: +* if (!@System::rm('-r file1 dir1')) { +* print "could not delete file1 or dir1"; +* } +* +* In case you need to to pass file names with spaces, +* pass the params as an array: +* +* System::rm(array('-r', $file1, $dir1)); +* +* @category pear +* @package System +* @author Tomas V.V. Cox +* @copyright 1997-2006 The PHP Group +* @license http://opensource.org/licenses/bsd-license.php New BSD License +* @version Release: @package_version@ +* @link http://pear.php.net/package/PEAR +* @since Class available since Release 0.1 +* @static +*/ +class System +{ + /** + * returns the commandline arguments of a function + * + * @param string $argv the commandline + * @param string $short_options the allowed option short-tags + * @param string $long_options the allowed option long-tags + * @return array the given options and there values + */ + public static function _parseArgs($argv, $short_options, $long_options = null) + { + if (!is_array($argv) && $argv !== null) { + /* + // Quote all items that are a short option + $av = preg_split('/(\A| )--?[a-z0-9]+[ =]?((? $a) { + if (empty($a)) { + continue; + } + $argv[$k] = trim($a) ; + } + } + + return Console_Getopt::getopt2($argv, $short_options, $long_options); + } + + /** + * Output errors with PHP trigger_error(). You can silence the errors + * with prefixing a "@" sign to the function call: @System::mkdir(..); + * + * @param mixed $error a PEAR error or a string with the error message + * @return bool false + */ + protected static function raiseError($error) + { + if (PEAR::isError($error)) { + $error = $error->getMessage(); + } + trigger_error($error, E_USER_WARNING); + return false; + } + + /** + * Creates a nested array representing the structure of a directory + * + * System::_dirToStruct('dir1', 0) => + * Array + * ( + * [dirs] => Array + * ( + * [0] => dir1 + * ) + * + * [files] => Array + * ( + * [0] => dir1/file2 + * [1] => dir1/file3 + * ) + * ) + * @param string $sPath Name of the directory + * @param integer $maxinst max. deep of the lookup + * @param integer $aktinst starting deep of the lookup + * @param bool $silent if true, do not emit errors. + * @return array the structure of the dir + */ + protected static function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false) + { + $struct = array('dirs' => array(), 'files' => array()); + if (($dir = @opendir($sPath)) === false) { + if (!$silent) { + System::raiseError("Could not open dir $sPath"); + } + return $struct; // XXX could not open error + } + + $struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ? + $list = array(); + while (false !== ($file = readdir($dir))) { + if ($file != '.' && $file != '..') { + $list[] = $file; + } + } + + closedir($dir); + natsort($list); + if ($aktinst < $maxinst || $maxinst == 0) { + foreach ($list as $val) { + $path = $sPath . DIRECTORY_SEPARATOR . $val; + if (is_dir($path) && !is_link($path)) { + $tmp = System::_dirToStruct($path, $maxinst, $aktinst+1, $silent); + $struct = array_merge_recursive($struct, $tmp); + } else { + $struct['files'][] = $path; + } + } + } + + return $struct; + } + + /** + * Creates a nested array representing the structure of a directory and files + * + * @param array $files Array listing files and dirs + * @return array + * @static + * @see System::_dirToStruct() + */ + protected static function _multipleToStruct($files) + { + $struct = array('dirs' => array(), 'files' => array()); + settype($files, 'array'); + foreach ($files as $file) { + if (is_dir($file) && !is_link($file)) { + $tmp = System::_dirToStruct($file, 0); + $struct = array_merge_recursive($tmp, $struct); + } else { + if (!in_array($file, $struct['files'])) { + $struct['files'][] = $file; + } + } + } + return $struct; + } + + /** + * The rm command for removing files. + * Supports multiple files and dirs and also recursive deletes + * + * @param string $args the arguments for rm + * @return mixed PEAR_Error or true for success + * @static + * @access public + */ + public static function rm($args) + { + $opts = System::_parseArgs($args, 'rf'); // "f" does nothing but I like it :-) + if (PEAR::isError($opts)) { + return System::raiseError($opts); + } + foreach ($opts[0] as $opt) { + if ($opt[0] == 'r') { + $do_recursive = true; + } + } + $ret = true; + if (isset($do_recursive)) { + $struct = System::_multipleToStruct($opts[1]); + foreach ($struct['files'] as $file) { + if (!@unlink($file)) { + $ret = false; + } + } + + rsort($struct['dirs']); + foreach ($struct['dirs'] as $dir) { + if (!@rmdir($dir)) { + $ret = false; + } + } + } else { + foreach ($opts[1] as $file) { + $delete = (is_dir($file)) ? 'rmdir' : 'unlink'; + if (!@$delete($file)) { + $ret = false; + } + } + } + return $ret; + } + + /** + * Make directories. + * + * The -p option will create parent directories + * @param string $args the name of the director(y|ies) to create + * @return bool True for success + */ + public static function mkDir($args) + { + $opts = System::_parseArgs($args, 'pm:'); + if (PEAR::isError($opts)) { + return System::raiseError($opts); + } + + $mode = 0777; // default mode + foreach ($opts[0] as $opt) { + if ($opt[0] == 'p') { + $create_parents = true; + } elseif ($opt[0] == 'm') { + // if the mode is clearly an octal number (starts with 0) + // convert it to decimal + if (strlen($opt[1]) && $opt[1][0] == '0') { + $opt[1] = octdec($opt[1]); + } else { + // convert to int + $opt[1] += 0; + } + $mode = $opt[1]; + } + } + + $ret = true; + if (isset($create_parents)) { + foreach ($opts[1] as $dir) { + $dirstack = array(); + while ((!file_exists($dir) || !is_dir($dir)) && + $dir != DIRECTORY_SEPARATOR) { + array_unshift($dirstack, $dir); + $dir = dirname($dir); + } + + while ($newdir = array_shift($dirstack)) { + if (!is_writeable(dirname($newdir))) { + $ret = false; + break; + } + + if (!mkdir($newdir, $mode)) { + $ret = false; + } + } + } + } else { + foreach($opts[1] as $dir) { + if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) { + $ret = false; + } + } + } + + return $ret; + } + + /** + * Concatenate files + * + * Usage: + * 1) $var = System::cat('sample.txt test.txt'); + * 2) System::cat('sample.txt test.txt > final.txt'); + * 3) System::cat('sample.txt test.txt >> final.txt'); + * + * Note: as the class use fopen, urls should work also + * + * @param string $args the arguments + * @return boolean true on success + */ + public static function &cat($args) + { + $ret = null; + $files = array(); + if (!is_array($args)) { + $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); + } + + $count_args = count($args); + for ($i = 0; $i < $count_args; $i++) { + if ($args[$i] == '>') { + $mode = 'wb'; + $outputfile = $args[$i+1]; + break; + } elseif ($args[$i] == '>>') { + $mode = 'ab+'; + $outputfile = $args[$i+1]; + break; + } else { + $files[] = $args[$i]; + } + } + $outputfd = false; + if (isset($mode)) { + if (!$outputfd = fopen($outputfile, $mode)) { + $err = System::raiseError("Could not open $outputfile"); + return $err; + } + $ret = true; + } + foreach ($files as $file) { + if (!$fd = fopen($file, 'r')) { + System::raiseError("Could not open $file"); + continue; + } + while ($cont = fread($fd, 2048)) { + if (is_resource($outputfd)) { + fwrite($outputfd, $cont); + } else { + $ret .= $cont; + } + } + fclose($fd); + } + if (is_resource($outputfd)) { + fclose($outputfd); + } + return $ret; + } + + /** + * Creates temporary files or directories. This function will remove + * the created files when the scripts finish its execution. + * + * Usage: + * 1) $tempfile = System::mktemp("prefix"); + * 2) $tempdir = System::mktemp("-d prefix"); + * 3) $tempfile = System::mktemp(); + * 4) $tempfile = System::mktemp("-t /var/tmp prefix"); + * + * prefix -> The string that will be prepended to the temp name + * (defaults to "tmp"). + * -d -> A temporary dir will be created instead of a file. + * -t -> The target dir where the temporary (file|dir) will be created. If + * this param is missing by default the env vars TMP on Windows or + * TMPDIR in Unix will be used. If these vars are also missing + * c:\windows\temp or /tmp will be used. + * + * @param string $args The arguments + * @return mixed the full path of the created (file|dir) or false + * @see System::tmpdir() + */ + public static function mktemp($args = null) + { + static $first_time = true; + $opts = System::_parseArgs($args, 't:d'); + if (PEAR::isError($opts)) { + return System::raiseError($opts); + } + + foreach ($opts[0] as $opt) { + if ($opt[0] == 'd') { + $tmp_is_dir = true; + } elseif ($opt[0] == 't') { + $tmpdir = $opt[1]; + } + } + + $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp'; + if (!isset($tmpdir)) { + $tmpdir = System::tmpdir(); + } + + if (!System::mkDir(array('-p', $tmpdir))) { + return false; + } + + $tmp = tempnam($tmpdir, $prefix); + if (isset($tmp_is_dir)) { + unlink($tmp); // be careful possible race condition here + if (!mkdir($tmp, 0700)) { + return System::raiseError("Unable to create temporary directory $tmpdir"); + } + } + + $GLOBALS['_System_temp_files'][] = $tmp; + if (isset($tmp_is_dir)) { + //$GLOBALS['_System_temp_files'][] = dirname($tmp); + } + + if ($first_time) { + PEAR::registerShutdownFunc(array('System', '_removeTmpFiles')); + $first_time = false; + } + + return $tmp; + } + + /** + * Remove temporary files created my mkTemp. This function is executed + * at script shutdown time + */ + public static function _removeTmpFiles() + { + if (count($GLOBALS['_System_temp_files'])) { + $delete = $GLOBALS['_System_temp_files']; + array_unshift($delete, '-r'); + System::rm($delete); + $GLOBALS['_System_temp_files'] = array(); + } + } + + /** + * Get the path of the temporal directory set in the system + * by looking in its environments variables. + * Note: php.ini-recommended removes the "E" from the variables_order setting, + * making unavaible the $_ENV array, that s why we do tests with _ENV + * + * @return string The temporary directory on the system + */ + public static function tmpdir() + { + if (OS_WINDOWS) { + if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) { + return $var; + } + if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) { + return $var; + } + if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) { + return $var; + } + if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) { + return $var; + } + return getenv('SystemRoot') . '\temp'; + } + if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) { + return $var; + } + return realpath(function_exists('sys_get_temp_dir') ? sys_get_temp_dir() : '/tmp'); + } + + /** + * The "which" command (show the full path of a command) + * + * @param string $program The command to search for + * @param mixed $fallback Value to return if $program is not found + * + * @return mixed A string with the full path or false if not found + * @author Stig Bakken + */ + public static function which($program, $fallback = false) + { + // enforce API + if (!is_string($program) || '' == $program) { + return $fallback; + } + + // full path given + if (basename($program) != $program) { + $path_elements[] = dirname($program); + $program = basename($program); + } else { + $path = getenv('PATH'); + if (!$path) { + $path = getenv('Path'); // some OSes are just stupid enough to do this + } + + $path_elements = explode(PATH_SEPARATOR, $path); + } + + if (OS_WINDOWS) { + $exe_suffixes = getenv('PATHEXT') + ? explode(PATH_SEPARATOR, getenv('PATHEXT')) + : array('.exe','.bat','.cmd','.com'); + // allow passing a command.exe param + if (strpos($program, '.') !== false) { + array_unshift($exe_suffixes, ''); + } + } else { + $exe_suffixes = array(''); + } + + foreach ($exe_suffixes as $suff) { + foreach ($path_elements as $dir) { + $file = $dir . DIRECTORY_SEPARATOR . $program . $suff; + // It's possible to run a .bat on Windows that is_executable + // would return false for. The is_executable check is meaningless... + if (OS_WINDOWS) { + if (file_exists($file)) { + return $file; + } + } else { + if (is_executable($file)) { + return $file; + } + } + } + } + return $fallback; + } + + /** + * The "find" command + * + * Usage: + * + * System::find($dir); + * System::find("$dir -type d"); + * System::find("$dir -type f"); + * System::find("$dir -name *.php"); + * System::find("$dir -name *.php -name *.htm*"); + * System::find("$dir -maxdepth 1"); + * + * Params implemented: + * $dir -> Start the search at this directory + * -type d -> return only directories + * -type f -> return only files + * -maxdepth -> max depth of recursion + * -name -> search pattern (bash style). Multiple -name param allowed + * + * @param mixed Either array or string with the command line + * @return array Array of found files + */ + public static function find($args) + { + if (!is_array($args)) { + $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); + } + $dir = realpath(array_shift($args)); + if (!$dir) { + return array(); + } + $patterns = array(); + $depth = 0; + $do_files = $do_dirs = true; + $args_count = count($args); + for ($i = 0; $i < $args_count; $i++) { + switch ($args[$i]) { + case '-type': + if (in_array($args[$i+1], array('d', 'f'))) { + if ($args[$i+1] == 'd') { + $do_files = false; + } else { + $do_dirs = false; + } + } + $i++; + break; + case '-name': + $name = preg_quote($args[$i+1], '#'); + // our magic characters ? and * have just been escaped, + // so now we change the escaped versions to PCRE operators + $name = strtr($name, array('\?' => '.', '\*' => '.*')); + $patterns[] = '('.$name.')'; + $i++; + break; + case '-maxdepth': + $depth = $args[$i+1]; + break; + } + } + $path = System::_dirToStruct($dir, $depth, 0, true); + if ($do_files && $do_dirs) { + $files = array_merge($path['files'], $path['dirs']); + } elseif ($do_dirs) { + $files = $path['dirs']; + } else { + $files = $path['files']; + } + if (count($patterns)) { + $dsq = preg_quote(DIRECTORY_SEPARATOR, '#'); + $pattern = '#(^|'.$dsq.')'.implode('|', $patterns).'($|'.$dsq.')#'; + $ret = array(); + $files_count = count($files); + for ($i = 0; $i < $files_count; $i++) { + // only search in the part of the file below the current directory + $filepart = basename($files[$i]); + if (preg_match($pattern, $filepart)) { + $ret[] = $files[$i]; + } + } + return $ret; + } + return $files; + } +} diff --git a/vendor/pear/pear_exception/LICENSE b/vendor/pear/pear_exception/LICENSE new file mode 100644 index 00000000..a00a2421 --- /dev/null +++ b/vendor/pear/pear_exception/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 1997-2009, + Stig Bakken , + Gregory Beaver , + Helgi รžormar รžorbjรถrnsson , + Tomas V.V.Cox , + Martin Jansen . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/pear/pear_exception/PEAR/Exception.php b/vendor/pear/pear_exception/PEAR/Exception.php new file mode 100644 index 00000000..a8ef6e08 --- /dev/null +++ b/vendor/pear/pear_exception/PEAR/Exception.php @@ -0,0 +1,456 @@ + + * @author Hans Lellelid + * @author Bertrand Mansion + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @link http://pear.php.net/package/PEAR_Exception + * @since File available since Release 1.0.0 + */ + + +/** + * Base PEAR_Exception Class + * + * 1) Features: + * + * - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception)) + * - Definable triggers, shot when exceptions occur + * - Pretty and informative error messages + * - Added more context info available (like class, method or cause) + * - cause can be a PEAR_Exception or an array of mixed + * PEAR_Exceptions/PEAR_ErrorStack warnings + * - callbacks for specific exception classes and their children + * + * 2) Ideas: + * + * - Maybe a way to define a 'template' for the output + * + * 3) Inherited properties from PHP Exception Class: + * + * protected $message + * protected $code + * protected $line + * protected $file + * private $trace + * + * 4) Inherited methods from PHP Exception Class: + * + * __clone + * __construct + * getMessage + * getCode + * getFile + * getLine + * getTraceSafe + * getTraceSafeAsString + * __toString + * + * 5) Usage example + * + * + * require_once 'PEAR/Exception.php'; + * + * class Test { + * function foo() { + * throw new PEAR_Exception('Error Message', ERROR_CODE); + * } + * } + * + * function myLogger($pear_exception) { + * echo $pear_exception->getMessage(); + * } + * // each time a exception is thrown the 'myLogger' will be called + * // (its use is completely optional) + * PEAR_Exception::addObserver('myLogger'); + * $test = new Test; + * try { + * $test->foo(); + * } catch (PEAR_Exception $e) { + * print $e; + * } + * + * + * @category PEAR + * @package PEAR_Exception + * @author Tomas V.V.Cox + * @author Hans Lellelid + * @author Bertrand Mansion + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/PEAR_Exception + * @since Class available since Release 1.0.0 + */ +class PEAR_Exception extends Exception +{ + const OBSERVER_PRINT = -2; + const OBSERVER_TRIGGER = -4; + const OBSERVER_DIE = -8; + protected $cause; + private static $_observers = array(); + private static $_uniqueid = 0; + private $_trace; + + /** + * Supported signatures: + * - PEAR_Exception(string $message); + * - PEAR_Exception(string $message, int $code); + * - PEAR_Exception(string $message, Exception $cause); + * - PEAR_Exception(string $message, Exception $cause, int $code); + * - PEAR_Exception(string $message, PEAR_Error $cause); + * - PEAR_Exception(string $message, PEAR_Error $cause, int $code); + * - PEAR_Exception(string $message, array $causes); + * - PEAR_Exception(string $message, array $causes, int $code); + * + * @param string $message exception message + * @param int|Exception|PEAR_Error|array|null $p2 exception cause + * @param int|null $p3 exception code or null + */ + public function __construct($message, $p2 = null, $p3 = null) + { + if (is_int($p2)) { + $code = $p2; + $this->cause = null; + } elseif (is_object($p2) || is_array($p2)) { + // using is_object allows both Exception and PEAR_Error + if (is_object($p2) && !($p2 instanceof Exception)) { + if (!class_exists('PEAR_Error') || !($p2 instanceof PEAR_Error)) { + throw new PEAR_Exception( + 'exception cause must be Exception, ' . + 'array, or PEAR_Error' + ); + } + } + $code = $p3; + if (is_array($p2) && isset($p2['message'])) { + // fix potential problem of passing in a single warning + $p2 = array($p2); + } + $this->cause = $p2; + } else { + $code = null; + $this->cause = null; + } + parent::__construct($message, (int) $code); + $this->signal(); + } + + /** + * Add an exception observer + * + * @param mixed $callback - A valid php callback, see php func is_callable() + * - A PEAR_Exception::OBSERVER_* constant + * - An array(const PEAR_Exception::OBSERVER_*, + * mixed $options) + * @param string $label The name of the observer. Use this if you want + * to remove it later with removeObserver() + * + * @return void + */ + public static function addObserver($callback, $label = 'default') + { + self::$_observers[$label] = $callback; + } + + /** + * Remove an exception observer + * + * @param string $label Name of the observer + * + * @return void + */ + public static function removeObserver($label = 'default') + { + unset(self::$_observers[$label]); + } + + /** + * Generate a unique ID for an observer + * + * @return int unique identifier for an observer + */ + public static function getUniqueId() + { + return self::$_uniqueid++; + } + + /** + * Send a signal to all observers + * + * @return void + */ + protected function signal() + { + foreach (self::$_observers as $func) { + if (is_callable($func)) { + call_user_func($func, $this); + continue; + } + settype($func, 'array'); + switch ($func[0]) { + case self::OBSERVER_PRINT : + $f = (isset($func[1])) ? $func[1] : '%s'; + printf($f, $this->getMessage()); + break; + case self::OBSERVER_TRIGGER : + $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE; + trigger_error($this->getMessage(), $f); + break; + case self::OBSERVER_DIE : + $f = (isset($func[1])) ? $func[1] : '%s'; + die(printf($f, $this->getMessage())); + break; + default: + trigger_error('invalid observer type', E_USER_WARNING); + } + } + } + + /** + * Return specific error information that can be used for more detailed + * error messages or translation. + * + * This method may be overridden in child exception classes in order + * to add functionality not present in PEAR_Exception and is a placeholder + * to define API + * + * The returned array must be an associative array of parameter => value like so: + *
+     * array('name' => $name, 'context' => array(...))
+     * 
+ * + * @return array + */ + public function getErrorData() + { + return array(); + } + + /** + * Returns the exception that caused this exception to be thrown + * + * @return Exception|array The context of the exception + */ + public function getCause() + { + return $this->cause; + } + + /** + * Function must be public to call on caused exceptions + * + * @param array $causes Array that gets filled. + * + * @return void + */ + public function getCauseMessage(&$causes) + { + $trace = $this->getTraceSafe(); + $cause = array('class' => get_class($this), + 'message' => $this->message, + 'file' => 'unknown', + 'line' => 'unknown'); + if (isset($trace[0])) { + if (isset($trace[0]['file'])) { + $cause['file'] = $trace[0]['file']; + $cause['line'] = $trace[0]['line']; + } + } + $causes[] = $cause; + if ($this->cause instanceof PEAR_Exception) { + $this->cause->getCauseMessage($causes); + } elseif ($this->cause instanceof Exception) { + $causes[] = array('class' => get_class($this->cause), + 'message' => $this->cause->getMessage(), + 'file' => $this->cause->getFile(), + 'line' => $this->cause->getLine()); + } elseif (class_exists('PEAR_Error') && $this->cause instanceof PEAR_Error) { + $causes[] = array('class' => get_class($this->cause), + 'message' => $this->cause->getMessage(), + 'file' => 'unknown', + 'line' => 'unknown'); + } elseif (is_array($this->cause)) { + foreach ($this->cause as $cause) { + if ($cause instanceof PEAR_Exception) { + $cause->getCauseMessage($causes); + } elseif ($cause instanceof Exception) { + $causes[] = array('class' => get_class($cause), + 'message' => $cause->getMessage(), + 'file' => $cause->getFile(), + 'line' => $cause->getLine()); + } elseif (class_exists('PEAR_Error') + && $cause instanceof PEAR_Error + ) { + $causes[] = array('class' => get_class($cause), + 'message' => $cause->getMessage(), + 'file' => 'unknown', + 'line' => 'unknown'); + } elseif (is_array($cause) && isset($cause['message'])) { + // PEAR_ErrorStack warning + $causes[] = array( + 'class' => $cause['package'], + 'message' => $cause['message'], + 'file' => isset($cause['context']['file']) ? + $cause['context']['file'] : + 'unknown', + 'line' => isset($cause['context']['line']) ? + $cause['context']['line'] : + 'unknown', + ); + } + } + } + } + + /** + * Build a backtrace and return it + * + * @return array Backtrace + */ + public function getTraceSafe() + { + if (!isset($this->_trace)) { + $this->_trace = $this->getTrace(); + if (empty($this->_trace)) { + $backtrace = debug_backtrace(); + $this->_trace = array($backtrace[count($backtrace)-1]); + } + } + return $this->_trace; + } + + /** + * Gets the first class of the backtrace + * + * @return string Class name + */ + public function getErrorClass() + { + $trace = $this->getTraceSafe(); + return $trace[0]['class']; + } + + /** + * Gets the first method of the backtrace + * + * @return string Method/function name + */ + public function getErrorMethod() + { + $trace = $this->getTraceSafe(); + return $trace[0]['function']; + } + + /** + * Converts the exception to a string (HTML or plain text) + * + * @return string String representation + * + * @see toHtml() + * @see toText() + */ + public function __toString() + { + if (isset($_SERVER['REQUEST_URI'])) { + return $this->toHtml(); + } + return $this->toText(); + } + + /** + * Generates a HTML representation of the exception + * + * @return string HTML code + */ + public function toHtml() + { + $trace = $this->getTraceSafe(); + $causes = array(); + $this->getCauseMessage($causes); + $html = '' . "\n"; + foreach ($causes as $i => $cause) { + $html .= '\n"; + } + $html .= '' . "\n" + . '' + . '' + . '' . "\n"; + + foreach ($trace as $k => $v) { + $html .= '' + . '' + . '' . "\n"; + } + $html .= '' + . '' + . '' . "\n" + . '
' + . str_repeat('-', $i) . ' ' . $cause['class'] . ': ' + . htmlspecialchars($cause['message']) + . ' in ' . $cause['file'] . ' ' + . 'on line ' . $cause['line'] . '' + . "
Exception trace
#FunctionLocation
' . $k . ''; + if (!empty($v['class'])) { + $html .= $v['class'] . $v['type']; + } + $html .= $v['function']; + $args = array(); + if (!empty($v['args'])) { + foreach ($v['args'] as $arg) { + if (is_null($arg)) { + $args[] = 'null'; + } else if (is_array($arg)) { + $args[] = 'Array'; + } else if (is_object($arg)) { + $args[] = 'Object('.get_class($arg).')'; + } else if (is_bool($arg)) { + $args[] = $arg ? 'true' : 'false'; + } else if (is_int($arg) || is_double($arg)) { + $args[] = $arg; + } else { + $arg = (string)$arg; + $str = htmlspecialchars(substr($arg, 0, 16)); + if (strlen($arg) > 16) { + $str .= '…'; + } + $args[] = "'" . $str . "'"; + } + } + } + $html .= '(' . implode(', ', $args) . ')' + . '' . (isset($v['file']) ? $v['file'] : 'unknown') + . ':' . (isset($v['line']) ? $v['line'] : 'unknown') + . '
' . ($k+1) . '{main} 
'; + return $html; + } + + /** + * Generates text representation of the exception and stack trace + * + * @return string + */ + public function toText() + { + $causes = array(); + $this->getCauseMessage($causes); + $causeMsg = ''; + foreach ($causes as $i => $cause) { + $causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': ' + . $cause['message'] . ' in ' . $cause['file'] + . ' on line ' . $cause['line'] . "\n"; + } + return $causeMsg . $this->getTraceAsString(); + } +} +?> diff --git a/vendor/pear/pear_exception/composer.json b/vendor/pear/pear_exception/composer.json new file mode 100644 index 00000000..9ffba9b3 --- /dev/null +++ b/vendor/pear/pear_exception/composer.json @@ -0,0 +1,41 @@ +{ + "name": "pear/pear_exception", + "description": "The PEAR Exception base class.", + "type": "class", + "keywords": [ + "exception" + ], + "homepage": "https://github.com/pear/PEAR_Exception", + "license": "BSD-2-Clause", + "authors": [ + { + "name": "Helgi Thormar", + "email": "dufuz@php.net" + }, + { + "name": "Greg Beaver", + "email": "cellog@php.net" + } + ], + "require": { + "php": ">=5.2.0" + }, + "autoload": { + "classmap": ["PEAR/"] + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "include-path": [ + "." + ], + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=PEAR_Exception", + "source": "https://github.com/pear/PEAR_Exception" + }, + "require-dev": { + "phpunit/phpunit": "<9" + } +} diff --git a/vendor/pear/spreadsheet_excel_writer/.github/workflows/ci.yaml b/vendor/pear/spreadsheet_excel_writer/.github/workflows/ci.yaml new file mode 100644 index 00000000..f50f2781 --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/.github/workflows/ci.yaml @@ -0,0 +1,60 @@ +# yamllint disable rule:line-length +# yamllint disable rule:braces + +name: Continuous Integration + +on: + pull_request: + push: + branches: + - main + - master + +jobs: + tests: + runs-on: ${{ matrix.operating-system }} + + strategy: + matrix: + operating-system: ['ubuntu-latest'] + php-version: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0'] + + name: CI on ${{ matrix.operating-system }} with PHP ${{ matrix.php-version }} + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + tools: composer:v2 + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: composer-${{ runner.os }}-${{ matrix.php-version }}-${{ hashFiles('composer.*') }}-${{ matrix.composer-flags }} + restore-keys: | + composer-${{ runner.os }}-${{ matrix.php-version }}-${{ hashFiles('composer.*') }}- + composer-${{ runner.os }}-${{ matrix.php-version }}- + composer-${{ runner.os }}- + composer- + + - name: Install dependencies + run: | + composer update --no-interaction --prefer-dist --no-progress ${{ matrix.composer-flags }} + + - name: Run tests + run: | + vendor/bin/phpunit + + - name: Lint code + run: | + find Spreadsheet/ -type f -name \*.php | xargs -n1 php -l diff --git a/vendor/pear/spreadsheet_excel_writer/.github/workflows/cs.yaml b/vendor/pear/spreadsheet_excel_writer/.github/workflows/cs.yaml new file mode 100644 index 00000000..1c13a4ac --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/.github/workflows/cs.yaml @@ -0,0 +1,38 @@ +name: Coding Standards + +on: + pull_request: + push: + branches: + - main + - master + +jobs: + coding-standards: + name: Coding Standards + runs-on: ubuntu-latest + + env: + PHP_CS_FIXER_VERSION: v2.17.3 + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + coverage: none + tools: php-cs-fixer:${{ env.PHP_CS_FIXER_VERSION }} + + - name: Restore PHP-CS-Fixer cache + uses: actions/cache@v2 + with: + path: .php_cs.cache + key: "php-cs-fixer" + restore-keys: "php-cs-fixer" + + - name: Run PHP-CS-Fixer, version ${{ env.PHP_CS_FIXER_VERSION }} + run: | + php-cs-fixer fix --diff --diff-format=udiff --dry-run --verbose diff --git a/vendor/pear/spreadsheet_excel_writer/.gitignore b/vendor/pear/spreadsheet_excel_writer/.gitignore new file mode 100644 index 00000000..8492a7aa --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/.gitignore @@ -0,0 +1,7 @@ +# composer related +composer.lock +composer.phar +vendor + +# build logs +build diff --git a/vendor/pear/spreadsheet_excel_writer/.php_cs.dist b/vendor/pear/spreadsheet_excel_writer/.php_cs.dist new file mode 100644 index 00000000..1af4afee --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/.php_cs.dist @@ -0,0 +1,11 @@ +setRules([ + 'native_function_invocation' => null, + ]) + ->setFinder( + PhpCsFixer\Finder::create() + ->in(__DIR__) + ) +; diff --git a/vendor/pear/spreadsheet_excel_writer/.travis.yml b/vendor/pear/spreadsheet_excel_writer/.travis.yml new file mode 100644 index 00000000..796fc16f --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/.travis.yml @@ -0,0 +1,25 @@ +language: php +php: + - 5.6 + - 7.0 + - 7.1 + - 7.2 + - 7.3 + - 7.4 + +cache: + directories: + - $HOME/.composer/cache + - $HOME/.cache/cache + - build/cache + +install: + - composer install --prefer-dist + - mkdir -p build/cache + +script: + - php vendor/bin/phpunit --coverage-clover build/logs/clover.xml + - vendor/bin/php-cs-fixer --cache-file=build/cache/.php_cs.cache --diff --dry-run --stop-on-violation --verbose fix + +after_success: + - travis_retry php vendor/bin/php-coveralls diff --git a/vendor/pear/spreadsheet_excel_writer/README.md b/vendor/pear/spreadsheet_excel_writer/README.md new file mode 100644 index 00000000..013368b5 --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/README.md @@ -0,0 +1,166 @@ +[![Build Status](https://travis-ci.org/pear/Spreadsheet_Excel_Writer.svg?branch=master)](https://travis-ci.org/pear/Spreadsheet_Excel_Writer) +[![Latest Stable Version](https://poser.pugx.org/pear/spreadsheet_excel_writer/v/stable)](https://packagist.org/packages/pear/spreadsheet_excel_writer) +[![Coverage Status](https://coveralls.io/repos/github/pear/Spreadsheet_Excel_Writer/badge.svg?branch=master)](https://coveralls.io/github/pear/Spreadsheet_Excel_Writer?branch=master) + +# Spreadsheet_Excel_Writer + +This package is [Spreadsheet_Excel_Writer](http://pear.php.net/package/Spreadsheet_Excel_Writer) and has been migrated from [svn.php.net](https://svn.php.net/repository/pear/packages/Spreadsheet_Excel_Writer). + +Please report all new issues [via the PEAR bug tracker](http://pear.php.net/bugs/search.php?cmd=display&package_name[]=Spreadsheet_Excel_Writer&order_by=ts1&direction=DESC&status=Open). + +If this package is marked as unmaintained and you have fixes, please submit your pull requests and start discussion on the pear-qa mailing list. + + +# Installation + +## Pear + +To test, run + + $ phpunit + +To build, simply + + $ pear package + +To install from scratch + + $ pear install package.xml + +To upgrade + + $ pear upgrade -f package.xml + +## Composer + +This package comes with support for Composer. + +To install from Composer + + $ composer require pear/spreadsheet_excel_writer + +To install the latest development version + + $ composer require pear/spreadsheet_excel_writer:dev-master + +# Features + +- writing Excel (.XLS) spreadsheets +- support: strings (with formatting for text and cells), formulas, images (BMP) + +# Limitations +Library support only 2 types of format for writing XLS, also known as Binary Interchange File Format ([BIFF](https://www.openoffice.org/sc/excelfileformat.pdf)): +- BIFF5 (Excel 5.0 - Excel 95) +- BIFF8 (Excel 98 - Excel 2003) + +**Some important limitations:** + +| Limit | BIFF5 | BIFF8 | +| --- | --- | --- | +| Maximum number of rows | 16384 | 65535 | +| Maximum number of columns | 255 | 255 | +| Maximum data size of a record | 2080 bytes | 8224 bytes | +| Unicode support | CodePage based character encoding | UTF-16LE | + +Explanation of formats and specifications you can find [here](https://www.loc.gov/preservation/digital/formats/fdd/fdd000510.shtml) (section "Useful references") + +Correct output only guaranteed with `mbstring.func_overload = 0` otherwise, you should use workround `mb_internal_encoding('latin1');` + +# Usage + +## Basic usage +```php +use Spreadsheet_Excel_Writer; + + +$filePath = __DIR__ . '/output/out.xls'; +$xls = new Spreadsheet_Excel_Writer($filePath); + +// 8 = BIFF8 +$xls->setVersion(8); + +$sheet = $xls->addWorksheet('info'); + +// only available with BIFF8 +$sheet->setInputEncoding('UTF-8'); + +$headers = [ + 'id', + 'name', + 'email', + 'code', + 'address' +]; + +$row = $col = 0; +foreach ($headers as $header) { + $sheet->write($row, $col, $header); + $col++; +} + +for ($id = 1; $id < 100; $id++) { + $data = [ + 'id' => $id, + 'name' => 'Name Surname', + 'email' => 'mail@gmail.com', + 'password' => 'cfcd208495d565ef66e7dff9f98764da', + 'address' => '00000 North Tantau Avenue. Cupertino, CA 12345. (000) 1234567' + ]; + $sheet->writeRow($id, 0, $data); +} + +$xls->close(); +``` + +## Format usage +```php +$xls = new Spreadsheet_Excel_Writer(); + +$titleFormat = $xls->addFormat(); +$titleFormat->setFontFamily('Helvetica'); +$titleFormat->setBold(); +$titleFormat->setSize(10); +$titleFormat->setColor('orange'); +$titleFormat->setBorder(1); +$titleFormat->setBottom(2); +$titleFormat->setBottomColor(44); +$titleFormat->setAlign('center'); + +$sheet = $xls->addWorksheet('info'); + +$sheet->write(0, 0, 'Text 123', $titleFormat); +``` + +## Header usage (Sending HTTP header for download dialog) +```php +$xls = new Spreadsheet_Excel_Writer(); +$xls->send('excel_'.date("Y-m-d__H:i:s").'.xls'); +``` + + +# Performance + +**Platform:** +Intel(R) Core(TM) i5-4670 CPU @ 3.40GHz +PHP 7.4 + +**Test case:** +Write xls (BIFF8 format, UTF-8), by 5 cells (1x number, 4x string without format/styles, average line length = 120 char) in each row + +**Estimated performance:** + +| Number of rows | Time (seconds) | Peak memory usage (MB) | +| --- | --- | --- | +| 10000 | 0.2 | 4 | +| 20000 | 0.4 | 4 | +| 30000 | 0.6 | 6 | +| 40000 | 0.8 | 6 | +| 50000 | 1.0 | 8 | +| 65534 | 1.2 | 8 | + +# Alternative solutions + +- [PHPOffice/PhpSpreadsheet](https://github.com/PHPOffice/PhpSpreadsheet) +File formats supported: https://phpspreadsheet.readthedocs.io/en/latest/ +- [box/spout](https://github.com/box/spout) +File formats supported: https://opensource.box.com/spout/ diff --git a/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer.php b/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer.php new file mode 100644 index 00000000..8bb710c1 --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer.php @@ -0,0 +1,105 @@ + +* +* PERL Spreadsheet::WriteExcel module. +* +* The author of the Spreadsheet::WriteExcel module is John McNamara +* +* +* I _DO_ maintain this code, and John McNamara has nothing to do with the +* porting of this code to PHP. Any questions directly related to this +* class library should be directed to me. +* +* License Information: +* +* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets +* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +if (!class_exists('Spreadsheet_Excel_Writer_Workbook')) { + require_once 'Spreadsheet/Excel/Writer/Workbook.php'; +} + +/** +* Class for writing Excel Spreadsheets. This class should change COMPLETELY. +* +* @author Xavier Noguer +* @category FileFormats +* @package Spreadsheet_Excel_Writer +*/ + +class Spreadsheet_Excel_Writer extends Spreadsheet_Excel_Writer_Workbook +{ + /** + * The constructor. It just creates a Workbook + * + * @param string $filename The optional filename for the Workbook. + * @return Spreadsheet_Excel_Writer_Workbook The Workbook created + */ + public function __construct($filename = '') + { + $this->_filename = $filename; + parent::__construct($filename); + } + + /** + * Send HTTP headers for the Excel file. + * + * @param string $filename The filename to use for HTTP headers + * @access public + */ + public function send($filename) + { + $filename = addslashes($filename); + header("Content-type: application/vnd.ms-excel"); + header("Content-Disposition: attachment; filename=\"$filename\""); + header("Expires: 0"); + header("Cache-Control: must-revalidate, post-check=0,pre-check=0"); + header("Pragma: public"); + } + + /** + * Utility function for writing formulas + * Converts a cell's coordinates to the A1 format. + * + * @access public + * @static + * @param integer $row Row for the cell to convert (0-indexed). + * @param integer $col Column for the cell to convert (0-indexed). + * @return string The cell identifier in A1 format + */ + function rowcolToCell($row, $col) + { + if ($col > 255) { //maximum column value exceeded + return new PEAR_Error("Maximum column value exceeded: $col"); + } + + $int = (int)($col / 26); + $frac = $col % 26; + $chr1 = ''; + + if ($int > 0) { + $chr1 = chr(ord('A') + $int - 1); + } + + $chr2 = chr(ord('A') + $frac); + $row++; + + return $chr1 . $chr2 . $row; + } +} \ No newline at end of file diff --git a/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/BIFFwriter.php b/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/BIFFwriter.php new file mode 100644 index 00000000..9d598946 --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/BIFFwriter.php @@ -0,0 +1,268 @@ + +* +* The majority of this is _NOT_ my code. I simply ported it from the +* PERL Spreadsheet::WriteExcel module. +* +* The author of the Spreadsheet::WriteExcel module is John McNamara +* +* +* I _DO_ maintain this code, and John McNamara has nothing to do with the +* porting of this code to PHP. Any questions directly related to this +* class library should be directed to me. +* +* License Information: +* +* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets +* Copyright (c) 2002-2003 Xavier Noguer xnoguer@php.net +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +if (!class_exists('PEAR')) { + require_once 'PEAR.php'; +} + +/** +* Class for writing Excel BIFF records. +* +* From "MICROSOFT EXCEL BINARY FILE FORMAT" by Mark O'Brien (Microsoft Corporation): +* +* BIFF (BInary File Format) is the file format in which Excel documents are +* saved on disk. A BIFF file is a complete description of an Excel document. +* BIFF files consist of sequences of variable-length records. There are many +* different types of BIFF records. For example, one record type describes a +* formula entered into a cell; one describes the size and location of a +* window into a document; another describes a picture format. +* +* @author Xavier Noguer +* @category FileFormats +* @package Spreadsheet_Excel_Writer +*/ + +class Spreadsheet_Excel_Writer_BIFFwriter extends PEAR +{ + /** + * The BIFF/Excel version (5). + * @var integer + */ + public $_BIFF_version = 0x0500; + + /** + * The byte order of this architecture. 0 => little endian, 1 => big endian + * @var integer + */ + public $_byte_order; + + /** + * The string containing the data of the BIFF stream + * @var string + */ + public $_data; + + /** + * The size of the data in bytes. Should be the same as strlen($this->_data) + * @var integer + */ + public $_datasize; + + /** + * The maximun length for a BIFF record. See _addContinue() + * @var integer + * @see _addContinue() + */ + public $_limit; + + /** + * The temporary dir for storing the OLE file + * @var string + */ + public $_tmp_dir; + + /** + * The temporary file for storing the OLE file + * @var string + */ + public $_tmp_file; + + /** + * Constructor + * + * @access public + */ + public function __construct() + { + $this->_byte_order = ''; + $this->_data = ''; + $this->_datasize = 0; + $this->_limit = 2080; + $this->_tmp_dir = ''; + // Set the byte order + $this->_setByteOrder(); + } + + /** + * Determine the byte order and store it as class data to avoid + * recalculating it for each call to new(). + * + * @access private + */ + protected function _setByteOrder() + { + // Check if "pack" gives the required IEEE 64bit float + $teststr = pack("d", 1.2345); + $number = pack("C8", 0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F); + if ($number == $teststr) { + $byte_order = 0; // Little Endian + } elseif ($number == strrev($teststr)){ + $byte_order = 1; // Big Endian + } else { + // Give up. I'll fix this in a later version. + return $this->raiseError("Required floating point format ". + "not supported on this platform."); + } + $this->_byte_order = $byte_order; + } + + /** + * General storage public function + * + * @param string $data binary data to prepend + * @access private + */ + protected function _prepend($data) + { + if (strlen($data) > $this->_limit) { + $data = $this->_addContinue($data); + } + $this->_data = $data.$this->_data; + $this->_datasize += strlen($data); + } + + /** + * General storage public function + * + * @param string $data binary data to append + * @access private + */ + protected function _append($data) + { + if (strlen($data) > $this->_limit) { + $data = $this->_addContinue($data); + } + $this->_data .= $data; + $this->_datasize += strlen($data); + } + + /** + * Writes Excel BOF record to indicate the beginning of a stream or + * sub-stream in the BIFF file. + * + * @param integer $type Type of BIFF file to write: 0x0005 Workbook, + * 0x0010 Worksheet. + * @access private + */ + protected function _storeBof($type) + { + $record = 0x0809; // Record identifier + + // According to the SDK $build and $year should be set to zero. + // However, this throws a warning in Excel 5. So, use magic numbers. + if ($this->_BIFF_version == 0x0500) { + $length = 0x0008; + $unknown = ''; + $build = 0x096C; + $year = 0x07C9; + } elseif ($this->_BIFF_version == 0x0600) { + $length = 0x0010; + $unknown = pack("VV", 0x00000041, 0x00000006); //unknown last 8 bytes for BIFF8 + $build = 0x0DBB; + $year = 0x07CC; + } + $version = $this->_BIFF_version; + + $header = pack("vv", $record, $length); + $data = pack("vvvv", $version, $type, $build, $year); + $this->_prepend($header . $data . $unknown); + } + + /** + * Writes Excel EOF record to indicate the end of a BIFF stream. + * + * @access private + */ + protected function _storeEof() + { + $record = 0x000A; // Record identifier + $length = 0x0000; // Number of bytes to follow + $header = pack("vv", $record, $length); + $this->_append($header); + } + + /** + * Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In + * Excel 97 the limit is 8228 bytes. Records that are longer than these limits + * must be split up into CONTINUE blocks. + * + * This public function takes a long BIFF record and inserts CONTINUE records as + * necessary. + * + * @param string $data The original binary data to be written + * @return string A very convenient string of continue blocks + * @access private + */ + protected function _addContinue($data) + { + $limit = $this->_limit; + $record = 0x003C; // Record identifier + + // The first 2080/8224 bytes remain intact. However, we have to change + // the length field of the record. + $tmp = substr($data, 0, 2).pack("v", $limit-4).substr($data, 4, $limit - 4); + + $header = pack("vv", $record, $limit); // Headers for continue records + + // Retrieve chunks of 2080/8224 bytes +4 for the header. + $data_length = strlen($data); + for ($i = $limit; $i < ($data_length - $limit); $i += $limit) { + $tmp .= $header; + $tmp .= substr($data, $i, $limit); + } + + // Retrieve the last chunk of data + $header = pack("vv", $record, strlen($data) - $i); + $tmp .= $header; + $tmp .= substr($data, $i, strlen($data) - $i); + + return $tmp; + } + + /** + * Sets the temp dir used for storing the OLE file + * + * @access public + * @param string $dir The dir to be used as temp dir + * @return true if given dir is valid, false otherwise + */ + public function setTempDir($dir) + { + if (is_dir($dir)) { + $this->_tmp_dir = $dir; + return true; + } + return false; + } +} \ No newline at end of file diff --git a/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Format.php b/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Format.php new file mode 100644 index 00000000..c19d4e53 --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Format.php @@ -0,0 +1,1110 @@ + +* +* The majority of this is _NOT_ my code. I simply ported it from the +* PERL Spreadsheet::WriteExcel module. +* +* The author of the Spreadsheet::WriteExcel module is John McNamara +* +* +* I _DO_ maintain this code, and John McNamara has nothing to do with the +* porting of this code to PHP. Any questions directly related to this +* class library should be directed to me. +* +* License Information: +* +* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets +* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +if (!class_exists('PEAR')) { + require_once 'PEAR.php'; +} + +/** +* Class for generating Excel XF records (formats) +* +* @author Xavier Noguer +* @category FileFormats +* @package Spreadsheet_Excel_Writer +*/ + +class Spreadsheet_Excel_Writer_Format extends PEAR +{ + /** + * The index given by the workbook when creating a new format. + * @var integer + */ + public $_xf_index; + + /** + * Index to the FONT record. + * @var integer + */ + public $font_index; + + /** + * The font name (ASCII). + * @var string + */ + public $_font_name; + + /** + * Height of font (1/20 of a point) + * @var integer + */ + public $_size; + + /** + * Bold style + * @var integer + */ + public $_bold; + + /** + * Bit specifiying if the font is italic. + * @var integer + */ + public $_italic; + + /** + * Index to the cell's color + * @var integer + */ + public $_color; + + /** + * The text underline property + * @var integer + */ + public $_underline; + + /** + * Bit specifiying if the font has strikeout. + * @var integer + */ + public $_font_strikeout; + + /** + * Bit specifiying if the font has outline. + * @var integer + */ + public $_font_outline; + + /** + * Bit specifiying if the font has shadow. + * @var integer + */ + public $_font_shadow; + + /** + * 2 bytes specifiying the script type for the font. + * @var integer + */ + public $_font_script; + + /** + * Byte specifiying the font family. + * @var integer + */ + public $_font_family; + + /** + * Byte specifiying the font charset. + * @var integer + */ + public $_font_charset; + + /** + * An index (2 bytes) to a FORMAT record (number format). + * @var integer + */ + public $_num_format; + + /** + * Bit specifying if formulas are hidden. + * @var integer + */ + public $_hidden; + + /** + * Bit specifying if the cell is locked. + * @var integer + */ + public $_locked; + + /** + * The three bits specifying the text horizontal alignment. + * @var integer + */ + public $_text_h_align; + + /** + * Bit specifying if the text is wrapped at the right border. + * @var integer + */ + public $_text_wrap; + + /** + * The three bits specifying the text vertical alignment. + * @var integer + */ + public $_text_v_align; + + /** + * 1 bit, apparently not used. + * @var integer + */ + public $_text_justlast; + + /** + * The two bits specifying the text rotation. + * @var integer + */ + public $_rotation; + + /** + * The cell's foreground color. + * @var integer + */ + public $_fg_color; + + /** + * The cell's background color. + * @var integer + */ + public $_bg_color; + + /** + * The cell's background fill pattern. + * @var integer + */ + public $_pattern; + + /** + * Style of the bottom border of the cell + * @var integer + */ + public $_bottom; + + /** + * Color of the bottom border of the cell. + * @var integer + */ + public $_bottom_color; + + /** + * Style of the top border of the cell + * @var integer + */ + public $_top; + + /** + * Color of the top border of the cell. + * @var integer + */ + public $_top_color; + + /** + * Style of the left border of the cell + * @var integer + */ + public $_left; + + /** + * Color of the left border of the cell. + * @var integer + */ + public $_left_color; + + /** + * Style of the right border of the cell + * @var integer + */ + public $_right; + + /** + * Color of the right border of the cell. + * @var integer + */ + public $_right_color; + + /** + * Constructor + * + * @access private + * @param integer $index the XF index for the format. + * @param array $properties array with properties to be set on initialization. + */ + public function __construct($BIFF_version, $index = 0, $properties = array()) + { + $this->_xf_index = $index; + $this->_BIFF_version = $BIFF_version; + $this->font_index = 0; + $this->_font_name = 'Arial'; + $this->_size = 10; + $this->_bold = 0x0190; + $this->_italic = 0; + $this->_color = 0x7FFF; + $this->_underline = 0; + $this->_font_strikeout = 0; + $this->_font_outline = 0; + $this->_font_shadow = 0; + $this->_font_script = 0; + $this->_font_family = 0; + $this->_font_charset = 0; + + $this->_num_format = 0; + + $this->_hidden = 0; + $this->_locked = 0; + + $this->_text_h_align = 0; + $this->_text_wrap = 0; + $this->_text_v_align = 2; + $this->_text_justlast = 0; + $this->_rotation = 0; + + $this->_fg_color = 0x40; + $this->_bg_color = 0x41; + + $this->_pattern = 0; + + $this->_bottom = 0; + $this->_top = 0; + $this->_left = 0; + $this->_right = 0; + $this->_diag = 0; + + $this->_bottom_color = 0x40; + $this->_top_color = 0x40; + $this->_left_color = 0x40; + $this->_right_color = 0x40; + $this->_diag_color = 0x40; + + // Set properties passed to Spreadsheet_Excel_Writer_Workbook::addFormat() + foreach ($properties as $property => $value) + { + if (method_exists($this, 'set'.ucwords($property))) { + $method_name = 'set'.ucwords($property); + $this->$method_name($value); + } + } + } + + + /** + * Generate an Excel BIFF XF record (style or cell). + * + * @param string $style The type of the XF record ('style' or 'cell'). + * @return string The XF record + */ + public function getXf($style) + { + // Set the type of the XF record and some of the attributes. + if ($style == 'style') { + $style = 0xFFF5; + } else { + $style = $this->_locked; + $style |= $this->_hidden << 1; + } + + // Flags to indicate if attributes have been set. + $atr_num = ($this->_num_format != 0)?1:0; + $atr_fnt = ($this->font_index != 0)?1:0; + $atr_alc = ($this->_text_wrap)?1:0; + $atr_bdr = ($this->_bottom || + $this->_top || + $this->_left || + $this->_right)?1:0; + $atr_pat = (($this->_fg_color != 0x40) || + ($this->_bg_color != 0x41) || + $this->_pattern)?1:0; + $atr_prot = $this->_locked | $this->_hidden; + + // Zero the default border colour if the border has not been set. + if ($this->_bottom == 0) { + $this->_bottom_color = 0; + } + if ($this->_top == 0) { + $this->_top_color = 0; + } + if ($this->_right == 0) { + $this->_right_color = 0; + } + if ($this->_left == 0) { + $this->_left_color = 0; + } + if ($this->_diag == 0) { + $this->_diag_color = 0; + } + + $record = 0x00E0; // Record identifier + if ($this->_BIFF_version == 0x0500) { + $length = 0x0010; // Number of bytes to follow + } + if ($this->_BIFF_version == 0x0600) { + $length = 0x0014; + } + + $ifnt = $this->font_index; // Index to FONT record + $ifmt = $this->_num_format; // Index to FORMAT record + if ($this->_BIFF_version == 0x0500) { + $align = $this->_text_h_align; // Alignment + $align |= $this->_text_wrap << 3; + $align |= $this->_text_v_align << 4; + $align |= $this->_text_justlast << 7; + $align |= $this->_rotation << 8; + $align |= $atr_num << 10; + $align |= $atr_fnt << 11; + $align |= $atr_alc << 12; + $align |= $atr_bdr << 13; + $align |= $atr_pat << 14; + $align |= $atr_prot << 15; + + $icv = $this->_fg_color; // fg and bg pattern colors + $icv |= $this->_bg_color << 7; + + $fill = $this->_pattern; // Fill and border line style + $fill |= $this->_bottom << 6; + $fill |= $this->_bottom_color << 9; + + $border1 = $this->_top; // Border line style and color + $border1 |= $this->_left << 3; + $border1 |= $this->_right << 6; + $border1 |= $this->_top_color << 9; + + $border2 = $this->_left_color; // Border color + $border2 |= $this->_right_color << 7; + + $header = pack("vv", $record, $length); + $data = pack("vvvvvvvv", $ifnt, $ifmt, $style, $align, + $icv, $fill, + $border1, $border2); + } elseif ($this->_BIFF_version == 0x0600) { + $align = $this->_text_h_align; // Alignment + $align |= $this->_text_wrap << 3; + $align |= $this->_text_v_align << 4; + $align |= $this->_text_justlast << 7; + + $used_attrib = $atr_num << 2; + $used_attrib |= $atr_fnt << 3; + $used_attrib |= $atr_alc << 4; + $used_attrib |= $atr_bdr << 5; + $used_attrib |= $atr_pat << 6; + $used_attrib |= $atr_prot << 7; + + $icv = $this->_fg_color; // fg and bg pattern colors + $icv |= $this->_bg_color << 7; + + $border1 = $this->_left; // Border line style and color + $border1 |= $this->_right << 4; + $border1 |= $this->_top << 8; + $border1 |= $this->_bottom << 12; + $border1 |= $this->_left_color << 16; + $border1 |= $this->_right_color << 23; + $diag_tl_to_rb = 0; // FIXME: add method + $diag_tr_to_lb = 0; // FIXME: add method + $border1 |= $diag_tl_to_rb << 30; + $border1 |= $diag_tr_to_lb << 31; + + $border2 = $this->_top_color; // Border color + $border2 |= $this->_bottom_color << 7; + $border2 |= $this->_diag_color << 14; + $border2 |= $this->_diag << 21; + $border2 |= $this->_pattern << 26; + + $header = pack("vv", $record, $length); + + $rotation = $this->_rotation; + $biff8_options = 0x00; + $data = pack("vvvC", $ifnt, $ifmt, $style, $align); + $data .= pack("CCC", $rotation, $biff8_options, $used_attrib); + $data .= pack("VVv", $border1, $border2, $icv); + } + + return($header . $data); + } + + /** + * Generate an Excel BIFF FONT record. + * + * @return string The FONT record + */ + public function getFont() + { + $dyHeight = $this->_size * 20; // Height of font (1/20 of a point) + $icv = $this->_color; // Index to color palette + $bls = $this->_bold; // Bold style + $sss = $this->_font_script; // Superscript/subscript + $uls = $this->_underline; // Underline + $bFamily = $this->_font_family; // Font family + $bCharSet = $this->_font_charset; // Character set + $encoding = 0; // TODO: Unicode support + + $cch = strlen($this->_font_name); // Length of font name + $record = 0x31; // Record identifier + if ($this->_BIFF_version == 0x0500) { + $length = 0x0F + $cch; // Record length + } elseif ($this->_BIFF_version == 0x0600) { + $length = 0x10 + $cch; + } + $reserved = 0x00; // Reserved + $grbit = 0x00; // Font attributes + if ($this->_italic) { + $grbit |= 0x02; + } + if ($this->_font_strikeout) { + $grbit |= 0x08; + } + if ($this->_font_outline) { + $grbit |= 0x10; + } + if ($this->_font_shadow) { + $grbit |= 0x20; + } + + $header = pack("vv", $record, $length); + if ($this->_BIFF_version == 0x0500) { + $data = pack("vvvvvCCCCC", $dyHeight, $grbit, $icv, $bls, + $sss, $uls, $bFamily, + $bCharSet, $reserved, $cch); + } elseif ($this->_BIFF_version == 0x0600) { + $data = pack("vvvvvCCCCCC", $dyHeight, $grbit, $icv, $bls, + $sss, $uls, $bFamily, + $bCharSet, $reserved, $cch, $encoding); + } + return($header . $data . $this->_font_name); + } + + /** + * Returns a unique hash key for a font. + * Used by Spreadsheet_Excel_Writer_Workbook::_storeAllFonts() + * + * The elements that form the key are arranged to increase the probability of + * generating a unique key. Elements that hold a large range of numbers + * (eg. _color) are placed between two binary elements such as _italic + * + * @return string A key for this font + */ + public function getFontKey() + { + $key = "$this->_font_name$this->_size"; + $key .= "$this->_font_script$this->_underline"; + $key .= "$this->_font_strikeout$this->_bold$this->_font_outline"; + $key .= "$this->_font_family$this->_font_charset"; + $key .= "$this->_font_shadow$this->_color$this->_italic"; + $key = str_replace(' ', '_', $key); + return ($key); + } + + /** + * Returns the index used by Spreadsheet_Excel_Writer_Worksheet::_XF() + * + * @return integer The index for the XF record + */ + public function getXfIndex() + { + return($this->_xf_index); + } + + /** + * Used in conjunction with the set_xxx_color methods to convert a color + * string into a number. Color range is 0..63 but we will restrict it + * to 8..63 to comply with Gnumeric. Colors 0..7 are repeated in 8..15. + * + * @access private + * @param string $name_color name of the color (i.e.: 'blue', 'red', etc..). Optional. + * @return integer The color index + */ + protected function _getColor($name_color = '') + { + $colors = array( + 'aqua' => 0x07, + 'cyan' => 0x07, + 'black' => 0x00, + 'blue' => 0x04, + 'brown' => 0x10, + 'magenta' => 0x06, + 'fuchsia' => 0x06, + 'gray' => 0x17, + 'grey' => 0x17, + 'green' => 0x11, + 'lime' => 0x03, + 'navy' => 0x12, + 'orange' => 0x35, + 'purple' => 0x14, + 'red' => 0x02, + 'silver' => 0x16, + 'white' => 0x01, + 'yellow' => 0x05 + ); + + // Return the default color, 0x7FFF, if undef, + if ($name_color === '') { + return(0x7FFF); + } + + // or the color string converted to an integer, + if (isset($colors[$name_color])) { + return($colors[$name_color]); + } + + // or the default color if string is unrecognised, + if (preg_match("/\D/",$name_color)) { + return(0x7FFF); + } + + // or the default color if arg is outside range, + if ($name_color > 63) { + return(0x7FFF); + } + + // or an integer in the valid range + return($name_color); + } + + /** + * Set cell alignment. + * + * @access public + * @param string $location alignment for the cell ('left', 'right', etc...). + */ + public function setAlign($location) + { + if (preg_match("/\d/",$location)) { + return; // Ignore numbers + } + + $location = strtolower($location); + + if ($location == 'left') { + $this->_text_h_align = 1; + } + if ($location == 'centre') { + $this->_text_h_align = 2; + } + if ($location == 'center') { + $this->_text_h_align = 2; + } + if ($location == 'right') { + $this->_text_h_align = 3; + } + if ($location == 'fill') { + $this->_text_h_align = 4; + } + if ($location == 'justify') { + $this->_text_h_align = 5; + } + if ($location == 'merge') { + $this->_text_h_align = 6; + } + if ($location == 'equal_space') { // For T.K. + $this->_text_h_align = 7; + } + if ($location == 'top') { + $this->_text_v_align = 0; + } + if ($location == 'vcentre') { + $this->_text_v_align = 1; + } + if ($location == 'vcenter') { + $this->_text_v_align = 1; + } + if ($location == 'bottom') { + $this->_text_v_align = 2; + } + if ($location == 'vjustify') { + $this->_text_v_align = 3; + } + if ($location == 'vequal_space') { // For T.K. + $this->_text_v_align = 4; + } + } + + /** + * Set cell horizontal alignment. + * + * @access public + * @param string $location alignment for the cell ('left', 'right', etc...). + */ + public function setHAlign($location) + { + if (preg_match("/\d/",$location)) { + return; // Ignore numbers + } + + $location = strtolower($location); + + if ($location == 'left') { + $this->_text_h_align = 1; + } + if ($location == 'centre') { + $this->_text_h_align = 2; + } + if ($location == 'center') { + $this->_text_h_align = 2; + } + if ($location == 'right') { + $this->_text_h_align = 3; + } + if ($location == 'fill') { + $this->_text_h_align = 4; + } + if ($location == 'justify') { + $this->_text_h_align = 5; + } + if ($location == 'merge') { + $this->_text_h_align = 6; + } + if ($location == 'equal_space') { // For T.K. + $this->_text_h_align = 7; + } + } + + /** + * Set cell vertical alignment. + * + * @access public + * @param string $location alignment for the cell ('top', 'vleft', 'vright', etc...). + */ + public function setVAlign($location) + { + if (preg_match("/\d/",$location)) { + return; // Ignore numbers + } + + $location = strtolower($location); + + if ($location == 'top') { + $this->_text_v_align = 0; + } + if ($location == 'vcentre') { + $this->_text_v_align = 1; + } + if ($location == 'vcenter') { + $this->_text_v_align = 1; + } + if ($location == 'bottom') { + $this->_text_v_align = 2; + } + if ($location == 'vjustify') { + $this->_text_v_align = 3; + } + if ($location == 'vequal_space') { // For T.K. + $this->_text_v_align = 4; + } + } + + /** + * This is an alias for the unintuitive setAlign('merge') + * + * @access public + */ + public function setMerge() + { + $this->setAlign('merge'); + } + + /** + * Sets the boldness of the text. + * Bold has a range 100..1000. + * 0 (400) is normal. 1 (700) is bold. + * + * @access public + * @param integer $weight Weight for the text, 0 maps to 400 (normal text), + 1 maps to 700 (bold text). Valid range is: 100-1000. + It's Optional, default is 1 (bold). + */ + public function setBold($weight = 1) + { + if ($weight == 1) { + $weight = 0x2BC; // Bold text + } + if ($weight == 0) { + $weight = 0x190; // Normal text + } + if ($weight < 0x064) { + $weight = 0x190; // Lower bound + } + if ($weight > 0x3E8) { + $weight = 0x190; // Upper bound + } + $this->_bold = $weight; + } + + + /************************************ + * FUNCTIONS FOR SETTING CELLS BORDERS + */ + + /** + * Sets the width for the bottom border of the cell + * + * @access public + * @param integer $style style of the cell border. 1 => thin, 2 => thick. + */ + public function setBottom($style) + { + $this->_bottom = $style; + } + + /** + * Sets the width for the top border of the cell + * + * @access public + * @param integer $style style of the cell top border. 1 => thin, 2 => thick. + */ + public function setTop($style) + { + $this->_top = $style; + } + + /** + * Sets the width for the left border of the cell + * + * @access public + * @param integer $style style of the cell left border. 1 => thin, 2 => thick. + */ + public function setLeft($style) + { + $this->_left = $style; + } + + /** + * Sets the width for the right border of the cell + * + * @access public + * @param integer $style style of the cell right border. 1 => thin, 2 => thick. + */ + public function setRight($style) + { + $this->_right = $style; + } + + + /** + * Set cells borders to the same style + * + * @access public + * @param integer $style style to apply for all cell borders. 1 => thin, 2 => thick. + */ + public function setBorder($style) + { + $this->setBottom($style); + $this->setTop($style); + $this->setLeft($style); + $this->setRight($style); + } + + + /******************************************* + * FUNCTIONS FOR SETTING CELLS BORDERS COLORS + */ + + /** + * Sets all the cell's borders to the same color + * + * @access public + * @param mixed $color The color we are setting. Either a string (like 'blue'), + * or an integer (range is [8...63]). + */ + public function setBorderColor($color) + { + $this->setBottomColor($color); + $this->setTopColor($color); + $this->setLeftColor($color); + $this->setRightColor($color); + } + + /** + * Sets the cell's bottom border color + * + * @access public + * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). + */ + public function setBottomColor($color) + { + $value = $this->_getColor($color); + $this->_bottom_color = $value; + } + + /** + * Sets the cell's top border color + * + * @access public + * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). + */ + public function setTopColor($color) + { + $value = $this->_getColor($color); + $this->_top_color = $value; + } + + /** + * Sets the cell's left border color + * + * @access public + * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). + */ + public function setLeftColor($color) + { + $value = $this->_getColor($color); + $this->_left_color = $value; + } + + /** + * Sets the cell's right border color + * + * @access public + * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). + */ + public function setRightColor($color) + { + $value = $this->_getColor($color); + $this->_right_color = $value; + } + + + /** + * Sets the cell's foreground color + * + * @access public + * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). + */ + public function setFgColor($color) + { + $value = $this->_getColor($color); + $this->_fg_color = $value; + if ($this->_pattern == 0) { // force color to be seen + $this->_pattern = 1; + } + } + + /** + * Sets the cell's background color + * + * @access public + * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). + */ + public function setBgColor($color) + { + $value = $this->_getColor($color); + $this->_bg_color = $value; + if ($this->_pattern == 0) { // force color to be seen + $this->_pattern = 1; + } + } + + /** + * Sets the cell's color + * + * @access public + * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]). + */ + public function setColor($color) + { + $value = $this->_getColor($color); + $this->_color = $value; + } + + /** + * Sets the fill pattern attribute of a cell + * + * @access public + * @param integer $arg Optional. Defaults to 1. Meaningful values are: 0-18, + * 0 meaning no background. + */ + public function setPattern($arg = 1) + { + $this->_pattern = $arg; + } + + /** + * Sets the underline of the text + * + * @access public + * @param integer $underline The value for underline. Possible values are: + * 1 => underline, 2 => double underline. + */ + public function setUnderline($underline) + { + $this->_underline = $underline; + } + + /** + * Sets the font style as italic + * + * @access public + */ + public function setItalic() + { + $this->_italic = 1; + } + + /** + * Sets the font size + * + * @access public + * @param integer $size The font size (in pixels I think). + */ + public function setSize($size) + { + $this->_size = $size; + } + + /** + * Sets text wrapping + * + * @access public + */ + public function setTextWrap() + { + $this->_text_wrap = 1; + } + + /** + * Sets the orientation of the text + * + * @access public + * @param integer $angle The rotation angle for the text (clockwise). Possible + values are: 0, 90, 270 and -1 for stacking top-to-bottom. + */ + public function setTextRotation($angle) + { + switch ($angle) + { + case 0: + $this->_rotation = 0; + break; + case 90: + if ($this->_BIFF_version == 0x0500) { + $this->_rotation = 3; + } elseif ($this->_BIFF_version == 0x0600) { + $this->_rotation = 180; + } + break; + case 270: + if ($this->_BIFF_version == 0x0500) { + $this->_rotation = 2; + } elseif ($this->_BIFF_version == 0x0600) { + $this->_rotation = 90; + } + break; + case -1: + if ($this->_BIFF_version == 0x0500) { + $this->_rotation = 1; + } elseif ($this->_BIFF_version == 0x0600) { + $this->_rotation = 255; + } + break; + default : + return $this->raiseError("Invalid value for angle.". + " Possible values are: 0, 90, 270 and -1 ". + "for stacking top-to-bottom."); + $this->_rotation = 0; + break; + } + } + + /** + * Sets the numeric format. + * It can be date, time, currency, etc... + * + * @access public + * @param integer $num_format The numeric format. + */ + public function setNumFormat($num_format) + { + $this->_num_format = $num_format; + } + + /** + * Sets font as strikeout. + * + * @access public + */ + public function setStrikeOut() + { + $this->_font_strikeout = 1; + } + + /** + * Sets outlining for a font. + * + * @access public + */ + public function setOutLine() + { + $this->_font_outline = 1; + } + + /** + * Sets font as shadow. + * + * @access public + */ + public function setShadow() + { + $this->_font_shadow = 1; + } + + /** + * Sets the script type of the text + * + * @access public + * @param integer $script The value for script type. Possible values are: + * 1 => superscript, 2 => subscript. + */ + public function setScript($script) + { + $this->_font_script = $script; + } + + /** + * Locks a cell. + * + * @access public + */ + public function setLocked() + { + $this->_locked = 1; + } + + /** + * Unlocks a cell. Useful for unprotecting particular cells of a protected sheet. + * + * @access public + */ + public function setUnLocked() + { + $this->_locked = 0; + } + + /** + * Sets the font family name. + * + * @access public + * @param string $fontfamily The font family name. Possible values are: + * 'Times New Roman', 'Arial', 'Courier'. + */ + public function setFontFamily($font_family) + { + $this->_font_name = $font_family; + } +} \ No newline at end of file diff --git a/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Parser.php b/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Parser.php new file mode 100644 index 00000000..09099699 --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Parser.php @@ -0,0 +1,1704 @@ +" +*/ +define('SPREADSHEET_EXCEL_WRITER_GT', ">"); + +/** +* @const SPREADSHEET_EXCEL_WRITER_LT token identifier for character "<" +*/ +define('SPREADSHEET_EXCEL_WRITER_LT', "<"); + +/** +* @const SPREADSHEET_EXCEL_WRITER_LE token identifier for character "<=" +*/ +define('SPREADSHEET_EXCEL_WRITER_LE', "<="); + +/** +* @const SPREADSHEET_EXCEL_WRITER_GE token identifier for character ">=" +*/ +define('SPREADSHEET_EXCEL_WRITER_GE', ">="); + +/** +* @const SPREADSHEET_EXCEL_WRITER_EQ token identifier for character "=" +*/ +define('SPREADSHEET_EXCEL_WRITER_EQ', "="); + +/** +* @const SPREADSHEET_EXCEL_WRITER_NE token identifier for character "<>" +*/ +define('SPREADSHEET_EXCEL_WRITER_NE', "<>"); + +/** +* * @const SPREADSHEET_EXCEL_WRITER_CONCAT token identifier for character "&" +*/ +define('SPREADSHEET_EXCEL_WRITER_CONCAT', "&"); + +if (!class_exists('PEAR')) { + require_once 'PEAR.php'; +} + +/** +* Class for parsing Excel formulas +* +* @author Xavier Noguer +* @category FileFormats +* @package Spreadsheet_Excel_Writer +*/ + +class Spreadsheet_Excel_Writer_Parser extends PEAR +{ + /** + * The index of the character we are currently looking at + * @var integer + */ + public $_current_char; + + /** + * The token we are working on. + * @var string + */ + public $_current_token; + + /** + * The formula to parse + * @var string + */ + public $_formula; + + /** + * The character ahead of the current char + * @var string + */ + public $_lookahead; + + /** + * The parse tree to be generated + * @var string + */ + public $_parse_tree; + + /** + * The byte order. 1 => big endian, 0 => little endian. + * @var integer + */ + public $_byte_order; + + /** + * Array of external sheets + * @var array + */ + public $_ext_sheets; + + /** + * Array of sheet references in the form of REF structures + * @var array + */ + public $_references; + + /** + * The BIFF version for the workbook + * @var integer + */ + public $_BIFF_version; + + /** + * The class constructor + * + * @param integer $byte_order The byte order (Little endian or Big endian) of the architecture + (optional). 1 => big endian, 0 (default) little endian. + */ + public function __construct($byte_order, $biff_version) + { + $this->_current_char = 0; + $this->_BIFF_version = $biff_version; + $this->_current_token = ''; // The token we are working on. + $this->_formula = ''; // The formula to parse. + $this->_lookahead = ''; // The character ahead of the current char. + $this->_parse_tree = ''; // The parse tree to be generated. + $this->_initializeHashes(); // Initialize the hashes: ptg's and public function's ptg's + $this->_byte_order = $byte_order; // Little Endian or Big Endian + $this->_ext_sheets = array(); + $this->_references = array(); + } + + /** + * Initialize the ptg and public function hashes. + * + * @access private + */ + protected function _initializeHashes() + { + // The Excel ptg indices + $this->ptg = array( + 'ptgExp' => 0x01, + 'ptgTbl' => 0x02, + 'ptgAdd' => 0x03, + 'ptgSub' => 0x04, + 'ptgMul' => 0x05, + 'ptgDiv' => 0x06, + 'ptgPower' => 0x07, + 'ptgConcat' => 0x08, + 'ptgLT' => 0x09, + 'ptgLE' => 0x0A, + 'ptgEQ' => 0x0B, + 'ptgGE' => 0x0C, + 'ptgGT' => 0x0D, + 'ptgNE' => 0x0E, + 'ptgIsect' => 0x0F, + 'ptgUnion' => 0x10, + 'ptgRange' => 0x11, + 'ptgUplus' => 0x12, + 'ptgUminus' => 0x13, + 'ptgPercent' => 0x14, + 'ptgParen' => 0x15, + 'ptgMissArg' => 0x16, + 'ptgStr' => 0x17, + 'ptgAttr' => 0x19, + 'ptgSheet' => 0x1A, + 'ptgEndSheet' => 0x1B, + 'ptgErr' => 0x1C, + 'ptgBool' => 0x1D, + 'ptgInt' => 0x1E, + 'ptgNum' => 0x1F, + 'ptgArray' => 0x20, + 'ptgFunc' => 0x21, + 'ptgFuncVar' => 0x22, + 'ptgName' => 0x23, + 'ptgRef' => 0x24, + 'ptgArea' => 0x25, + 'ptgMemArea' => 0x26, + 'ptgMemErr' => 0x27, + 'ptgMemNoMem' => 0x28, + 'ptgMemFunc' => 0x29, + 'ptgRefErr' => 0x2A, + 'ptgAreaErr' => 0x2B, + 'ptgRefN' => 0x2C, + 'ptgAreaN' => 0x2D, + 'ptgMemAreaN' => 0x2E, + 'ptgMemNoMemN' => 0x2F, + 'ptgNameX' => 0x39, + 'ptgRef3d' => 0x3A, + 'ptgArea3d' => 0x3B, + 'ptgRefErr3d' => 0x3C, + 'ptgAreaErr3d' => 0x3D, + 'ptgArrayV' => 0x40, + 'ptgFuncV' => 0x41, + 'ptgFuncVarV' => 0x42, + 'ptgNameV' => 0x43, + 'ptgRefV' => 0x44, + 'ptgAreaV' => 0x45, + 'ptgMemAreaV' => 0x46, + 'ptgMemErrV' => 0x47, + 'ptgMemNoMemV' => 0x48, + 'ptgMemFuncV' => 0x49, + 'ptgRefErrV' => 0x4A, + 'ptgAreaErrV' => 0x4B, + 'ptgRefNV' => 0x4C, + 'ptgAreaNV' => 0x4D, + 'ptgMemAreaNV' => 0x4E, + 'ptgMemNoMemN' => 0x4F, + 'ptgFuncCEV' => 0x58, + 'ptgNameXV' => 0x59, + 'ptgRef3dV' => 0x5A, + 'ptgArea3dV' => 0x5B, + 'ptgRefErr3dV' => 0x5C, + 'ptgAreaErr3d' => 0x5D, + 'ptgArrayA' => 0x60, + 'ptgFuncA' => 0x61, + 'ptgFuncVarA' => 0x62, + 'ptgNameA' => 0x63, + 'ptgRefA' => 0x64, + 'ptgAreaA' => 0x65, + 'ptgMemAreaA' => 0x66, + 'ptgMemErrA' => 0x67, + 'ptgMemNoMemA' => 0x68, + 'ptgMemFuncA' => 0x69, + 'ptgRefErrA' => 0x6A, + 'ptgAreaErrA' => 0x6B, + 'ptgRefNA' => 0x6C, + 'ptgAreaNA' => 0x6D, + 'ptgMemAreaNA' => 0x6E, + 'ptgMemNoMemN' => 0x6F, + 'ptgFuncCEA' => 0x78, + 'ptgNameXA' => 0x79, + 'ptgRef3dA' => 0x7A, + 'ptgArea3dA' => 0x7B, + 'ptgRefErr3dA' => 0x7C, + 'ptgAreaErr3d' => 0x7D + ); + + // Thanks to Michael Meeks and Gnumeric for the initial arg values. + // + // The following hash was generated by "function_locale.pl" in the distro. + // Refer to function_locale.pl for non-English public function names. + // + // The array elements are as follow: + // ptg: The Excel public function ptg code. + // args: The number of arguments that the public function takes: + // >=0 is a fixed number of arguments. + // -1 is a variable number of arguments. + // class: The reference, value or array class of the public function args. + // vol: The public function is volatile. + // + $this->_functions = array( + // public function ptg args class vol + 'COUNT' => array( 0, -1, 0, 0 ), + 'IF' => array( 1, -1, 1, 0 ), + 'ISNA' => array( 2, 1, 1, 0 ), + 'ISERROR' => array( 3, 1, 1, 0 ), + 'SUM' => array( 4, -1, 0, 0 ), + 'AVERAGE' => array( 5, -1, 0, 0 ), + 'MIN' => array( 6, -1, 0, 0 ), + 'MAX' => array( 7, -1, 0, 0 ), + 'ROW' => array( 8, -1, 0, 0 ), + 'COLUMN' => array( 9, -1, 0, 0 ), + 'NA' => array( 10, 0, 0, 0 ), + 'NPV' => array( 11, -1, 1, 0 ), + 'STDEV' => array( 12, -1, 0, 0 ), + 'DOLLAR' => array( 13, -1, 1, 0 ), + 'FIXED' => array( 14, -1, 1, 0 ), + 'SIN' => array( 15, 1, 1, 0 ), + 'COS' => array( 16, 1, 1, 0 ), + 'TAN' => array( 17, 1, 1, 0 ), + 'ATAN' => array( 18, 1, 1, 0 ), + 'PI' => array( 19, 0, 1, 0 ), + 'SQRT' => array( 20, 1, 1, 0 ), + 'EXP' => array( 21, 1, 1, 0 ), + 'LN' => array( 22, 1, 1, 0 ), + 'LOG10' => array( 23, 1, 1, 0 ), + 'ABS' => array( 24, 1, 1, 0 ), + 'INT' => array( 25, 1, 1, 0 ), + 'SIGN' => array( 26, 1, 1, 0 ), + 'ROUND' => array( 27, 2, 1, 0 ), + 'LOOKUP' => array( 28, -1, 0, 0 ), + 'INDEX' => array( 29, -1, 0, 1 ), + 'REPT' => array( 30, 2, 1, 0 ), + 'MID' => array( 31, 3, 1, 0 ), + 'LEN' => array( 32, 1, 1, 0 ), + 'VALUE' => array( 33, 1, 1, 0 ), + 'TRUE' => array( 34, 0, 1, 0 ), + 'FALSE' => array( 35, 0, 1, 0 ), + 'AND' => array( 36, -1, 0, 0 ), + 'OR' => array( 37, -1, 0, 0 ), + 'NOT' => array( 38, 1, 1, 0 ), + 'MOD' => array( 39, 2, 1, 0 ), + 'DCOUNT' => array( 40, 3, 0, 0 ), + 'DSUM' => array( 41, 3, 0, 0 ), + 'DAVERAGE' => array( 42, 3, 0, 0 ), + 'DMIN' => array( 43, 3, 0, 0 ), + 'DMAX' => array( 44, 3, 0, 0 ), + 'DSTDEV' => array( 45, 3, 0, 0 ), + 'VAR' => array( 46, -1, 0, 0 ), + 'DVAR' => array( 47, 3, 0, 0 ), + 'TEXT' => array( 48, 2, 1, 0 ), + 'LINEST' => array( 49, -1, 0, 0 ), + 'TREND' => array( 50, -1, 0, 0 ), + 'LOGEST' => array( 51, -1, 0, 0 ), + 'GROWTH' => array( 52, -1, 0, 0 ), + 'PV' => array( 56, -1, 1, 0 ), + 'FV' => array( 57, -1, 1, 0 ), + 'NPER' => array( 58, -1, 1, 0 ), + 'PMT' => array( 59, -1, 1, 0 ), + 'RATE' => array( 60, -1, 1, 0 ), + 'MIRR' => array( 61, 3, 0, 0 ), + 'IRR' => array( 62, -1, 0, 0 ), + 'RAND' => array( 63, 0, 1, 1 ), + 'MATCH' => array( 64, -1, 0, 0 ), + 'DATE' => array( 65, 3, 1, 0 ), + 'TIME' => array( 66, 3, 1, 0 ), + 'DAY' => array( 67, 1, 1, 0 ), + 'MONTH' => array( 68, 1, 1, 0 ), + 'YEAR' => array( 69, 1, 1, 0 ), + 'WEEKDAY' => array( 70, -1, 1, 0 ), + 'HOUR' => array( 71, 1, 1, 0 ), + 'MINUTE' => array( 72, 1, 1, 0 ), + 'SECOND' => array( 73, 1, 1, 0 ), + 'NOW' => array( 74, 0, 1, 1 ), + 'AREAS' => array( 75, 1, 0, 1 ), + 'ROWS' => array( 76, 1, 0, 1 ), + 'COLUMNS' => array( 77, 1, 0, 1 ), + 'OFFSET' => array( 78, -1, 0, 1 ), + 'SEARCH' => array( 82, -1, 1, 0 ), + 'TRANSPOSE' => array( 83, 1, 1, 0 ), + 'TYPE' => array( 86, 1, 1, 0 ), + 'ATAN2' => array( 97, 2, 1, 0 ), + 'ASIN' => array( 98, 1, 1, 0 ), + 'ACOS' => array( 99, 1, 1, 0 ), + 'CHOOSE' => array( 100, -1, 1, 0 ), + 'HLOOKUP' => array( 101, -1, 0, 0 ), + 'VLOOKUP' => array( 102, -1, 0, 0 ), + 'ISREF' => array( 105, 1, 0, 0 ), + 'LOG' => array( 109, -1, 1, 0 ), + 'CHAR' => array( 111, 1, 1, 0 ), + 'LOWER' => array( 112, 1, 1, 0 ), + 'UPPER' => array( 113, 1, 1, 0 ), + 'PROPER' => array( 114, 1, 1, 0 ), + 'LEFT' => array( 115, -1, 1, 0 ), + 'RIGHT' => array( 116, -1, 1, 0 ), + 'EXACT' => array( 117, 2, 1, 0 ), + 'TRIM' => array( 118, 1, 1, 0 ), + 'REPLACE' => array( 119, 4, 1, 0 ), + 'SUBSTITUTE' => array( 120, -1, 1, 0 ), + 'CODE' => array( 121, 1, 1, 0 ), + 'FIND' => array( 124, -1, 1, 0 ), + 'CELL' => array( 125, -1, 0, 1 ), + 'ISERR' => array( 126, 1, 1, 0 ), + 'ISTEXT' => array( 127, 1, 1, 0 ), + 'ISNUMBER' => array( 128, 1, 1, 0 ), + 'ISBLANK' => array( 129, 1, 1, 0 ), + 'T' => array( 130, 1, 0, 0 ), + 'N' => array( 131, 1, 0, 0 ), + 'DATEVALUE' => array( 140, 1, 1, 0 ), + 'TIMEVALUE' => array( 141, 1, 1, 0 ), + 'SLN' => array( 142, 3, 1, 0 ), + 'SYD' => array( 143, 4, 1, 0 ), + 'DDB' => array( 144, -1, 1, 0 ), + 'INDIRECT' => array( 148, -1, 1, 1 ), + 'CALL' => array( 150, -1, 1, 0 ), + 'CLEAN' => array( 162, 1, 1, 0 ), + 'MDETERM' => array( 163, 1, 2, 0 ), + 'MINVERSE' => array( 164, 1, 2, 0 ), + 'MMULT' => array( 165, 2, 2, 0 ), + 'IPMT' => array( 167, -1, 1, 0 ), + 'PPMT' => array( 168, -1, 1, 0 ), + 'COUNTA' => array( 169, -1, 0, 0 ), + 'PRODUCT' => array( 183, -1, 0, 0 ), + 'FACT' => array( 184, 1, 1, 0 ), + 'DPRODUCT' => array( 189, 3, 0, 0 ), + 'ISNONTEXT' => array( 190, 1, 1, 0 ), + 'STDEVP' => array( 193, -1, 0, 0 ), + 'VARP' => array( 194, -1, 0, 0 ), + 'DSTDEVP' => array( 195, 3, 0, 0 ), + 'DVARP' => array( 196, 3, 0, 0 ), + 'TRUNC' => array( 197, -1, 1, 0 ), + 'ISLOGICAL' => array( 198, 1, 1, 0 ), + 'DCOUNTA' => array( 199, 3, 0, 0 ), + 'ROUNDUP' => array( 212, 2, 1, 0 ), + 'ROUNDDOWN' => array( 213, 2, 1, 0 ), + 'RANK' => array( 216, -1, 0, 0 ), + 'ADDRESS' => array( 219, -1, 1, 0 ), + 'DAYS360' => array( 220, -1, 1, 0 ), + 'TODAY' => array( 221, 0, 1, 1 ), + 'VDB' => array( 222, -1, 1, 0 ), + 'MEDIAN' => array( 227, -1, 0, 0 ), + 'SUMPRODUCT' => array( 228, -1, 2, 0 ), + 'SINH' => array( 229, 1, 1, 0 ), + 'COSH' => array( 230, 1, 1, 0 ), + 'TANH' => array( 231, 1, 1, 0 ), + 'ASINH' => array( 232, 1, 1, 0 ), + 'ACOSH' => array( 233, 1, 1, 0 ), + 'ATANH' => array( 234, 1, 1, 0 ), + 'DGET' => array( 235, 3, 0, 0 ), + 'INFO' => array( 244, 1, 1, 1 ), + 'DB' => array( 247, -1, 1, 0 ), + 'FREQUENCY' => array( 252, 2, 0, 0 ), + 'ERROR.TYPE' => array( 261, 1, 1, 0 ), + 'REGISTER.ID' => array( 267, -1, 1, 0 ), + 'AVEDEV' => array( 269, -1, 0, 0 ), + 'BETADIST' => array( 270, -1, 1, 0 ), + 'GAMMALN' => array( 271, 1, 1, 0 ), + 'BETAINV' => array( 272, -1, 1, 0 ), + 'BINOMDIST' => array( 273, 4, 1, 0 ), + 'CHIDIST' => array( 274, 2, 1, 0 ), + 'CHIINV' => array( 275, 2, 1, 0 ), + 'COMBIN' => array( 276, 2, 1, 0 ), + 'CONFIDENCE' => array( 277, 3, 1, 0 ), + 'CRITBINOM' => array( 278, 3, 1, 0 ), + 'EVEN' => array( 279, 1, 1, 0 ), + 'EXPONDIST' => array( 280, 3, 1, 0 ), + 'FDIST' => array( 281, 3, 1, 0 ), + 'FINV' => array( 282, 3, 1, 0 ), + 'FISHER' => array( 283, 1, 1, 0 ), + 'FISHERINV' => array( 284, 1, 1, 0 ), + 'FLOOR' => array( 285, 2, 1, 0 ), + 'GAMMADIST' => array( 286, 4, 1, 0 ), + 'GAMMAINV' => array( 287, 3, 1, 0 ), + 'CEILING' => array( 288, 2, 1, 0 ), + 'HYPGEOMDIST' => array( 289, 4, 1, 0 ), + 'LOGNORMDIST' => array( 290, 3, 1, 0 ), + 'LOGINV' => array( 291, 3, 1, 0 ), + 'NEGBINOMDIST' => array( 292, 3, 1, 0 ), + 'NORMDIST' => array( 293, 4, 1, 0 ), + 'NORMSDIST' => array( 294, 1, 1, 0 ), + 'NORMINV' => array( 295, 3, 1, 0 ), + 'NORMSINV' => array( 296, 1, 1, 0 ), + 'STANDARDIZE' => array( 297, 3, 1, 0 ), + 'ODD' => array( 298, 1, 1, 0 ), + 'PERMUT' => array( 299, 2, 1, 0 ), + 'POISSON' => array( 300, 3, 1, 0 ), + 'TDIST' => array( 301, 3, 1, 0 ), + 'WEIBULL' => array( 302, 4, 1, 0 ), + 'SUMXMY2' => array( 303, 2, 2, 0 ), + 'SUMX2MY2' => array( 304, 2, 2, 0 ), + 'SUMX2PY2' => array( 305, 2, 2, 0 ), + 'CHITEST' => array( 306, 2, 2, 0 ), + 'CORREL' => array( 307, 2, 2, 0 ), + 'COVAR' => array( 308, 2, 2, 0 ), + 'FORECAST' => array( 309, 3, 2, 0 ), + 'FTEST' => array( 310, 2, 2, 0 ), + 'INTERCEPT' => array( 311, 2, 2, 0 ), + 'PEARSON' => array( 312, 2, 2, 0 ), + 'RSQ' => array( 313, 2, 2, 0 ), + 'STEYX' => array( 314, 2, 2, 0 ), + 'SLOPE' => array( 315, 2, 2, 0 ), + 'TTEST' => array( 316, 4, 2, 0 ), + 'PROB' => array( 317, -1, 2, 0 ), + 'DEVSQ' => array( 318, -1, 0, 0 ), + 'GEOMEAN' => array( 319, -1, 0, 0 ), + 'HARMEAN' => array( 320, -1, 0, 0 ), + 'SUMSQ' => array( 321, -1, 0, 0 ), + 'KURT' => array( 322, -1, 0, 0 ), + 'SKEW' => array( 323, -1, 0, 0 ), + 'ZTEST' => array( 324, -1, 0, 0 ), + 'LARGE' => array( 325, 2, 0, 0 ), + 'SMALL' => array( 326, 2, 0, 0 ), + 'QUARTILE' => array( 327, 2, 0, 0 ), + 'PERCENTILE' => array( 328, 2, 0, 0 ), + 'PERCENTRANK' => array( 329, -1, 0, 0 ), + 'MODE' => array( 330, -1, 2, 0 ), + 'TRIMMEAN' => array( 331, 2, 0, 0 ), + 'TINV' => array( 332, 2, 1, 0 ), + 'CONCATENATE' => array( 336, -1, 1, 0 ), + 'POWER' => array( 337, 2, 1, 0 ), + 'RADIANS' => array( 342, 1, 1, 0 ), + 'DEGREES' => array( 343, 1, 1, 0 ), + 'SUBTOTAL' => array( 344, -1, 0, 0 ), + 'SUMIF' => array( 345, -1, 0, 0 ), + 'COUNTIF' => array( 346, 2, 0, 0 ), + 'COUNTBLANK' => array( 347, 1, 0, 0 ), + 'ROMAN' => array( 354, -1, 1, 0 ) + ); + } + + /** + * Convert a token to the proper ptg value. + * + * @access private + * @param mixed $token The token to convert. + * @return mixed the converted token on success. PEAR_Error if the token + * is not recognized + */ + protected function _convert($token) + { + if (preg_match("/^\"[^\"]{0,255}\"$/", $token)) { + return $this->_convertString($token); + + } elseif (is_numeric($token)) { + return $this->_convertNumber($token); + + // match references like A1 or $A$1 + } elseif (preg_match('/^\$?([A-Ia-i]?[A-Za-z])\$?(\d+)$/',$token)) { + return $this->_convertRef2d($token); + + // match external references like Sheet1!A1 or Sheet1:Sheet2!A1 + } elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z](\d+)$/u",$token)) { + return $this->_convertRef3d($token); + + // match external references like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1 + } elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z](\d+)$/u",$token)) { + return $this->_convertRef3d($token); + + // match ranges like A1:B2 + } elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)\:(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/",$token)) { + return $this->_convertRange2d($token); + + // match ranges like A1..B2 + } elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/",$token)) { + return $this->_convertRange2d($token); + + // match external ranges like Sheet1!A1 or Sheet1:Sheet2!A1:B2 + } elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?(\d+)\:([A-Ia-i]?[A-Za-z])?(\d+)$/u",$token)) { + return $this->_convertRange3d($token); + + // match external ranges like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1:B2 + } elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?(\d+)\:([A-Ia-i]?[A-Za-z])?(\d+)$/u",$token)) { + return $this->_convertRange3d($token); + + // operators (including parentheses) + } elseif (isset($this->ptg[$token])) { + return pack("C", $this->ptg[$token]); + + // commented so argument number can be processed correctly. See toReversePolish(). + /*elseif (preg_match("/[A-Z0-9\xc0-\xdc\.]+/",$token)) + { + return($this->_convertFunction($token,$this->_func_args)); + }*/ + + // if it's an argument, ignore the token (the argument remains) + } elseif ($token == 'arg') { + return ''; + } + // TODO: use real error codes + return $this->raiseError("Unknown token $token"); + } + + /** + * Convert a number token to ptgInt or ptgNum + * + * @access private + * @param mixed $num an integer or double for conversion to its ptg value + */ + protected function _convertNumber($num) + { + // Integer in the range 0..2**16-1 + if ((preg_match("/^\d+$/", $num)) and ($num <= 65535)) { + return pack("Cv", $this->ptg['ptgInt'], $num); + } else { // A float + if ($this->_byte_order) { // if it's Big Endian + $num = strrev($num); + } + return pack("Cd", $this->ptg['ptgNum'], $num); + } + } + + /** + * Convert a string token to ptgStr + * + * @access private + * @param string $string A string for conversion to its ptg value. + * @return mixed the converted token on success. PEAR_Error if the string + * is longer than 255 characters. + */ + protected function _convertString($string) + { + // chop away beggining and ending quotes + $string = substr($string, 1, strlen($string) - 2); + if (strlen($string) > 255) { + return $this->raiseError("String is too long"); + } + + if ($this->_BIFF_version == 0x0500) { + return pack("CC", $this->ptg['ptgStr'], strlen($string)).$string; + } elseif ($this->_BIFF_version == 0x0600) { + $encoding = 0; // TODO: Unicode support + return pack("CCC", $this->ptg['ptgStr'], strlen($string), $encoding).$string; + } + } + + /** + * Convert a public function to a ptgFunc or ptgFuncVarV depending on the number of + * args that it takes. + * + * @access private + * @param string $token The name of the public function for convertion to ptg value. + * @param integer $num_args The number of arguments the public function receives. + * @return string The packed ptg for the public function + */ + protected function _convertFunction($token, $num_args) + { + $args = $this->_functions[$token][1]; + $volatile = $this->_functions[$token][3]; + + // Fixed number of args eg. TIME($i,$j,$k). + if ($args >= 0) { + return pack("Cv", $this->ptg['ptgFuncV'], $this->_functions[$token][0]); + } + // Variable number of args eg. SUM($i,$j,$k, ..). + if ($args == -1) { + return pack("CCv", $this->ptg['ptgFuncVarV'], $num_args, $this->_functions[$token][0]); + } + } + + /** + * Convert an Excel range such as A1:D4 to a ptgRefV. + * + * @access private + * @param string $range An Excel range in the A1:A2 or A1..A2 format. + */ + protected function _convertRange2d($range, $class=0) + { + + // TODO: possible class value 0,1,2 check Formula.pm + // Split the range into 2 cell refs + if (preg_match("/^([A-Ia-i]?[A-Za-z])(\d+)\:([A-Ia-i]?[A-Za-z])(\d+)$/", $range)) { + list($cell1, $cell2) = explode(':', $range); + } elseif (preg_match("/^([A-Ia-i]?[A-Za-z])(\d+)\.\.([A-Ia-i]?[A-Za-z])(\d+)$/", $range)) { + list($cell1, $cell2) = explode('..', $range); + + } else { + // TODO: use real error codes + return $this->raiseError("Unknown range separator", 0, PEAR_ERROR_DIE); + } + + // Convert the cell references + $cell_array1 = $this->_cellToPackedRowcol($cell1); + if (PEAR::isError($cell_array1)) { + return $cell_array1; + } + list($row1, $col1) = $cell_array1; + $cell_array2 = $this->_cellToPackedRowcol($cell2); + if (PEAR::isError($cell_array2)) { + return $cell_array2; + } + list($row2, $col2) = $cell_array2; + + // The ptg value depends on the class of the ptg. + if ($class == 0) { + $ptgArea = pack("C", $this->ptg['ptgArea']); + } elseif ($class == 1) { + $ptgArea = pack("C", $this->ptg['ptgAreaV']); + } elseif ($class == 2) { + $ptgArea = pack("C", $this->ptg['ptgAreaA']); + } else { + // TODO: use real error codes + return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE); + } + return $ptgArea . $row1 . $row2 . $col1. $col2; + } + + /** + * Convert an Excel 3d range such as "Sheet1!A1:D4" or "Sheet1:Sheet2!A1:D4" to + * a ptgArea3d. + * + * @access private + * @param string $token An Excel range in the Sheet1!A1:A2 format. + * @return mixed The packed ptgArea3d token on success, PEAR_Error on failure. + */ + protected function _convertRange3d($token) + { + $class = 2; // as far as I know, this is magick. + + // Split the ref at the ! symbol + list($ext_ref, $range) = explode('!', $token); + + // Convert the external reference part (different for BIFF8) + if ($this->_BIFF_version == 0x0500) { + $ext_ref = $this->_packExtRef($ext_ref); + if (PEAR::isError($ext_ref)) { + return $ext_ref; + } + } elseif ($this->_BIFF_version == 0x0600) { + $ext_ref = $this->_getRefIndex($ext_ref); + if (PEAR::isError($ext_ref)) { + return $ext_ref; + } + } + + // Split the range into 2 cell refs + list($cell1, $cell2) = explode(':', $range); + + // Convert the cell references + if (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/", $cell1)) { + $cell_array1 = $this->_cellToPackedRowcol($cell1); + if (PEAR::isError($cell_array1)) { + return $cell_array1; + } + list($row1, $col1) = $cell_array1; + $cell_array2 = $this->_cellToPackedRowcol($cell2); + if (PEAR::isError($cell_array2)) { + return $cell_array2; + } + list($row2, $col2) = $cell_array2; + } else { // It's a rows range (like 26:27) + $cells_array = $this->_rangeToPackedRange($cell1.':'.$cell2); + if (PEAR::isError($cells_array)) { + return $cells_array; + } + list($row1, $col1, $row2, $col2) = $cells_array; + } + + // The ptg value depends on the class of the ptg. + if ($class == 0) { + $ptgArea = pack("C", $this->ptg['ptgArea3d']); + } elseif ($class == 1) { + $ptgArea = pack("C", $this->ptg['ptgArea3dV']); + } elseif ($class == 2) { + $ptgArea = pack("C", $this->ptg['ptgArea3dA']); + } else { + return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE); + } + + return $ptgArea . $ext_ref . $row1 . $row2 . $col1. $col2; + } + + /** + * Convert an Excel reference such as A1, $B2, C$3 or $D$4 to a ptgRefV. + * + * @access private + * @param string $cell An Excel cell reference + * @return string The cell in packed() format with the corresponding ptg + */ + protected function _convertRef2d($cell) + { + $class = 2; // as far as I know, this is magick. + + // Convert the cell reference + $cell_array = $this->_cellToPackedRowcol($cell); + if (PEAR::isError($cell_array)) { + return $cell_array; + } + list($row, $col) = $cell_array; + + // The ptg value depends on the class of the ptg. + if ($class == 0) { + $ptgRef = pack("C", $this->ptg['ptgRef']); + } elseif ($class == 1) { + $ptgRef = pack("C", $this->ptg['ptgRefV']); + } elseif ($class == 2) { + $ptgRef = pack("C", $this->ptg['ptgRefA']); + } else { + // TODO: use real error codes + return $this->raiseError("Unknown class $class"); + } + return $ptgRef.$row.$col; + } + + /** + * Convert an Excel 3d reference such as "Sheet1!A1" or "Sheet1:Sheet2!A1" to a + * ptgRef3d. + * + * @access private + * @param string $cell An Excel cell reference + * @return mixed The packed ptgRef3d token on success, PEAR_Error on failure. + */ + protected function _convertRef3d($cell) + { + $class = 2; // as far as I know, this is magick. + + // Split the ref at the ! symbol + list($ext_ref, $cell) = explode('!', $cell); + + // Convert the external reference part (different for BIFF8) + if ($this->_BIFF_version == 0x0500) { + $ext_ref = $this->_packExtRef($ext_ref); + if (PEAR::isError($ext_ref)) { + return $ext_ref; + } + } elseif ($this->_BIFF_version == 0x0600) { + $ext_ref = $this->_getRefIndex($ext_ref); + if (PEAR::isError($ext_ref)) { + return $ext_ref; + } + } + + // Convert the cell reference part + list($row, $col) = $this->_cellToPackedRowcol($cell); + + // The ptg value depends on the class of the ptg. + if ($class == 0) { + $ptgRef = pack("C", $this->ptg['ptgRef3d']); + } elseif ($class == 1) { + $ptgRef = pack("C", $this->ptg['ptgRef3dV']); + } elseif ($class == 2) { + $ptgRef = pack("C", $this->ptg['ptgRef3dA']); + } else { + return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE); + } + + return $ptgRef . $ext_ref. $row . $col; + } + + /** + * Convert the sheet name part of an external reference, for example "Sheet1" or + * "Sheet1:Sheet2", to a packed structure. + * + * @access private + * @param string $ext_ref The name of the external reference + * @return string The reference index in packed() format + */ + protected function _packExtRef($ext_ref) + { + $ext_ref = preg_replace("/^'/", '', $ext_ref); // Remove leading ' if any. + $ext_ref = preg_replace("/'$/", '', $ext_ref); // Remove trailing ' if any. + + // Check if there is a sheet range eg., Sheet1:Sheet2. + if (preg_match("/:/", $ext_ref)) { + list($sheet_name1, $sheet_name2) = explode(':', $ext_ref); + + $sheet1 = $this->_getSheetIndex($sheet_name1); + if ($sheet1 == -1) { + return $this->raiseError("Unknown sheet name $sheet_name1 in formula"); + } + $sheet2 = $this->_getSheetIndex($sheet_name2); + if ($sheet2 == -1) { + return $this->raiseError("Unknown sheet name $sheet_name2 in formula"); + } + + // Reverse max and min sheet numbers if necessary + if ($sheet1 > $sheet2) { + list($sheet1, $sheet2) = array($sheet2, $sheet1); + } + } else { // Single sheet name only. + $sheet1 = $this->_getSheetIndex($ext_ref); + if ($sheet1 == -1) { + return $this->raiseError("Unknown sheet name $ext_ref in formula"); + } + $sheet2 = $sheet1; + } + + // References are stored relative to 0xFFFF. + $offset = -1 - $sheet1; + + return pack('vdvv', $offset, 0x00, $sheet1, $sheet2); + } + + /** + * Look up the REF index that corresponds to an external sheet name + * (or range). If it doesn't exist yet add it to the workbook's references + * array. It assumes all sheet names given must exist. + * + * @access private + * @param string $ext_ref The name of the external reference + * @return mixed The reference index in packed() format on success, + * PEAR_Error on failure + */ + protected function _getRefIndex($ext_ref) + { + $ext_ref = preg_replace("/^'/", '', $ext_ref); // Remove leading ' if any. + $ext_ref = preg_replace("/'$/", '', $ext_ref); // Remove trailing ' if any. + + // Check if there is a sheet range eg., Sheet1:Sheet2. + if (preg_match("/:/", $ext_ref)) { + list($sheet_name1, $sheet_name2) = explode(':', $ext_ref); + + $sheet1 = $this->_getSheetIndex($sheet_name1); + if ($sheet1 == -1) { + return $this->raiseError("Unknown sheet name $sheet_name1 in formula"); + } + $sheet2 = $this->_getSheetIndex($sheet_name2); + if ($sheet2 == -1) { + return $this->raiseError("Unknown sheet name $sheet_name2 in formula"); + } + + // Reverse max and min sheet numbers if necessary + if ($sheet1 > $sheet2) { + list($sheet1, $sheet2) = array($sheet2, $sheet1); + } + } else { // Single sheet name only. + $sheet1 = $this->_getSheetIndex($ext_ref); + if ($sheet1 == -1) { + return $this->raiseError("Unknown sheet name $ext_ref in formula"); + } + $sheet2 = $sheet1; + } + + // assume all references belong to this document + $supbook_index = 0x00; + $ref = pack('vvv', $supbook_index, $sheet1, $sheet2); + $total_references = count($this->_references); + $index = -1; + for ($i = 0; $i < $total_references; $i++) { + if ($ref == $this->_references[$i]) { + $index = $i; + break; + } + } + // if REF was not found add it to references array + if ($index == -1) { + $this->_references[$total_references] = $ref; + $index = $total_references; + } + + return pack('v', $index); + } + + /** + * Look up the index that corresponds to an external sheet name. The hash of + * sheet names is updated by the addworksheet() method of the + * Spreadsheet_Excel_Writer_Workbook class. + * + * @access private + * @return integer The sheet index, -1 if the sheet was not found + */ + protected function _getSheetIndex($sheet_name) + { + if (!isset($this->_ext_sheets[$sheet_name])) { + return -1; + } else { + return $this->_ext_sheets[$sheet_name]; + } + } + + /** + * This method is used to update the array of sheet names. It is + * called by the addWorksheet() method of the + * Spreadsheet_Excel_Writer_Workbook class. + * + * @access public + * @see Spreadsheet_Excel_Writer_Workbook::addWorksheet() + * @param string $name The name of the worksheet being added + * @param integer $index The index of the worksheet being added + */ + public function setExtSheet($name, $index) + { + $this->_ext_sheets[$name] = $index; + } + + /** + * pack() row and column into the required 3 or 4 byte format. + * + * @access private + * @param string $cell The Excel cell reference to be packed + * @return array Array containing the row and column in packed() format + */ + protected function _cellToPackedRowcol($cell) + { + $cell = strtoupper($cell); + list($row, $col, $row_rel, $col_rel) = $this->_cellToRowcol($cell); + if ($col >= 256) { + return $this->raiseError("Column in: $cell greater than 255"); + } + // FIXME: change for BIFF8 + if ($row >= 16384) { + return $this->raiseError("Row in: $cell greater than 16384 "); + } + + // Set the high bits to indicate if row or col are relative. + if ($this->_BIFF_version == 0x0500) { + $row |= $col_rel << 14; + $row |= $row_rel << 15; + $col = pack('C', $col); + } elseif ($this->_BIFF_version == 0x0600) { + $col |= $col_rel << 14; + $col |= $row_rel << 15; + $col = pack('v', $col); + } + $row = pack('v', $row); + + return array($row, $col); + } + + /** + * pack() row range into the required 3 or 4 byte format. + * Just using maximum col/rows, which is probably not the correct solution + * + * @access private + * @param string $range The Excel range to be packed + * @return array Array containing (row1,col1,row2,col2) in packed() format + */ + protected function _rangeToPackedRange($range) + { + preg_match('/(\$)?(\d+)\:(\$)?(\d+)/', $range, $match); + // return absolute rows if there is a $ in the ref + $row1_rel = empty($match[1]) ? 1 : 0; + $row1 = $match[2]; + $row2_rel = empty($match[3]) ? 1 : 0; + $row2 = $match[4]; + // Convert 1-index to zero-index + $row1--; + $row2--; + // Trick poor inocent Excel + $col1 = 0; + $col2 = 16383; // FIXME: maximum possible value for Excel 5 (change this!!!) + + // FIXME: this changes for BIFF8 + if (($row1 >= 16384) or ($row2 >= 16384)) { + return $this->raiseError("Row in: $range greater than 16384 "); + } + + // Set the high bits to indicate if rows are relative. + if ($this->_BIFF_version == 0x0500) { + $row1 |= $row1_rel << 14; // FIXME: probably a bug + $row2 |= $row2_rel << 15; + $col1 = pack('C', $col1); + $col2 = pack('C', $col2); + } elseif ($this->_BIFF_version == 0x0600) { + $col1 |= $row1_rel << 15; + $col2 |= $row2_rel << 15; + $col1 = pack('v', $col1); + $col2 = pack('v', $col2); + } + $row1 = pack('v', $row1); + $row2 = pack('v', $row2); + + return array($row1, $col1, $row2, $col2); + } + + /** + * Convert an Excel cell reference such as A1 or $B2 or C$3 or $D$4 to a zero + * indexed row and column number. Also returns two (0,1) values to indicate + * whether the row or column are relative references. + * + * @access private + * @param string $cell The Excel cell reference in A1 format. + * @return array + */ + protected function _cellToRowcol($cell) + { + preg_match('/(\$)?([A-I]?[A-Z])(\$)?(\d+)/',$cell,$match); + // return absolute column if there is a $ in the ref + $col_rel = empty($match[1]) ? 1 : 0; + $col_ref = $match[2]; + $row_rel = empty($match[3]) ? 1 : 0; + $row = $match[4]; + + // Convert base26 column string to a number. + $expn = strlen($col_ref) - 1; + $col = 0; + $col_ref_length = strlen($col_ref); + for ($i = 0; $i < $col_ref_length; $i++) { + $col += (ord($col_ref[$i]) - ord('A') + 1) * pow(26, $expn); + $expn--; + } + + // Convert 1-index to zero-index + $row--; + $col--; + + return array($row, $col, $row_rel, $col_rel); + } + + /** + * Advance to the next valid token. + * + * @access private + */ + protected function _advance() + { + $i = $this->_current_char; + $formula_length = strlen($this->_formula); + // eat up white spaces + if ($i < $formula_length) { + while ($this->_formula[$i] == " ") { + $i++; + } + + if ($i < ($formula_length - 1)) { + $this->_lookahead = $this->_formula[$i+1]; + } + $token = ''; + } + + while ($i < $formula_length) { + $token .= $this->_formula[$i]; + if ($i < ($formula_length - 1)) { + $this->_lookahead = $this->_formula[$i+1]; + } else { + $this->_lookahead = ''; + } + + if ($this->_match($token) != '') { + //if ($i < strlen($this->_formula) - 1) { + // $this->_lookahead = $this->_formula{$i+1}; + //} + $this->_current_char = $i + 1; + $this->_current_token = $token; + return 1; + } + + if ($i < ($formula_length - 2)) { + $this->_lookahead = $this->_formula[$i+2]; + } else { // if we run out of characters _lookahead becomes empty + $this->_lookahead = ''; + } + $i++; + } + //die("Lexical error ".$this->_current_char); + } + + /** + * Checks if it's a valid token. + * + * @access private + * @param mixed $token The token to check. + * @return mixed The checked token or false on failure + */ + protected function _match($token) + { + switch($token) { + case SPREADSHEET_EXCEL_WRITER_ADD: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_SUB: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_MUL: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_DIV: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_OPEN: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_CLOSE: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_COMA: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_SEMICOLON: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_GT: + if ($this->_lookahead == '=') { // it's a GE token + break; + } + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_LT: + // it's a LE or a NE token + if (($this->_lookahead == '=') or ($this->_lookahead == '>')) { + break; + } + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_GE: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_LE: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_EQ: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_NE: + return $token; + break; + case SPREADSHEET_EXCEL_WRITER_CONCAT: + return $token; + break; + default: + // if it's a reference + if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?[0-9]+$/',$token) and + !preg_match("/[0-9]/",$this->_lookahead) and + ($this->_lookahead != ':') and ($this->_lookahead != '.') and + ($this->_lookahead != '!')) + { + return $token; + } + // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1) + elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z][0-9]+$/u",$token) and + !preg_match("/[0-9]/",$this->_lookahead) and + ($this->_lookahead != ':') and ($this->_lookahead != '.')) + { + return $token; + } + // If it's an external reference ('Sheet1'!A1 or 'Sheet1:Sheet2'!A1) + elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z][0-9]+$/u",$token) and + !preg_match("/[0-9]/",$this->_lookahead) and + ($this->_lookahead != ':') and ($this->_lookahead != '.')) + { + return $token; + } + // if it's a range (A1:A2) + elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+:(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$token) and + !preg_match("/[0-9]/",$this->_lookahead)) + { + return $token; + } + // if it's a range (A1..A2) + elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$token) and + !preg_match("/[0-9]/",$this->_lookahead)) + { + return $token; + } + // If it's an external range like Sheet1!A1 or Sheet1:Sheet2!A1:B2 + elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$token) and + !preg_match("/[0-9]/",$this->_lookahead)) + { + return $token; + } + // If it's an external range like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1:B2 + elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$token) and + !preg_match("/[0-9]/",$this->_lookahead)) + { + return $token; + } + // If it's a number (check that it's not a sheet name or range) + elseif (is_numeric($token) and + (!is_numeric($token.$this->_lookahead) or ($this->_lookahead == '')) and + ($this->_lookahead != '!') and ($this->_lookahead != ':')) + { + return $token; + } + // If it's a string (of maximum 255 characters) + elseif (preg_match("/^\"[^\"]{0,255}\"$/",$token)) + { + return $token; + } + // if it's a public function call + elseif (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/i",$token) and ($this->_lookahead == "(")) + { + return $token; + } + return ''; + } + } + + /** + * The parsing method. It parses a formula. + * + * @access public + * @param string $formula The formula to parse, without the initial equal + * sign (=). + * @return mixed true on success, PEAR_Error on failure + */ + public function parse($formula) + { + $this->_current_char = 0; + $this->_formula = $formula; + $this->_lookahead = $formula[1]; + $this->_advance(); + $this->_parse_tree = $this->_condition(); + if (PEAR::isError($this->_parse_tree)) { + return $this->_parse_tree; + } + return true; + } + + /** + * It parses a condition. It assumes the following rule: + * Cond -> Expr [(">" | "<") Expr] + * + * @access private + * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure + */ + protected function _condition() + { + $result = $this->_expression(); + if (PEAR::isError($result)) { + return $result; + } + if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_LT) { + $this->_advance(); + $result2 = $this->_expression(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgLT', $result, $result2); + } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_GT) { + $this->_advance(); + $result2 = $this->_expression(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgGT', $result, $result2); + } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_LE) { + $this->_advance(); + $result2 = $this->_expression(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgLE', $result, $result2); + } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_GE) { + $this->_advance(); + $result2 = $this->_expression(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgGE', $result, $result2); + } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_EQ) { + $this->_advance(); + $result2 = $this->_expression(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgEQ', $result, $result2); + } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_NE) { + $this->_advance(); + $result2 = $this->_expression(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgNE', $result, $result2); + } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_CONCAT) { + $this->_advance(); + $result2 = $this->_expression(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgConcat', $result, $result2); + } + return $result; + } + + /** + * It parses a expression. It assumes the following rule: + * Expr -> Term [("+" | "-") Term] + * -> "string" + * -> "-" Term + * + * @access private + * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure + */ + protected function _expression() + { + // If it's a string return a string node + if (preg_match("/^\"[^\"]{0,255}\"$/", $this->_current_token)) { + $result = $this->_createTree($this->_current_token, '', ''); + $this->_advance(); + return $result; + } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_SUB) { + // catch "-" Term + $this->_advance(); + $result2 = $this->_expression(); + $result = $this->_createTree('ptgUminus', $result2, ''); + return $result; + } + $result = $this->_term(); + if (PEAR::isError($result)) { + return $result; + } + while (($this->_current_token == SPREADSHEET_EXCEL_WRITER_ADD) or + ($this->_current_token == SPREADSHEET_EXCEL_WRITER_SUB)) { + /**/ + if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_ADD) { + $this->_advance(); + $result2 = $this->_term(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgAdd', $result, $result2); + } else { + $this->_advance(); + $result2 = $this->_term(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgSub', $result, $result2); + } + } + return $result; + } + + /** + * This public function just introduces a ptgParen element in the tree, so that Excel + * doesn't get confused when working with a parenthesized formula afterwards. + * + * @access private + * @see _fact() + * @return array The parsed ptg'd tree + */ + protected function _parenthesizedExpression() + { + $result = $this->_createTree('ptgParen', $this->_expression(), ''); + return $result; + } + + /** + * It parses a term. It assumes the following rule: + * Term -> Fact [("*" | "/") Fact] + * + * @access private + * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure + */ + protected function _term() + { + $result = $this->_fact(); + if (PEAR::isError($result)) { + return $result; + } + while (($this->_current_token == SPREADSHEET_EXCEL_WRITER_MUL) or + ($this->_current_token == SPREADSHEET_EXCEL_WRITER_DIV)) { + /**/ + if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_MUL) { + $this->_advance(); + $result2 = $this->_fact(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgMul', $result, $result2); + } else { + $this->_advance(); + $result2 = $this->_fact(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('ptgDiv', $result, $result2); + } + } + return $result; + } + + /** + * It parses a factor. It assumes the following rule: + * Fact -> ( Expr ) + * | CellRef + * | CellRange + * | Number + * | Function + * + * @access private + * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure + */ + protected function _fact() + { + if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_OPEN) { + $this->_advance(); // eat the "(" + $result = $this->_parenthesizedExpression(); + if ($this->_current_token != SPREADSHEET_EXCEL_WRITER_CLOSE) { + return $this->raiseError("')' token expected."); + } + $this->_advance(); // eat the ")" + return $result; + } + // if it's a reference + if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?[0-9]+$/',$this->_current_token)) + { + $result = $this->_createTree($this->_current_token, '', ''); + $this->_advance(); + return $result; + } + // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1) + elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z][0-9]+$/u",$this->_current_token)) + { + $result = $this->_createTree($this->_current_token, '', ''); + $this->_advance(); + return $result; + } + // If it's an external reference ('Sheet1'!A1 or 'Sheet1:Sheet2'!A1) + elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z][0-9]+$/u",$this->_current_token)) + { + $result = $this->_createTree($this->_current_token, '', ''); + $this->_advance(); + return $result; + } + // if it's a range + elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+:(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$this->_current_token) or + preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$this->_current_token)) + { + $result = $this->_current_token; + $this->_advance(); + return $result; + } + // If it's an external range (Sheet1!A1 or Sheet1!A1:B2) + elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$this->_current_token)) + { + $result = $this->_current_token; + $this->_advance(); + return $result; + } + // If it's an external range ('Sheet1'!A1 or 'Sheet1'!A1:B2) + elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$this->_current_token)) + { + $result = $this->_current_token; + $this->_advance(); + return $result; + } + elseif (is_numeric($this->_current_token)) + { + $result = $this->_createTree($this->_current_token, '', ''); + $this->_advance(); + return $result; + } + // if it's a public function call + elseif (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/i",$this->_current_token)) + { + $result = $this->_func(); + return $result; + } + return $this->raiseError("Syntax error: ".$this->_current_token. + ", lookahead: ".$this->_lookahead. + ", current char: ".$this->_current_char); + } + + /** + * It parses a public function call. It assumes the following rule: + * Func -> ( Expr [,Expr]* ) + * + * @access private + * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure + */ + protected function _func() + { + $num_args = 0; // number of arguments received + $function = strtoupper($this->_current_token); + $result = ''; // initialize result + $this->_advance(); + $this->_advance(); // eat the "(" + while ($this->_current_token != ')') { + /**/ + if ($num_args > 0) { + if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_COMA or + $this->_current_token == SPREADSHEET_EXCEL_WRITER_SEMICOLON) + { + $this->_advance(); // eat the "," or ";" + } else { + return $this->raiseError("Syntax error: comma expected in ". + "public function $function, arg #{$num_args}"); + } + $result2 = $this->_condition(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('arg', $result, $result2); + } else { // first argument + $result2 = $this->_condition(); + if (PEAR::isError($result2)) { + return $result2; + } + $result = $this->_createTree('arg', '', $result2); + } + $num_args++; + } + if (!isset($this->_functions[$function])) { + return $this->raiseError("Function $function() doesn't exist"); + } + $args = $this->_functions[$function][1]; + // If fixed number of args eg. TIME($i,$j,$k). Check that the number of args is valid. + if (($args >= 0) and ($args != $num_args)) { + return $this->raiseError("Incorrect number of arguments in public function $function() "); + } + + $result = $this->_createTree($function, $result, $num_args); + $this->_advance(); // eat the ")" + return $result; + } + + /** + * Creates a tree. In fact an array which may have one or two arrays (sub-trees) + * as elements. + * + * @access private + * @param mixed $value The value of this node. + * @param mixed $left The left array (sub-tree) or a final node. + * @param mixed $right The right array (sub-tree) or a final node. + * @return array A tree + */ + protected function _createTree($value, $left, $right) + { + return array('value' => $value, 'left' => $left, 'right' => $right); + } + + /** + * Builds a string containing the tree in reverse polish notation (What you + * would use in a HP calculator stack). + * The following tree: + * + * + + * / \ + * 2 3 + * + * produces: "23+" + * + * The following tree: + * + * + + * / \ + * 3 * + * / \ + * 6 A1 + * + * produces: "36A1*+" + * + * In fact all operands, functions, references, etc... are written as ptg's + * + * @access public + * @param array $tree The optional tree to convert. + * @return string The tree in reverse polish notation + */ + public function toReversePolish($tree = array()) + { + $polish = ""; // the string we are going to return + if (empty($tree)) { // If it's the first call use _parse_tree + $tree = $this->_parse_tree; + } + if (is_array($tree['left'])) { + $converted_tree = $this->toReversePolish($tree['left']); + if (PEAR::isError($converted_tree)) { + return $converted_tree; + } + $polish .= $converted_tree; + } elseif ($tree['left'] != '') { // It's a final node + $converted_tree = $this->_convert($tree['left']); + if (PEAR::isError($converted_tree)) { + return $converted_tree; + } + $polish .= $converted_tree; + } + if (is_array($tree['right'])) { + $converted_tree = $this->toReversePolish($tree['right']); + if (PEAR::isError($converted_tree)) { + return $converted_tree; + } + $polish .= $converted_tree; + } elseif ($tree['right'] != '') { // It's a final node + $converted_tree = $this->_convert($tree['right']); + if (PEAR::isError($converted_tree)) { + return $converted_tree; + } + $polish .= $converted_tree; + } + // if it's a public function convert it here (so we can set it's arguments) + if (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/",$tree['value']) and + !preg_match('/^([A-Ia-i]?[A-Za-z])(\d+)$/',$tree['value']) and + !preg_match("/^[A-Ia-i]?[A-Za-z](\d+)\.\.[A-Ia-i]?[A-Za-z](\d+)$/",$tree['value']) and + !is_numeric($tree['value']) and + !isset($this->ptg[$tree['value']])) + { + // left subtree for a public function is always an array. + if ($tree['left'] != '') { + $left_tree = $this->toReversePolish($tree['left']); + } else { + $left_tree = ''; + } + if (PEAR::isError($left_tree)) { + return $left_tree; + } + // add it's left subtree and return. + return $left_tree.$this->_convertFunction($tree['value'], $tree['right']); + } else { + $converted_tree = $this->_convert($tree['value']); + if (PEAR::isError($converted_tree)) { + return $converted_tree; + } + } + $polish .= $converted_tree; + return $polish; + } +} \ No newline at end of file diff --git a/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Validator.php b/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Validator.php new file mode 100644 index 00000000..e2bd4cf3 --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Validator.php @@ -0,0 +1,228 @@ + +* +* License Information: +* +* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets +* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +//require_once('PEAR.php'); + +// Possible operator types + +/* +FIXME: change prefixes +*/ +define("OP_BETWEEN", 0x00); +define("OP_NOTBETWEEN", 0x01); +define("OP_EQUAL", 0x02); +define("OP_NOTEQUAL", 0x03); +define("OP_GT", 0x04); +define("OP_LT", 0x05); +define("OP_GTE", 0x06); +define("OP_LTE", 0x07); + +/** +* Baseclass for generating Excel DV records (validations) +* +* @author Herman Kuiper +* @category FileFormats +* @package Spreadsheet_Excel_Writer +*/ +class Spreadsheet_Excel_Writer_Validator +{ + public $_type; + public $_style; + public $_fixedList; + public $_blank; + public $_incell; + public $_showprompt; + public $_showerror; + public $_title_prompt; + public $_descr_prompt; + public $_title_error; + public $_descr_error; + public $_operator; + public $_formula1; + public $_formula2; + /** + * The parser from the workbook. Used to parse validation formulas also + * @var Spreadsheet_Excel_Writer_Parser + */ + public $_parser; + + public function __construct($parser) + { + $this->_parser = $parser; + $this->_type = 0x01; // FIXME: add method for setting datatype + $this->_style = 0x00; + $this->_fixedList = false; + $this->_blank = false; + $this->_incell = false; + $this->_showprompt = false; + $this->_showerror = true; + $this->_title_prompt = "\x00"; + $this->_descr_prompt = "\x00"; + $this->_title_error = "\x00"; + $this->_descr_error = "\x00"; + $this->_operator = 0x00; // default is equal + $this->_formula1 = ''; + $this->_formula2 = ''; + } + + public function setPrompt($promptTitle = "\x00", $promptDescription = "\x00", $showPrompt = true) + { + $this->_showprompt = $showPrompt; + $this->_title_prompt = $promptTitle; + $this->_descr_prompt = $promptDescription; + } + + public function setError($errorTitle = "\x00", $errorDescription = "\x00", $showError = true) + { + $this->_showerror = $showError; + $this->_title_error = $errorTitle; + $this->_descr_error = $errorDescription; + } + + public function allowBlank() + { + $this->_blank = true; + } + + public function onInvalidStop() + { + $this->_style = 0x00; + } + + public function onInvalidWarn() + { + $this->_style = 0x01; + } + + public function onInvalidInfo() + { + $this->_style = 0x02; + } + + public function setFormula1($formula) + { + // Parse the formula using the parser in Parser.php + $error = $this->_parser->parse($formula); + if (PEAR::isError($error)) { + return $this->_formula1; + } + + $this->_formula1 = $this->_parser->toReversePolish(); + if (PEAR::isError($this->_formula1)) { + return $this->_formula1; + } + return true; + } + + public function setFormula2($formula) + { + // Parse the formula using the parser in Parser.php + $error = $this->_parser->parse($formula); + if (PEAR::isError($error)) { + return $this->_formula2; + } + + $this->_formula2 = $this->_parser->toReversePolish(); + if (PEAR::isError($this->_formula2)) { + return $this->_formula2; + } + return true; + } + + protected function _getOptions() + { + $options = $this->_type; + $options |= $this->_style << 3; + if ($this->_fixedList) { + $options |= 0x80; + } + if ($this->_blank) { + $options |= 0x100; + } + if (!$this->_incell) { + $options |= 0x200; + } + if ($this->_showprompt) { + $options |= 0x40000; + } + if ($this->_showerror) { + $options |= 0x80000; + } + $options |= $this->_operator << 20; + + return $options; + } + + protected function _getData() + { + $title_prompt_len = strlen($this->_title_prompt); + $descr_prompt_len = strlen($this->_descr_prompt); + $title_error_len = strlen($this->_title_error); + $descr_error_len = strlen($this->_descr_error); + + $formula1_size = strlen($this->_formula1); + $formula2_size = strlen($this->_formula2); + + $data = pack("V", $this->_getOptions()); + $data .= pack("vC", $title_prompt_len, 0x00) . $this->_title_prompt; + $data .= pack("vC", $title_error_len, 0x00) . $this->_title_error; + $data .= pack("vC", $descr_prompt_len, 0x00) . $this->_descr_prompt; + $data .= pack("vC", $descr_error_len, 0x00) . $this->_descr_error; + + $data .= pack("vv", $formula1_size, 0x0000) . $this->_formula1; + $data .= pack("vv", $formula2_size, 0x0000) . $this->_formula2; + + return $data; + } +} + +/*class Spreadsheet_Excel_Writer_Validation_List extends Spreadsheet_Excel_Writer_Validation +{ + public function Spreadsheet_Excel_Writer_Validation_list() + { + parent::Spreadsheet_Excel_Writer_Validation(); + $this->_type = 0x03; + } + + public function setList($source, $incell = true) + { + $this->_incell = $incell; + $this->_fixedList = true; + + $source = implode("\x00", $source); + $this->_formula1 = pack("CCC", 0x17, strlen($source), 0x0c) . $source; + } + + public function setRow($row, $col1, $col2, $incell = true) + { + $this->_incell = $incell; + //$this->_formula1 = ...; + } + + public function setCol($col, $row1, $row2, $incell = true) + { + $this->_incell = $incell; + //$this->_formula1 = ...; + } +}*/ \ No newline at end of file diff --git a/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Workbook.php b/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Workbook.php new file mode 100644 index 00000000..63eb839d --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Workbook.php @@ -0,0 +1,1629 @@ + +* +* The majority of this is _NOT_ my code. I simply ported it from the +* PERL Spreadsheet::WriteExcel module. +* +* The author of the Spreadsheet::WriteExcel module is John McNamara +* +* +* I _DO_ maintain this code, and John McNamara has nothing to do with the +* porting of this code to PHP. Any questions directly related to this +* class library should be directed to me. +* +* License Information: +* +* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets +* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +if (!class_exists('Spreadsheet_Excel_Writer_BIFFwriter')) { + require_once 'Spreadsheet/Excel/Writer/Format.php'; + require_once 'Spreadsheet/Excel/Writer/BIFFwriter.php'; + require_once 'Spreadsheet/Excel/Writer/Worksheet.php'; + require_once 'Spreadsheet/Excel/Writer/Parser.php'; +} + +if (!class_exists('OLE')) { + require_once 'OLE.php'; +} + +if (!class_exists('OLE_PPS_Root')) { + require_once 'OLE/PPS/Root.php'; +} + +if (!class_exists('OLE_PPS_File')) { + require_once 'OLE/PPS/File.php'; +} + +/** +* Class for generating Excel Spreadsheets +* +* @author Xavier Noguer +* @category FileFormats +* @package Spreadsheet_Excel_Writer +*/ + +class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwriter +{ + /** + * Filename for the Workbook + * @var string + */ + public $_filename; + + /** + * Formula parser + * @var Spreadsheet_Excel_Writer_Parser + */ + public $_parser; + + /** + * Flag for 1904 date system (0 => base date is 1900, 1 => base date is 1904) + * @var integer + */ + public $_1904; + + /** + * The active worksheet of the workbook (0 indexed) + * @var integer + */ + public $_activesheet; + + /** + * 1st displayed worksheet in the workbook (0 indexed) + * @var integer + */ + public $_firstsheet; + + /** + * Number of workbook tabs selected + * @var integer + */ + public $_selected; + + /** + * Index for creating adding new formats to the workbook + * @var integer + */ + public $_xf_index; + + /** + * Flag for preventing close from being called twice. + * @var integer + * @see close() + */ + public $_fileclosed; + + /** + * The BIFF file size for the workbook. + * @var integer + * @see _calcSheetOffsets() + */ + public $_biffsize; + + /** + * The default sheetname for all sheets created. + * @var string + */ + public $_sheetname; + + /** + * The default XF format. + * @var Spreadsheet_Excel_Writer_Format + */ + public $_tmp_format; + + /** + * Array containing references to all of this workbook's worksheets + * @var array + */ + public $_worksheets; + + /** + * Array of sheetnames for creating the EXTERNSHEET records + * @var array + */ + public $_sheetnames; + + /** + * Array containing references to all of this workbook's formats + * @var array + */ + public $_formats; + + /** + * Array containing the colour palette + * @var array + */ + public $_palette; + + /** + * The default format for URLs. + * @var Spreadsheet_Excel_Writer_Format + */ + public $_url_format; + + /** + * The codepage indicates the text encoding used for strings + * @var integer + */ + public $_codepage; + + /** + * The country code used for localization + * @var integer + */ + public $_country_code; + + /** + * number of bytes for sizeinfo of strings + * @var integer + */ + public $_string_sizeinfo_size; + + /** @var int */ + public $_timestamp; + + /** + * Class constructor + * + * @param string filename for storing the workbook. "-" for writing to stdout. + * @access public + */ + public function __construct($filename) + { + // It needs to call its parent's constructor explicitly + parent::__construct(); + + $this->_filename = $filename; + $this->_parser = new Spreadsheet_Excel_Writer_Parser($this->_byte_order, $this->_BIFF_version); + $this->_1904 = 0; + $this->_activesheet = 0; + $this->_firstsheet = 0; + $this->_selected = 0; + $this->_xf_index = 16; // 15 style XF's and 1 cell XF. + $this->_fileclosed = 0; + $this->_biffsize = 0; + $this->_sheetname = 'Sheet'; + $this->_tmp_format = new Spreadsheet_Excel_Writer_Format($this->_BIFF_version); + $this->_worksheets = array(); + $this->_sheetnames = array(); + $this->_formats = array(); + $this->_palette = array(); + $this->_codepage = 0x04E4; // FIXME: should change for BIFF8 + $this->_country_code = -1; + $this->_string_sizeinfo = 3; + + // Add the default format for hyperlinks + $this->_url_format = $this->addFormat(array('color' => 'blue', 'underline' => 1)); + $this->_str_total = 0; + $this->_str_unique = 0; + $this->_str_table = array(); + $this->_timestamp = time(); + + $this->_setPaletteXl97(); + } + + /** + * Calls finalization methods. + * This method should always be the last one to be called on every workbook + * + * @access public + * @return mixed true on success. PEAR_Error on failure + */ + public function close() + { + if ($this->_fileclosed) { // Prevent close() from being called twice. + return true; + } + $res = $this->_storeWorkbook(); + if ($this->isError($res)) { + return $this->raiseError($res->getMessage()); + } + $this->_fileclosed = 1; + return true; + } + + /** + * An accessor for the _worksheets[] array + * Returns an array of the worksheet objects in a workbook + * It actually calls to worksheets() + * + * @access public + * @see worksheets() + * @return array + */ + public function sheets() + { + return $this->worksheets(); + } + + /** + * An accessor for the _worksheets[] array. + * Returns an array of the worksheet objects in a workbook + * + * @access public + * @return array + */ + public function worksheets() + { + return $this->_worksheets; + } + + /** + * Sets the BIFF version. + * This method exists just to access experimental public functionality + * from BIFF8. It will be deprecated ! + * Only possible value is 8 (Excel 97/2000). + * For any other value it fails silently. + * + * @access public + * @param integer $version The BIFF version + */ + public function setVersion($version) + { + if ($version == 8) { // only accept version 8 + $version = 0x0600; + $this->_BIFF_version = $version; + // change BIFFwriter limit for CONTINUE records + $this->_limit = 8228; + $this->_tmp_format->_BIFF_version = $version; + $this->_url_format->_BIFF_version = $version; + $this->_parser->_BIFF_version = $version; + $this->_codepage = 0x04B0; + + $total_worksheets = count($this->_worksheets); + // change version for all worksheets too + for ($i = 0; $i < $total_worksheets; $i++) { + $this->_worksheets[$i]->_BIFF_version = $version; + } + + $total_formats = count($this->_formats); + // change version for all formats too + for ($i = 0; $i < $total_formats; $i++) { + $this->_formats[$i]->_BIFF_version = $version; + } + } + } + + /** + * Set the country identifier for the workbook + * + * @access public + * @param integer $code Is the international calling country code for the + * chosen country. + */ + public function setCountry($code) + { + $this->_country_code = $code; + } + + /** + * Add a new worksheet to the Excel workbook. + * If no name is given the name of the worksheet will be Sheeti$i, with + * $i in [1..]. + * + * @access public + * @param string $name the optional name of the worksheet + * @return mixed reference to a worksheet object on success, PEAR_Error + * on failure + */ + public function addWorksheet($name = '') + { + $index = count($this->_worksheets); + $sheetname = $this->_sheetname; + + if ($name == '') { + $name = $sheetname.($index+1); + } + + // Check that sheetname is <= 31 chars (Excel limit before BIFF8). + if ($this->_BIFF_version != 0x0600) + { + if (strlen($name) > 31) { + return $this->raiseError("Sheetname $name must be <= 31 chars"); + } + } else { + if(function_exists('iconv')) { + $name = iconv('UTF-8','UTF-16LE',$name); + } + } + + // Check that the worksheet name doesn't already exist: a fatal Excel error. + $total_worksheets = count($this->_worksheets); + for ($i = 0; $i < $total_worksheets; $i++) { + if ($this->_worksheets[$i]->getName() == $name) { + return $this->raiseError("Worksheet '$name' already exists"); + } + } + + $worksheet = new Spreadsheet_Excel_Writer_Worksheet($this->_BIFF_version, + $name, $index, + $this->_activesheet, $this->_firstsheet, + $this->_str_total, $this->_str_unique, + $this->_str_table, $this->_url_format, + $this->_parser, $this->_tmp_dir); + + $this->_worksheets[$index] = $worksheet; // Store ref for iterator + $this->_sheetnames[$index] = $name; // Store EXTERNSHEET names + $this->_parser->setExtSheet($name, $index); // Register worksheet name with parser + return $worksheet; + } + + /** + * Add a new format to the Excel workbook. + * Also, pass any properties to the Format constructor. + * + * @access public + * @param array $properties array with properties for initializing the format. + * @return Spreadsheet_Excel_Writer_Format + */ + public function addFormat($properties = array()) + { + $format = new Spreadsheet_Excel_Writer_Format($this->_BIFF_version, $this->_xf_index, $properties); + $this->_xf_index += 1; + $this->_formats[] = $format; + return $format; + } + + /** + * Create new validator. + * + * @access public + * @return Spreadsheet_Excel_Writer_Validator + */ + public function addValidator() + { + if (!class_exists('Spreadsheet_Excel_Writer_Validator')) { + include_once 'Spreadsheet/Excel/Writer/Validator.php'; + } + /* FIXME: check for successful inclusion*/ + $valid = new Spreadsheet_Excel_Writer_Validator($this->_parser); + return $valid; + } + + /** + * Change the RGB components of the elements in the colour palette. + * + * @access public + * @param integer $index colour index + * @param integer $red red RGB value [0-255] + * @param integer $green green RGB value [0-255] + * @param integer $blue blue RGB value [0-255] + * @return integer The palette index for the custom color + */ + public function setCustomColor($index, $red, $green, $blue) + { + // Match a HTML #xxyyzz style parameter + /*if (defined $_[1] and $_[1] =~ /^#(\w\w)(\w\w)(\w\w)/ ) { + @_ = ($_[0], hex $1, hex $2, hex $3); + }*/ + + // Check that the colour index is the right range + if ($index < 8 or $index > 64) { + // TODO: assign real error codes + return $this->raiseError("Color index $index outside range: 8 <= index <= 64"); + } + + // Check that the colour components are in the right range + if (($red < 0 or $red > 255) || + ($green < 0 or $green > 255) || + ($blue < 0 or $blue > 255)) + { + return $this->raiseError("Color component outside range: 0 <= color <= 255"); + } + + $index -= 8; // Adjust colour index (wingless dragonfly) + + // Set the RGB value + $this->_palette[$index] = array($red, $green, $blue, 0); + return($index + 8); + } + + /** + * Sets the colour palette to the Excel 97+ default. + * + * @access private + */ + protected function _setPaletteXl97() + { + $this->_palette = array( + array(0x00, 0x00, 0x00, 0x00), // 8 + array(0xff, 0xff, 0xff, 0x00), // 9 + array(0xff, 0x00, 0x00, 0x00), // 10 + array(0x00, 0xff, 0x00, 0x00), // 11 + array(0x00, 0x00, 0xff, 0x00), // 12 + array(0xff, 0xff, 0x00, 0x00), // 13 + array(0xff, 0x00, 0xff, 0x00), // 14 + array(0x00, 0xff, 0xff, 0x00), // 15 + array(0x80, 0x00, 0x00, 0x00), // 16 + array(0x00, 0x80, 0x00, 0x00), // 17 + array(0x00, 0x00, 0x80, 0x00), // 18 + array(0x80, 0x80, 0x00, 0x00), // 19 + array(0x80, 0x00, 0x80, 0x00), // 20 + array(0x00, 0x80, 0x80, 0x00), // 21 + array(0xc0, 0xc0, 0xc0, 0x00), // 22 + array(0x80, 0x80, 0x80, 0x00), // 23 + array(0x99, 0x99, 0xff, 0x00), // 24 + array(0x99, 0x33, 0x66, 0x00), // 25 + array(0xff, 0xff, 0xcc, 0x00), // 26 + array(0xcc, 0xff, 0xff, 0x00), // 27 + array(0x66, 0x00, 0x66, 0x00), // 28 + array(0xff, 0x80, 0x80, 0x00), // 29 + array(0x00, 0x66, 0xcc, 0x00), // 30 + array(0xcc, 0xcc, 0xff, 0x00), // 31 + array(0x00, 0x00, 0x80, 0x00), // 32 + array(0xff, 0x00, 0xff, 0x00), // 33 + array(0xff, 0xff, 0x00, 0x00), // 34 + array(0x00, 0xff, 0xff, 0x00), // 35 + array(0x80, 0x00, 0x80, 0x00), // 36 + array(0x80, 0x00, 0x00, 0x00), // 37 + array(0x00, 0x80, 0x80, 0x00), // 38 + array(0x00, 0x00, 0xff, 0x00), // 39 + array(0x00, 0xcc, 0xff, 0x00), // 40 + array(0xcc, 0xff, 0xff, 0x00), // 41 + array(0xcc, 0xff, 0xcc, 0x00), // 42 + array(0xff, 0xff, 0x99, 0x00), // 43 + array(0x99, 0xcc, 0xff, 0x00), // 44 + array(0xff, 0x99, 0xcc, 0x00), // 45 + array(0xcc, 0x99, 0xff, 0x00), // 46 + array(0xff, 0xcc, 0x99, 0x00), // 47 + array(0x33, 0x66, 0xff, 0x00), // 48 + array(0x33, 0xcc, 0xcc, 0x00), // 49 + array(0x99, 0xcc, 0x00, 0x00), // 50 + array(0xff, 0xcc, 0x00, 0x00), // 51 + array(0xff, 0x99, 0x00, 0x00), // 52 + array(0xff, 0x66, 0x00, 0x00), // 53 + array(0x66, 0x66, 0x99, 0x00), // 54 + array(0x96, 0x96, 0x96, 0x00), // 55 + array(0x00, 0x33, 0x66, 0x00), // 56 + array(0x33, 0x99, 0x66, 0x00), // 57 + array(0x00, 0x33, 0x00, 0x00), // 58 + array(0x33, 0x33, 0x00, 0x00), // 59 + array(0x99, 0x33, 0x00, 0x00), // 60 + array(0x99, 0x33, 0x66, 0x00), // 61 + array(0x33, 0x33, 0x99, 0x00), // 62 + array(0x33, 0x33, 0x33, 0x00), // 63 + ); + } + + /** + * Assemble worksheets into a workbook and send the BIFF data to an OLE + * storage. + * + * @access private + * @return mixed true on success. PEAR_Error on failure + */ + protected function _storeWorkbook() + { + if (count($this->_worksheets) == 0) { + return true; + } + + // Ensure that at least one worksheet has been selected. + if ($this->_activesheet == 0) { + $this->_worksheets[0]->selected = 1; + } + + // Calculate the number of selected worksheet tabs and call the finalization + // methods for each worksheet + $total_worksheets = count($this->_worksheets); + for ($i = 0; $i < $total_worksheets; $i++) { + if ($this->_worksheets[$i]->selected) { + $this->_selected++; + } + $this->_worksheets[$i]->close($this->_sheetnames); + } + + // Add Workbook globals + $this->_storeBof(0x0005); + $this->_storeCodepage(); + if ($this->_BIFF_version == 0x0600) { + $this->_storeWindow1(); + } + if ($this->_BIFF_version == 0x0500) { + $this->_storeExterns(); // For print area and repeat rows + } + $this->_storeNames(); // For print area and repeat rows + if ($this->_BIFF_version == 0x0500) { + $this->_storeWindow1(); + } + $this->_storeDatemode(); + $this->_storeAllFonts(); + $this->_storeAllNumFormats(); + $this->_storeAllXfs(); + $this->_storeAllStyles(); + $this->_storePalette(); + $this->_calcSheetOffsets(); + + // Add BOUNDSHEET records + for ($i = 0; $i < $total_worksheets; $i++) { + $this->_storeBoundsheet($this->_worksheets[$i]->name,$this->_worksheets[$i]->offset); + } + + if ($this->_country_code != -1) { + $this->_storeCountry(); + } + + if ($this->_BIFF_version == 0x0600) { + //$this->_storeSupbookInternal(); + /* TODO: store external SUPBOOK records and XCT and CRN records + in case of external references for BIFF8 */ + //$this->_storeExternsheetBiff8(); + $this->_storeSharedStringsTable(); + } + + // End Workbook globals + $this->_storeEof(); + + // Store the workbook in an OLE container + $res = $this->_storeOLEFile(); + if ($this->isError($res)) { + return $this->raiseError($res->getMessage()); + } + return true; + } + + /** + * Store the workbook in an OLE container + * + * @access private + * @return mixed true on success. PEAR_Error on failure + */ + protected function _storeOLEFile() + { + if($this->_BIFF_version == 0x0600) { + $OLE = new OLE_PPS_File(OLE::Asc2Ucs('Workbook')); + } else { + $OLE = new OLE_PPS_File(OLE::Asc2Ucs('Book')); + } + if ($this->_tmp_dir != '') { + $OLE->setTempDir($this->_tmp_dir); + } + $res = $OLE->init(); + if ($this->isError($res)) { + return $this->raiseError("OLE Error: ".$res->getMessage()); + } + $OLE->append($this->_data); + + $total_worksheets = count($this->_worksheets); + for ($i = 0; $i < $total_worksheets; $i++) { + while ($tmp = $this->_worksheets[$i]->getData(true)) { + $OLE->append($tmp); + } + } + + $root = new OLE_PPS_Root($this->_timestamp, $this->_timestamp, array($OLE)); + if ($this->_tmp_dir != '') { + $root->setTempDir($this->_tmp_dir); + } + + $res = $root->save($this->_filename); + if ($this->isError($res)) { + return $this->raiseError("OLE Error: ".$res->getMessage()); + } + return true; + } + + /** + * Calculate offsets for Worksheet BOF records. + * + * @access private + */ + protected function _calcSheetOffsets() + { + if ($this->_BIFF_version == 0x0600) { + $boundsheet_length = 12; // fixed length for a BOUNDSHEET record + } else { + $boundsheet_length = 11; + } + $EOF = 4; + $offset = $this->_datasize; + + if ($this->_BIFF_version == 0x0600) { + // add the length of the SST + /* TODO: check this works for a lot of strings (> 8224 bytes) */ + $offset += $this->_calculateSharedStringsSizes(); + if ($this->_country_code != -1) { + $offset += 8; // adding COUNTRY record + } + // add the lenght of SUPBOOK, EXTERNSHEET and NAME records + //$offset += 8; // FIXME: calculate real value when storing the records + } + $total_worksheets = count($this->_worksheets); + // add the length of the BOUNDSHEET records + for ($i = 0; $i < $total_worksheets; $i++) { + $offset += $boundsheet_length + strlen($this->_worksheets[$i]->name); + } + $offset += $EOF; + + for ($i = 0; $i < $total_worksheets; $i++) { + $this->_worksheets[$i]->offset = $offset; + $offset += $this->_worksheets[$i]->_datasize; + } + $this->_biffsize = $offset; + } + + /** + * Store the Excel FONT records. + * + * @access private + */ + protected function _storeAllFonts() + { + // tmp_format is added by the constructor. We use this to write the default XF's + $format = $this->_tmp_format; + $font = $format->getFont(); + + // Note: Fonts are 0-indexed. According to the SDK there is no index 4, + // so the following fonts are 0, 1, 2, 3, 5 + // + for ($i = 1; $i <= 5; $i++){ + $this->_append($font); + } + + // Iterate through the XF objects and write a FONT record if it isn't the + // same as the default FONT and if it hasn't already been used. + // + $fonts = array(); + $index = 6; // The first user defined FONT + + $key = $format->getFontKey(); // The default font from _tmp_format + $fonts[$key] = 0; // Index of the default font + + $total_formats = count($this->_formats); + for ($i = 0; $i < $total_formats; $i++) { + $key = $this->_formats[$i]->getFontKey(); + if (isset($fonts[$key])) { + // FONT has already been used + $this->_formats[$i]->font_index = $fonts[$key]; + } else { + // Add a new FONT record + $fonts[$key] = $index; + $this->_formats[$i]->font_index = $index; + $index++; + $font = $this->_formats[$i]->getFont(); + $this->_append($font); + } + } + } + + /** + * Store user defined numerical formats i.e. FORMAT records + * + * @access private + */ + protected function _storeAllNumFormats() + { + // Leaning num_format syndrome + $hash_num_formats = array(); + $num_formats = array(); + $index = 164; + + // Iterate through the XF objects and write a FORMAT record if it isn't a + // built-in format type and if the FORMAT string hasn't already been used. + $total_formats = count($this->_formats); + for ($i = 0; $i < $total_formats; $i++) { + $num_format = $this->_formats[$i]->_num_format; + + // Check if $num_format is an index to a built-in format. + // Also check for a string of zeros, which is a valid format string + // but would evaluate to zero. + // + if (!preg_match("/^0+\d/", $num_format)) { + if (preg_match("/^\d+$/", $num_format)) { // built-in format + continue; + } + } + + if (isset($hash_num_formats[$num_format])) { + // FORMAT has already been used + $this->_formats[$i]->_num_format = $hash_num_formats[$num_format]; + } else{ + // Add a new FORMAT + $hash_num_formats[$num_format] = $index; + $this->_formats[$i]->_num_format = $index; + array_push($num_formats,$num_format); + $index++; + } + } + + // Write the new FORMAT records starting from 0xA4 + $index = 164; + foreach ($num_formats as $num_format) { + $this->_storeNumFormat($num_format,$index); + $index++; + } + } + + /** + * Write all XF records. + * + * @access private + */ + protected function _storeAllXfs() + { + // _tmp_format is added by the constructor. We use this to write the default XF's + // The default font index is 0 + // + $format = $this->_tmp_format; + for ($i = 0; $i <= 14; $i++) { + $xf = $format->getXf('style'); // Style XF + $this->_append($xf); + } + + $xf = $format->getXf('cell'); // Cell XF + $this->_append($xf); + + // User defined XFs + $total_formats = count($this->_formats); + for ($i = 0; $i < $total_formats; $i++) { + $xf = $this->_formats[$i]->getXf('cell'); + $this->_append($xf); + } + } + + /** + * Write all STYLE records. + * + * @access private + */ + protected function _storeAllStyles() + { + $this->_storeStyle(); + } + + /** + * Write the EXTERNCOUNT and EXTERNSHEET records. These are used as indexes for + * the NAME records. + * + * @access private + */ + protected function _storeExterns() + + { + // Create EXTERNCOUNT with number of worksheets + $this->_storeExterncount(count($this->_worksheets)); + + // Create EXTERNSHEET for each worksheet + foreach ($this->_sheetnames as $sheetname) { + $this->_storeExternsheet($sheetname); + } + } + + /** + * Write the NAME record to define the print area and the repeat rows and cols. + * + * @access private + */ + protected function _storeNames() + { + // Create the print area NAME records + $total_worksheets = count($this->_worksheets); + for ($i = 0; $i < $total_worksheets; $i++) { + // Write a Name record if the print area has been defined + if (isset($this->_worksheets[$i]->print_rowmin)) { + $this->_storeNameShort( + $this->_worksheets[$i]->index, + 0x06, // NAME type + $this->_worksheets[$i]->print_rowmin, + $this->_worksheets[$i]->print_rowmax, + $this->_worksheets[$i]->print_colmin, + $this->_worksheets[$i]->print_colmax + ); + } + } + + // Create the print title NAME records + $total_worksheets = count($this->_worksheets); + for ($i = 0; $i < $total_worksheets; $i++) { + $rowmin = $this->_worksheets[$i]->title_rowmin; + $rowmax = $this->_worksheets[$i]->title_rowmax; + $colmin = $this->_worksheets[$i]->title_colmin; + $colmax = $this->_worksheets[$i]->title_colmax; + + // Determine if row + col, row, col or nothing has been defined + // and write the appropriate record + // + if (isset($rowmin) && isset($colmin)) { + // Row and column titles have been defined. + // Row title has been defined. + $this->_storeNameLong( + $this->_worksheets[$i]->index, + 0x07, // NAME type + $rowmin, + $rowmax, + $colmin, + $colmax + ); + } elseif (isset($rowmin)) { + // Row title has been defined. + $this->_storeNameShort( + $this->_worksheets[$i]->index, + 0x07, // NAME type + $rowmin, + $rowmax, + 0x00, + 0xff + ); + } elseif (isset($colmin)) { + // Column title has been defined. + $this->_storeNameShort( + $this->_worksheets[$i]->index, + 0x07, // NAME type + 0x0000, + 0x3fff, + $colmin, + $colmax + ); + } else { + // Print title hasn't been defined. + } + } + } + + + + + /****************************************************************************** + * + * BIFF RECORDS + * + */ + + /** + * Stores the CODEPAGE biff record. + * + * @access private + */ + protected function _storeCodepage() + { + $record = 0x0042; // Record identifier + $length = 0x0002; // Number of bytes to follow + $cv = $this->_codepage; // The code page + + $header = pack('vv', $record, $length); + $data = pack('v', $cv); + + $this->_append($header . $data); + } + + /** + * Write Excel BIFF WINDOW1 record. + * + * @access private + */ + protected function _storeWindow1() + { + $record = 0x003D; // Record identifier + $length = 0x0012; // Number of bytes to follow + + $xWn = 0x0000; // Horizontal position of window + $yWn = 0x0000; // Vertical position of window + $dxWn = 0x25BC; // Width of window + $dyWn = 0x1572; // Height of window + + $grbit = 0x0038; // Option flags + $ctabsel = $this->_selected; // Number of workbook tabs selected + $wTabRatio = 0x0258; // Tab to scrollbar ratio + + $itabFirst = $this->_firstsheet; // 1st displayed worksheet + $itabCur = $this->_activesheet; // Active worksheet + + $header = pack("vv", $record, $length); + $data = pack("vvvvvvvvv", $xWn, $yWn, $dxWn, $dyWn, + $grbit, + $itabCur, $itabFirst, + $ctabsel, $wTabRatio); + $this->_append($header . $data); + } + + /** + * Writes Excel BIFF BOUNDSHEET record. + * FIXME: inconsistent with BIFF documentation + * + * @param string $sheetname Worksheet name + * @param integer $offset Location of worksheet BOF + * @access private + */ + protected function _storeBoundsheet($sheetname,$offset) + { + $record = 0x0085; // Record identifier + if ($this->_BIFF_version == 0x0600) { + $length = 0x08 + strlen($sheetname); // Number of bytes to follow + } else { + $length = 0x07 + strlen($sheetname); // Number of bytes to follow + } + + $grbit = 0x0000; // Visibility and sheet type + if ($this->_BIFF_version == 0x0600) { + $cch = mb_strlen($sheetname,'UTF-16LE'); // Length of sheet name + } else { + $cch = strlen($sheetname); // Length of sheet name + } + + $header = pack("vv", $record, $length); + if ($this->_BIFF_version == 0x0600) { + $data = pack("VvCC", $offset, $grbit, $cch, 0x1); + } else { + $data = pack("VvC", $offset, $grbit, $cch); + } + $this->_append($header.$data.$sheetname); + } + + /** + * Write Internal SUPBOOK record + * + * @access private + */ + protected function _storeSupbookInternal() + { + $record = 0x01AE; // Record identifier + $length = 0x0004; // Bytes to follow + + $header = pack("vv", $record, $length); + $data = pack("vv", count($this->_worksheets), 0x0104); + $this->_append($header . $data); + } + + /** + * Writes the Excel BIFF EXTERNSHEET record. These references are used by + * formulas. + * + * @param string $sheetname Worksheet name + * @access private + */ + protected function _storeExternsheetBiff8() + { + $total_references = count($this->_parser->_references); + $record = 0x0017; // Record identifier + $length = 2 + 6 * $total_references; // Number of bytes to follow + + $supbook_index = 0; // FIXME: only using internal SUPBOOK record + $header = pack("vv", $record, $length); + $data = pack('v', $total_references); + for ($i = 0; $i < $total_references; $i++) { + $data .= $this->_parser->_references[$i]; + } + $this->_append($header . $data); + } + + /** + * Write Excel BIFF STYLE records. + * + * @access private + */ + protected function _storeStyle() + { + $record = 0x0293; // Record identifier + $length = 0x0004; // Bytes to follow + + $ixfe = 0x8000; // Index to style XF + $BuiltIn = 0x00; // Built-in style + $iLevel = 0xff; // Outline style level + + $header = pack("vv", $record, $length); + $data = pack("vCC", $ixfe, $BuiltIn, $iLevel); + $this->_append($header . $data); + } + + + /** + * Writes Excel FORMAT record for non "built-in" numerical formats. + * + * @param string $format Custom format string + * @param integer $ifmt Format index code + * @access private + */ + protected function _storeNumFormat($format, $ifmt) + { + $record = 0x041E; // Record identifier + + if ($this->_BIFF_version == 0x0600) { + $length = 5 + strlen($format); // Number of bytes to follow + $encoding = 0x0; + } elseif ($this->_BIFF_version == 0x0500) { + $length = 3 + strlen($format); // Number of bytes to follow + } + + if ( $this->_BIFF_version == 0x0600 && function_exists('iconv') ) { // Encode format String + if (mb_detect_encoding($format, 'auto') !== 'UTF-16LE'){ + $format = iconv(mb_detect_encoding($format, 'auto'),'UTF-16LE',$format); + } + $encoding = 1; + $cch = function_exists('mb_strlen') ? mb_strlen($format, 'UTF-16LE') : (strlen($format) / 2); + } else { + $encoding = 0; + $cch = strlen($format); // Length of format string + } + $length = strlen($format); + + if ($this->_BIFF_version == 0x0600) { + $header = pack("vv", $record, 5 + $length); + $data = pack("vvC", $ifmt, $cch, $encoding); + } elseif ($this->_BIFF_version == 0x0500) { + $header = pack("vv", $record, 3 + $length); + $data = pack("vC", $ifmt, $cch); + } + $this->_append($header . $data . $format); + } + + /** + * Write DATEMODE record to indicate the date system in use (1904 or 1900). + * + * @access private + */ + protected function _storeDatemode() + { + $record = 0x0022; // Record identifier + $length = 0x0002; // Bytes to follow + + $f1904 = $this->_1904; // Flag for 1904 date system + + $header = pack("vv", $record, $length); + $data = pack("v", $f1904); + $this->_append($header . $data); + } + + + /** + * Write BIFF record EXTERNCOUNT to indicate the number of external sheet + * references in the workbook. + * + * Excel only stores references to external sheets that are used in NAME. + * The workbook NAME record is required to define the print area and the repeat + * rows and columns. + * + * A similar method is used in Worksheet.php for a slightly different purpose. + * + * @param integer $cxals Number of external references + * @access private + */ + protected function _storeExterncount($cxals) + { + $record = 0x0016; // Record identifier + $length = 0x0002; // Number of bytes to follow + + $header = pack("vv", $record, $length); + $data = pack("v", $cxals); + $this->_append($header . $data); + } + + + /** + * Writes the Excel BIFF EXTERNSHEET record. These references are used by + * formulas. NAME record is required to define the print area and the repeat + * rows and columns. + * + * A similar method is used in Worksheet.php for a slightly different purpose. + * + * @param string $sheetname Worksheet name + * @access private + */ + protected function _storeExternsheet($sheetname) + { + $record = 0x0017; // Record identifier + $length = 0x02 + strlen($sheetname); // Number of bytes to follow + + $cch = strlen($sheetname); // Length of sheet name + $rgch = 0x03; // Filename encoding + + $header = pack("vv", $record, $length); + $data = pack("CC", $cch, $rgch); + $this->_append($header . $data . $sheetname); + } + + + /** + * Store the NAME record in the short format that is used for storing the print + * area, repeat rows only and repeat columns only. + * + * @param integer $index Sheet index + * @param integer $type Built-in name type + * @param integer $rowmin Start row + * @param integer $rowmax End row + * @param integer $colmin Start colum + * @param integer $colmax End column + * @access private + */ + protected function _storeNameShort($index, $type, $rowmin, $rowmax, $colmin, $colmax) + { + $record = 0x0018; // Record identifier + $length = 0x0024; // Number of bytes to follow + + $grbit = 0x0020; // Option flags + $chKey = 0x00; // Keyboard shortcut + $cch = 0x01; // Length of text name + $cce = 0x0015; // Length of text definition + $ixals = $index + 1; // Sheet index + $itab = $ixals; // Equal to ixals + $cchCustMenu = 0x00; // Length of cust menu text + $cchDescription = 0x00; // Length of description text + $cchHelptopic = 0x00; // Length of help topic text + $cchStatustext = 0x00; // Length of status bar text + $rgch = $type; // Built-in name type + + $unknown03 = 0x3b; + $unknown04 = 0xffff-$index; + $unknown05 = 0x0000; + $unknown06 = 0x0000; + $unknown07 = 0x1087; + $unknown08 = 0x8005; + + $header = pack("vv", $record, $length); + $data = pack("v", $grbit); + $data .= pack("C", $chKey); + $data .= pack("C", $cch); + $data .= pack("v", $cce); + $data .= pack("v", $ixals); + $data .= pack("v", $itab); + $data .= pack("C", $cchCustMenu); + $data .= pack("C", $cchDescription); + $data .= pack("C", $cchHelptopic); + $data .= pack("C", $cchStatustext); + $data .= pack("C", $rgch); + $data .= pack("C", $unknown03); + $data .= pack("v", $unknown04); + $data .= pack("v", $unknown05); + $data .= pack("v", $unknown06); + $data .= pack("v", $unknown07); + $data .= pack("v", $unknown08); + $data .= pack("v", $index); + $data .= pack("v", $index); + $data .= pack("v", $rowmin); + $data .= pack("v", $rowmax); + $data .= pack("C", $colmin); + $data .= pack("C", $colmax); + $this->_append($header . $data); + } + + + /** + * Store the NAME record in the long format that is used for storing the repeat + * rows and columns when both are specified. This shares a lot of code with + * _storeNameShort() but we use a separate method to keep the code clean. + * Code abstraction for reuse can be carried too far, and I should know. ;-) + * + * @param integer $index Sheet index + * @param integer $type Built-in name type + * @param integer $rowmin Start row + * @param integer $rowmax End row + * @param integer $colmin Start colum + * @param integer $colmax End column + * @access private + */ + protected function _storeNameLong($index, $type, $rowmin, $rowmax, $colmin, $colmax) + { + $record = 0x0018; // Record identifier + $length = 0x003d; // Number of bytes to follow + $grbit = 0x0020; // Option flags + $chKey = 0x00; // Keyboard shortcut + $cch = 0x01; // Length of text name + $cce = 0x002e; // Length of text definition + $ixals = $index + 1; // Sheet index + $itab = $ixals; // Equal to ixals + $cchCustMenu = 0x00; // Length of cust menu text + $cchDescription = 0x00; // Length of description text + $cchHelptopic = 0x00; // Length of help topic text + $cchStatustext = 0x00; // Length of status bar text + $rgch = $type; // Built-in name type + + $unknown01 = 0x29; + $unknown02 = 0x002b; + $unknown03 = 0x3b; + $unknown04 = 0xffff-$index; + $unknown05 = 0x0000; + $unknown06 = 0x0000; + $unknown07 = 0x1087; + $unknown08 = 0x8008; + + $header = pack("vv", $record, $length); + $data = pack("v", $grbit); + $data .= pack("C", $chKey); + $data .= pack("C", $cch); + $data .= pack("v", $cce); + $data .= pack("v", $ixals); + $data .= pack("v", $itab); + $data .= pack("C", $cchCustMenu); + $data .= pack("C", $cchDescription); + $data .= pack("C", $cchHelptopic); + $data .= pack("C", $cchStatustext); + $data .= pack("C", $rgch); + $data .= pack("C", $unknown01); + $data .= pack("v", $unknown02); + // Column definition + $data .= pack("C", $unknown03); + $data .= pack("v", $unknown04); + $data .= pack("v", $unknown05); + $data .= pack("v", $unknown06); + $data .= pack("v", $unknown07); + $data .= pack("v", $unknown08); + $data .= pack("v", $index); + $data .= pack("v", $index); + $data .= pack("v", 0x0000); + $data .= pack("v", 0x3fff); + $data .= pack("C", $colmin); + $data .= pack("C", $colmax); + // Row definition + $data .= pack("C", $unknown03); + $data .= pack("v", $unknown04); + $data .= pack("v", $unknown05); + $data .= pack("v", $unknown06); + $data .= pack("v", $unknown07); + $data .= pack("v", $unknown08); + $data .= pack("v", $index); + $data .= pack("v", $index); + $data .= pack("v", $rowmin); + $data .= pack("v", $rowmax); + $data .= pack("C", 0x00); + $data .= pack("C", 0xff); + // End of data + $data .= pack("C", 0x10); + $this->_append($header . $data); + } + + /** + * Stores the COUNTRY record for localization + * + * @access private + */ + protected function _storeCountry() + { + $record = 0x008C; // Record identifier + $length = 4; // Number of bytes to follow + + $header = pack('vv', $record, $length); + /* using the same country code always for simplicity */ + $data = pack('vv', $this->_country_code, $this->_country_code); + $this->_append($header . $data); + } + + /** + * Stores the PALETTE biff record. + * + * @access private + */ + protected function _storePalette() + { + $aref = $this->_palette; + + $record = 0x0092; // Record identifier + $length = 2 + 4 * count($aref); // Number of bytes to follow + $ccv = count($aref); // Number of RGB values to follow + $data = ''; // The RGB data + + // Pack the RGB data + foreach ($aref as $color) { + foreach ($color as $byte) { + $data .= pack("C",$byte); + } + } + + $header = pack("vvv", $record, $length, $ccv); + $this->_append($header . $data); + } + + /** + * Calculate + * Handling of the SST continue blocks is complicated by the need to include an + * additional continuation byte depending on whether the string is split between + * blocks or whether it starts at the beginning of the block. (There are also + * additional complications that will arise later when/if Rich Strings are + * supported). + * + * @access private + */ + protected function _calculateSharedStringsSizes() + { + /* Iterate through the strings to calculate the CONTINUE block sizes. + For simplicity we use the same size for the SST and CONTINUE records: + 8228 : Maximum Excel97 block size + -4 : Length of block header + -8 : Length of additional SST header information + -8 : Arbitrary number to keep within _add_continue() limit = 8208 + */ + $continue_limit = 8208; + $block_length = 0; + $written = 0; + $this->_block_sizes = array(); + $continue = 0; + + foreach (array_keys($this->_str_table) as $string) { + $string_length = strlen($string); + $headerinfo = unpack("vlength/Cencoding", $string); + $encoding = $headerinfo["encoding"]; + $split_string = 0; + + // Block length is the total length of the strings that will be + // written out in a single SST or CONTINUE block. + $block_length += $string_length; + + // We can write the string if it doesn't cross a CONTINUE boundary + if ($block_length < $continue_limit) { + $written += $string_length; + continue; + } + + // Deal with the cases where the next string to be written will exceed + // the CONTINUE boundary. If the string is very long it may need to be + // written in more than one CONTINUE record. + while ($block_length >= $continue_limit) { + + // We need to avoid the case where a string is continued in the first + // n bytes that contain the string header information. + $header_length = 3; // Min string + header size -1 + $space_remaining = $continue_limit - $written - $continue; + + + /* TODO: Unicode data should only be split on char (2 byte) + boundaries. Therefore, in some cases we need to reduce the + amount of available + */ + $align = 0; + + // Only applies to Unicode strings + if ($encoding == 1) { + // Min string + header size -1 + $header_length = 4; + + if ($space_remaining > $header_length) { + // String contains 3 byte header => split on odd boundary + if (!$split_string && $space_remaining % 2 != 1) { + $space_remaining--; + $align = 1; + } + // Split section without header => split on even boundary + else if ($split_string && $space_remaining % 2 == 1) { + $space_remaining--; + $align = 1; + } + + $split_string = 1; + } + } + + + if ($space_remaining > $header_length) { + // Write as much as possible of the string in the current block + $written += $space_remaining; + + // Reduce the current block length by the amount written + $block_length -= $continue_limit - $continue - $align; + + // Store the max size for this block + $this->_block_sizes[] = $continue_limit - $align; + + // If the current string was split then the next CONTINUE block + // should have the string continue flag (grbit) set unless the + // split string fits exactly into the remaining space. + if ($block_length > 0) { + $continue = 1; + } else { + $continue = 0; + } + } else { + // Store the max size for this block + $this->_block_sizes[] = $written + $continue; + + // Not enough space to start the string in the current block + $block_length -= $continue_limit - $space_remaining - $continue; + $continue = 0; + + } + + // If the string (or substr) is small enough we can write it in the + // new CONTINUE block. Else, go through the loop again to write it in + // one or more CONTINUE blocks + if ($block_length < $continue_limit) { + $written = $block_length; + } else { + $written = 0; + } + } + } + + // Store the max size for the last block unless it is empty + if ($written + $continue) { + $this->_block_sizes[] = $written + $continue; + } + + + /* Calculate the total length of the SST and associated CONTINUEs (if any). + The SST record will have a length even if it contains no strings. + This length is required to set the offsets in the BOUNDSHEET records since + they must be written before the SST records + */ + + $tmp_block_sizes = $this->_block_sizes; + + $length = 12; + if (!empty($tmp_block_sizes)) { + $length += array_shift($tmp_block_sizes); // SST + } + while (!empty($tmp_block_sizes)) { + $length += 4 + array_shift($tmp_block_sizes); // CONTINUEs + } + + return $length; + } + + /** + * Write all of the workbooks strings into an indexed array. + * See the comments in _calculate_shared_string_sizes() for more information. + * + * The Excel documentation says that the SST record should be followed by an + * EXTSST record. The EXTSST record is a hash table that is used to optimise + * access to SST. However, despite the documentation it doesn't seem to be + * required so we will ignore it. + * + * @access private + */ + protected function _storeSharedStringsTable() + { + $record = 0x00fc; // Record identifier + $length = 0x0008; // Number of bytes to follow + $total = 0x0000; + + // Iterate through the strings to calculate the CONTINUE block sizes + $continue_limit = 8208; + $block_length = 0; + $written = 0; + $continue = 0; + + // sizes are upside down + $tmp_block_sizes = $this->_block_sizes; + // $tmp_block_sizes = array_reverse($this->_block_sizes); + + // The SST record is required even if it contains no strings. Thus we will + // always have a length + // + if (!empty($tmp_block_sizes)) { + $length = 8 + array_shift($tmp_block_sizes); + } + else { + // No strings + $length = 8; + } + + + + // Write the SST block header information + $header = pack("vv", $record, $length); + $data = pack("VV", $this->_str_total, $this->_str_unique); + $this->_append($header . $data); + + + + + /* TODO: not good for performance */ + foreach (array_keys($this->_str_table) as $string) { + + $string_length = strlen($string); + $headerinfo = unpack("vlength/Cencoding", $string); + $encoding = $headerinfo["encoding"]; + $split_string = 0; + + // Block length is the total length of the strings that will be + // written out in a single SST or CONTINUE block. + // + $block_length += $string_length; + + + // We can write the string if it doesn't cross a CONTINUE boundary + if ($block_length < $continue_limit) { + $this->_append($string); + $written += $string_length; + continue; + } + + // Deal with the cases where the next string to be written will exceed + // the CONTINUE boundary. If the string is very long it may need to be + // written in more than one CONTINUE record. + // + while ($block_length >= $continue_limit) { + + // We need to avoid the case where a string is continued in the first + // n bytes that contain the string header information. + // + $header_length = 3; // Min string + header size -1 + $space_remaining = $continue_limit - $written - $continue; + + + // Unicode data should only be split on char (2 byte) boundaries. + // Therefore, in some cases we need to reduce the amount of available + // space by 1 byte to ensure the correct alignment. + $align = 0; + + // Only applies to Unicode strings + if ($encoding == 1) { + // Min string + header size -1 + $header_length = 4; + + if ($space_remaining > $header_length) { + // String contains 3 byte header => split on odd boundary + if (!$split_string && $space_remaining % 2 != 1) { + $space_remaining--; + $align = 1; + } + // Split section without header => split on even boundary + else if ($split_string && $space_remaining % 2 == 1) { + $space_remaining--; + $align = 1; + } + + $split_string = 1; + } + } + + + if ($space_remaining > $header_length) { + // Write as much as possible of the string in the current block + $tmp = substr($string, 0, $space_remaining); + $this->_append($tmp); + + // The remainder will be written in the next block(s) + $string = substr($string, $space_remaining); + + // Reduce the current block length by the amount written + $block_length -= $continue_limit - $continue - $align; + + // If the current string was split then the next CONTINUE block + // should have the string continue flag (grbit) set unless the + // split string fits exactly into the remaining space. + // + if ($block_length > 0) { + $continue = 1; + } else { + $continue = 0; + } + } else { + // Not enough space to start the string in the current block + $block_length -= $continue_limit - $space_remaining - $continue; + $continue = 0; + } + + // Write the CONTINUE block header + if (!empty($this->_block_sizes)) { + $record = 0x003C; + $length = array_shift($tmp_block_sizes); + + $header = pack('vv', $record, $length); + if ($continue) { + $header .= pack('C', $encoding); + } + $this->_append($header); + } + + // If the string (or substr) is small enough we can write it in the + // new CONTINUE block. Else, go through the loop again to write it in + // one or more CONTINUE blocks + // + if ($block_length < $continue_limit) { + $this->_append($string); + $written = $block_length; + } else { + $written = 0; + } + } + } + } + + +} + diff --git a/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Worksheet.php b/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Worksheet.php new file mode 100644 index 00000000..32516495 --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/Spreadsheet/Excel/Writer/Worksheet.php @@ -0,0 +1,3609 @@ + +* +* The majority of this is _NOT_ my code. I simply ported it from the +* PERL Spreadsheet::WriteExcel module. +* +* The author of the Spreadsheet::WriteExcel module is John McNamara +* +* +* I _DO_ maintain this code, and John McNamara has nothing to do with the +* porting of this code to PHP. Any questions directly related to this +* class library should be directed to me. +* +* License Information: +* +* Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets +* Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +if (!class_exists('Spreadsheet_Excel_Writer_BIFFwriter')) { + require_once 'Spreadsheet/Excel/Writer/Parser.php'; + require_once 'Spreadsheet/Excel/Writer/BIFFwriter.php'; +} + +/** +* Class for generating Excel Spreadsheets +* +* @author Xavier Noguer +* @category FileFormats +* @package Spreadsheet_Excel_Writer +*/ + +class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwriter +{ + /** + * Name of the Worksheet + * @var string + */ + public $name; + + /** + * Index for the Worksheet + * @var integer + */ + public $index; + + /** + * Reference to the (default) Format object for URLs + * @var Spreadsheet_Excel_Writer_Format + */ + public $_url_format; + + /** + * Reference to the parser used for parsing formulas + * @var Spreadsheet_Excel_Writer_Format + */ + public $_parser; + + /** + * Filehandle to the temporary file for storing data + * @var resource + */ + public $_filehandle; + + /** + * Boolean indicating if we are using a temporary file for storing data + * @var bool + */ + public $_using_tmpfile; + + /** + * Maximum number of rows for an Excel spreadsheet (BIFF5) + * @var integer + */ + public $_xls_rowmax; + + /** + * Maximum number of columns for an Excel spreadsheet (BIFF5) + * @var integer + */ + public $_xls_colmax; + + /** + * Maximum number of characters for a string (LABEL record in BIFF5) + * @var integer + */ + public $_xls_strmax; + + /** + * First row for the DIMENSIONS record + * @var integer + * @see _storeDimensions() + */ + public $_dim_rowmin; + + /** + * Last row for the DIMENSIONS record + * @var integer + * @see _storeDimensions() + */ + public $_dim_rowmax; + + /** + * First column for the DIMENSIONS record + * @var integer + * @see _storeDimensions() + */ + public $_dim_colmin; + + /** + * Last column for the DIMENSIONS record + * @var integer + * @see _storeDimensions() + */ + public $_dim_colmax; + + /** + * Array containing format information for columns + * @var array + */ + public $_colinfo; + + /** + * Array containing the selected area for the worksheet + * @var array + */ + public $_selection; + + /** + * Array containing the panes for the worksheet + * @var array + */ + public $_panes; + + /** + * The active pane for the worksheet + * @var integer + */ + public $_active_pane; + + /** + * Bit specifying if panes are frozen + * @var integer + */ + public $_frozen; + + /** + * Bit specifying if the worksheet is selected + * @var integer + */ + public $selected; + + /** + * The paper size (for printing) (DOCUMENT!!!) + * @var integer + */ + public $_paper_size; + + /** + * Bit specifying paper orientation (for printing). 0 => landscape, 1 => portrait + * @var integer + */ + public $_orientation; + + /** + * The page header caption + * @var string + */ + public $_header; + + /** + * The page footer caption + * @var string + */ + public $_footer; + + /** + * The horizontal centering value for the page + * @var integer + */ + public $_hcenter; + + /** + * The vertical centering value for the page + * @var integer + */ + public $_vcenter; + + /** + * The margin for the header + * @var float + */ + public $_margin_head; + + /** + * The margin for the footer + * @var float + */ + public $_margin_foot; + + /** + * The left margin for the worksheet in inches + * @var float + */ + public $_margin_left; + + /** + * The right margin for the worksheet in inches + * @var float + */ + public $_margin_right; + + /** + * The top margin for the worksheet in inches + * @var float + */ + public $_margin_top; + + /** + * The bottom margin for the worksheet in inches + * @var float + */ + public $_margin_bottom; + + /** + * First row to reapeat on each printed page + * @var integer + */ + public $title_rowmin; + + /** + * Last row to reapeat on each printed page + * @var integer + */ + public $title_rowmax; + + /** + * First column to reapeat on each printed page + * @var integer + */ + public $title_colmin; + + /** + * First row of the area to print + * @var integer + */ + public $print_rowmin; + + /** + * Last row to of the area to print + * @var integer + */ + public $print_rowmax; + + /** + * First column of the area to print + * @var integer + */ + public $print_colmin; + + /** + * Last column of the area to print + * @var integer + */ + public $print_colmax; + + /** + * Whether to display RightToLeft. + * @var integer + */ + public $_Arabic; + + /** + * Whether to use outline. + * @var integer + */ + public $_outline_on; + + /** + * Auto outline styles. + * @var bool + */ + public $_outline_style; + + /** + * Whether to have outline summary below. + * @var bool + */ + public $_outline_below; + + /** + * Whether to have outline summary at the right. + * @var bool + */ + public $_outline_right; + + /** + * Outline row level. + * @var integer + */ + public $_outline_row_level; + + /** + * Whether to fit to page when printing or not. + * @var bool + */ + public $_fit_page; + + /** + * Number of pages to fit wide + * @var integer + */ + public $_fit_width; + + /** + * Number of pages to fit high + * @var integer + */ + public $_fit_height; + + /** + * Reference to the total number of strings in the workbook + * @var integer + */ + public $_str_total; + + /** + * Reference to the number of unique strings in the workbook + * @var integer + */ + public $_str_unique; + + /** + * Reference to the array containing all the unique strings in the workbook + * @var array + */ + public $_str_table; + + /** + * Number of merged cell ranges in actual record + * @var int $_merged_cells_counter + */ + public $_merged_cells_counter = 0; + + /** + * Number of actual mergedcells record + * @var int $_merged_cells_record + */ + public $_merged_cells_record = 0; + + /** + * Merged cell ranges + * @var array + */ + public $_merged_ranges; + + /** + * Charset encoding currently used when calling writeString() + * @var string + */ + public $_input_encoding; + + /** + * Constructor + * + * @param string $name The name of the new worksheet + * @param integer $index The index of the new worksheet + * @param mixed $activesheet The current activesheet of the workbook we belong to + * @param mixed $firstsheet The first worksheet in the workbook we belong to + * @param int &$str_total Reference to the total number of strings in the workbook + * @param int &$str_unique Reference to the number of unique strings in the workbook + * @param array &$str_table Reference to the array containing all the unique strings in the workbook + * @param mixed $url_format The default format for hyperlinks + * @param mixed $parser The formula parser created for the Workbook + * @param string $tmp_dir The path to the directory for temporary files + * @access private + */ + public function __construct($BIFF_version, $name, + $index, $activesheet, + $firstsheet, &$str_total, + &$str_unique, &$str_table, + $url_format, $parser, + $tmp_dir) + { + // It needs to call its parent's constructor explicitly + parent::__construct(); + $this->_BIFF_version = $BIFF_version; + $rowmax = 65536; // 16384 in Excel 5 + $colmax = 256; + + $this->name = $name; + $this->index = $index; + $this->activesheet = $activesheet; + $this->firstsheet = $firstsheet; + // _str_total _str_unique _str_table - are actual references + // everything breaks if they're not + $this->_str_total = &$str_total; + $this->_str_unique = &$str_unique; + $this->_str_table = &$str_table; + $this->_url_format = $url_format; + $this->_parser = $parser; + + //$this->ext_sheets = array(); + $this->_filehandle = ''; + $this->_using_tmpfile = true; + //$this->fileclosed = 0; + //$this->offset = 0; + $this->_xls_rowmax = $rowmax; + $this->_xls_colmax = $colmax; + $this->_xls_strmax = 255; + $this->_dim_rowmin = $rowmax + 1; + $this->_dim_rowmax = 0; + $this->_dim_colmin = $colmax + 1; + $this->_dim_colmax = 0; + $this->_colinfo = array(); + $this->_selection = array(0,0,0,0); + $this->_panes = array(); + $this->_active_pane = 3; + $this->_frozen = 0; + $this->selected = 0; + + $this->_paper_size = 0x0; + $this->_orientation = 0x1; + $this->_header = ''; + $this->_footer = ''; + $this->_hcenter = 0; + $this->_vcenter = 0; + $this->_margin_head = 0.50; + $this->_margin_foot = 0.50; + $this->_margin_left = 0.75; + $this->_margin_right = 0.75; + $this->_margin_top = 1.00; + $this->_margin_bottom = 1.00; + + $this->title_rowmin = null; + $this->title_rowmax = null; + $this->title_colmin = null; + $this->title_colmax = null; + $this->print_rowmin = null; + $this->print_rowmax = null; + $this->print_colmin = null; + $this->print_colmax = null; + + $this->_print_gridlines = 1; + $this->_screen_gridlines = 1; + $this->_print_headers = 0; + + $this->_fit_page = 0; + $this->_fit_width = 0; + $this->_fit_height = 0; + + $this->_hbreaks = array(); + $this->_vbreaks = array(); + + $this->_protect = 0; + $this->_password = null; + + $this->col_sizes = array(); + $this->_row_sizes = array(); + + $this->_zoom = 100; + $this->_print_scale = 100; + + $this->_outline_row_level = 0; + $this->_outline_style = 0; + $this->_outline_below = 1; + $this->_outline_right = 1; + $this->_outline_on = 1; + $this->_Arabic = 0; + + $this->_merged_ranges = array(); + + $this->_input_encoding = ''; + + $this->_dv = array(); + + $this->_tmp_dir = $tmp_dir; + $this->_tmp_file = ''; + + $this->_initialize(); + } + + /** + * Open a tmp file to store the majority of the Worksheet data. If this fails, + * for example due to write permissions, store the data in memory. This can be + * slow for large files. + * + * @access private + */ + protected function _initialize() + { + if ($this->_using_tmpfile == false) { + return; + } + + if ($this->_tmp_dir === '' && ini_get('open_basedir') === true) { + // open_basedir restriction in effect - store data in memory + // ToDo: Let the error actually have an effect somewhere + $this->_using_tmpfile = false; + return new PEAR_Error('Temp file could not be opened since open_basedir restriction in effect - please use setTmpDir() - using memory storage instead'); + } + + // Open tmp file for storing Worksheet data + if ($this->_tmp_dir === '') { + $fh = tmpfile(); + } else { + // For people with open base dir restriction + $this->_tmp_file = tempnam($this->_tmp_dir, "Spreadsheet_Excel_Writer"); + $fh = @fopen($this->_tmp_file, "w+b"); + } + + if ($fh === false) { + // If tmpfile() fails store data in memory + $this->_using_tmpfile = false; + } else { + // Store filehandle + $this->_filehandle = $fh; + } + } + + /** + * Add data to the beginning of the workbook (note the reverse order) + * and to the end of the workbook. + * + * @access public + * @see Spreadsheet_Excel_Writer_Workbook::storeWorkbook() + * @param array $sheetnames The array of sheetnames from the Workbook this + * worksheet belongs to + */ + public function close($sheetnames) + { + $num_sheets = count($sheetnames); + + /*********************************************** + * Prepend in reverse order!! + */ + + // Prepend the sheet dimensions + $this->_storeDimensions(); + + // Prepend the sheet password + $this->_storePassword(); + + // Prepend the sheet protection + $this->_storeProtect(); + + // Prepend the page setup + $this->_storeSetup(); + + /* FIXME: margins are actually appended */ + // Prepend the bottom margin + $this->_storeMarginBottom(); + + // Prepend the top margin + $this->_storeMarginTop(); + + // Prepend the right margin + $this->_storeMarginRight(); + + // Prepend the left margin + $this->_storeMarginLeft(); + + // Prepend the page vertical centering + $this->_storeVcenter(); + + // Prepend the page horizontal centering + $this->_storeHcenter(); + + // Prepend the page footer + $this->_storeFooter(); + + // Prepend the page header + $this->_storeHeader(); + + // Prepend the vertical page breaks + $this->_storeVbreak(); + + // Prepend the horizontal page breaks + $this->_storeHbreak(); + + // Prepend WSBOOL + $this->_storeWsbool(); + + // Prepend GRIDSET + $this->_storeGridset(); + + // Prepend GUTS + if ($this->_BIFF_version == 0x0500) { + $this->_storeGuts(); + } + + // Prepend PRINTGRIDLINES + $this->_storePrintGridlines(); + + // Prepend PRINTHEADERS + $this->_storePrintHeaders(); + + // Prepend EXTERNSHEET references + if ($this->_BIFF_version == 0x0500) { + for ($i = $num_sheets; $i > 0; $i--) { + $sheetname = $sheetnames[$i-1]; + $this->_storeExternsheet($sheetname); + } + } + + // Prepend the EXTERNCOUNT of external references. + if ($this->_BIFF_version == 0x0500) { + $this->_storeExterncount($num_sheets); + } + + // Prepend the COLINFO records if they exist + if (!empty($this->_colinfo)) { + $colcount = count($this->_colinfo); + for ($i = 0; $i < $colcount; $i++) { + $this->_storeColinfo($this->_colinfo[$i]); + } + $this->_storeDefcol(); + } + + // Prepend the BOF record + $this->_storeBof(0x0010); + + /* + * End of prepend. Read upwards from here. + ***********************************************/ + + // Append + $this->_storeWindow2(); + $this->_storeZoom(); + if (!empty($this->_panes)) { + $this->_storePanes($this->_panes); + } + $this->_storeSelection($this->_selection); + $this->_storeMergedCells(); + /* TODO: add data validity */ + /*if ($this->_BIFF_version == 0x0600) { + $this->_storeDataValidity(); + }*/ + $this->_storeEof(); + } + + /** + * Retrieve the worksheet name. + * This is usefull when creating worksheets without a name. + * + * @access public + * @return string The worksheet's name + */ + public function getName() + { + return $this->name; + } + + /** + * Retrieves data from memory in one chunk, or from disk in $buffer + * sized chunks. + * + * @return string The data + */ + public function getData($cleanup = true) + { + $buffer = 4096; + + // Return data stored in memory + if (isset($this->_data)) { + $tmp = $this->_data; + unset($this->_data); + if ($this->_using_tmpfile) { + fseek($this->_filehandle, 0); + } + return $tmp; + } + // Return data stored on disk + if ($this->_using_tmpfile) { + if ($tmp = fread($this->_filehandle, $buffer)) { + return $tmp; + } + + // All data has now been read (both from memory & from file) so we + // can now trash the file + if ($cleanup) { + if ( $this->_filehandle ) { + fclose($this->_filehandle); + $this->_filehandle = ''; + } + @unlink($this->_tmp_file); + $this->_tmp_file = ''; + $this->_using_tmpfile = false; + $this->_datasize = 0; + } + } + + // No data to return + return ''; + } + + /** + * Sets a merged cell range + * + * @access public + * @param integer $first_row First row of the area to merge + * @param integer $first_col First column of the area to merge + * @param integer $last_row Last row of the area to merge + * @param integer $last_col Last column of the area to merge + */ + public function setMerge($first_row, $first_col, $last_row, $last_col) + { + if (($last_row < $first_row) || ($last_col < $first_col)) { + return; + } + + $max_record_ranges = floor(($this->_limit - 6) / 8); + if($this->_merged_cells_counter >= $max_record_ranges) + { + $this->_merged_cells_record++; + $this->_merged_cells_counter = 0; + } + + // don't check rowmin, rowmax, etc... because we don't know when this + // is going to be called + $this->_merged_ranges[$this->_merged_cells_record][] = array($first_row, $first_col, $last_row, $last_col); + $this->_merged_cells_counter++; + } + + /** + * Set this worksheet as a selected worksheet, + * i.e. the worksheet has its tab highlighted. + * + * @access public + */ + public function select() + { + $this->selected = 1; + } + + /** + * Set this worksheet as the active worksheet, + * i.e. the worksheet that is displayed when the workbook is opened. + * Also set it as selected. + * + * @access public + */ + public function activate() + { + $this->selected = 1; + $this->activesheet = $this->index; + } + + /** + * Set this worksheet as the first visible sheet. + * This is necessary when there are a large number of worksheets and the + * activated worksheet is not visible on the screen. + * + * @access public + */ + public function setFirstSheet() + { + $this->firstsheet = $this->index; + } + + /** + * Set the worksheet protection flag + * to prevent accidental modification and to + * hide formulas if the locked and hidden format properties have been set. + * + * @access public + * @param string $password The password to use for protecting the sheet. + */ + public function protect($password) + { + $this->_protect = 1; + $this->_password = $this->_encodePassword($password); + } + + /** + * Set the width of a single column or a range of columns. + * + * @access public + * @param integer $firstcol first column on the range + * @param integer $lastcol last column on the range + * @param integer $width width to set + * @param mixed $format The optional XF format to apply to the columns + * @param integer $hidden The optional hidden atribute + * @param integer $level The optional outline level + */ + public function setColumn($firstcol, $lastcol, $width, $format = null, $hidden = 0, $level = 0) + { // added by Dan Lynn _colinfo as $key => $colinfo) + { + $existing_start = $colinfo[0]; $existing_end = $colinfo[1]; + // if the new range starts within another range + if ($firstcol > $existing_start && $firstcol < $existing_end) + { // trim the existing range to the beginning of the new range + $this->_colinfo[$key][1] = $firstcol - 1; + // if the new range lies WITHIN the existing range + if ($lastcol < $existing_end) + { // split the existing range by adding a range after our new range + $this->_colinfo[] = array($lastcol+1, $existing_end, $colinfo[2], /* format */ $colinfo[3], $colinfo[4], $colinfo[5]); + } + } // if the new range ends inside an existing range + elseif ($lastcol > $existing_start && $lastcol < $existing_end) + { // trim the existing range to the end of the new range + $this->_colinfo[$key][0] = $lastcol + 1; + } // if the new range completely overlaps the existing range + elseif ($firstcol <= $existing_start && $lastcol >= $existing_end) + { + unset($this->_colinfo[$key]); + } + } // added by Dan Lynn _colinfo = array_values($this->_colinfo); + $this->_colinfo[] = array($firstcol, $lastcol, $width, $format, $hidden, $level); + // Set width to zero if column is hidden + $width = ($hidden) ? 0 : $width; + for ($col = $firstcol; $col <= $lastcol; $col++) + { + $this->col_sizes[$col] = $width; + } + } + + /** + * Set which cell or cells are selected in a worksheet + * + * @access public + * @param integer $first_row first row in the selected quadrant + * @param integer $first_column first column in the selected quadrant + * @param integer $last_row last row in the selected quadrant + * @param integer $last_column last column in the selected quadrant + */ + public function setSelection($first_row,$first_column,$last_row,$last_column) + { + $this->_selection = array($first_row,$first_column,$last_row,$last_column); + } + + /** + * Set panes and mark them as frozen. + * + * @access public + * @param array $panes This is the only parameter received and is composed of the following: + * 0 => Vertical split position, + * 1 => Horizontal split position + * 2 => Top row visible + * 3 => Leftmost column visible + * 4 => Active pane + */ + public function freezePanes($panes) + { + $this->_frozen = 1; + $this->_panes = $panes; + } + + /** + * Set panes and mark them as unfrozen. + * + * @access public + * @param array $panes This is the only parameter received and is composed of the following: + * 0 => Vertical split position, + * 1 => Horizontal split position + * 2 => Top row visible + * 3 => Leftmost column visible + * 4 => Active pane + */ + public function thawPanes($panes) + { + $this->_frozen = 0; + $this->_panes = $panes; + } + + /** + * Set the page orientation as portrait. + * + * @access public + */ + public function setPortrait() + { + $this->_orientation = 1; + } + + /** + * Set the page orientation as landscape. + * + * @access public + */ + public function setLandscape() + { + $this->_orientation = 0; + } + + /** + * Set the paper type. Ex. 1 = US Letter, 9 = A4 + * + * @access public + * @param integer $size The type of paper size to use + */ + public function setPaper($size = 0) + { + $this->_paper_size = $size; + } + + + /** + * Set the page header caption and optional margin. + * + * @access public + * @param string $string The header text + * @param float $margin optional head margin in inches. + */ + public function setHeader($string,$margin = 0.50) + { + if (strlen($string) >= 255) { + //carp 'Header string must be less than 255 characters'; + return; + } + $this->_header = $string; + $this->_margin_head = $margin; + } + + /** + * Set the page footer caption and optional margin. + * + * @access public + * @param string $string The footer text + * @param float $margin optional foot margin in inches. + */ + public function setFooter($string,$margin = 0.50) + { + if (strlen($string) >= 255) { + //carp 'Footer string must be less than 255 characters'; + return; + } + $this->_footer = $string; + $this->_margin_foot = $margin; + } + + /** + * Center the page horinzontally. + * + * @access public + * @param integer $center the optional value for centering. Defaults to 1 (center). + */ + public function centerHorizontally($center = 1) + { + $this->_hcenter = $center; + } + + /** + * Center the page vertically. + * + * @access public + * @param integer $center the optional value for centering. Defaults to 1 (center). + */ + public function centerVertically($center = 1) + { + $this->_vcenter = $center; + } + + /** + * Set all the page margins to the same value in inches. + * + * @access public + * @param float $margin The margin to set in inches + */ + public function setMargins($margin) + { + $this->setMarginLeft($margin); + $this->setMarginRight($margin); + $this->setMarginTop($margin); + $this->setMarginBottom($margin); + } + + /** + * Set the left and right margins to the same value in inches. + * + * @access public + * @param float $margin The margin to set in inches + */ + public function setMargins_LR($margin) + { + $this->setMarginLeft($margin); + $this->setMarginRight($margin); + } + + /** + * Set the top and bottom margins to the same value in inches. + * + * @access public + * @param float $margin The margin to set in inches + */ + public function setMargins_TB($margin) + { + $this->setMarginTop($margin); + $this->setMarginBottom($margin); + } + + /** + * Set the left margin in inches. + * + * @access public + * @param float $margin The margin to set in inches + */ + public function setMarginLeft($margin = 0.75) + { + $this->_margin_left = $margin; + } + + /** + * Set the right margin in inches. + * + * @access public + * @param float $margin The margin to set in inches + */ + public function setMarginRight($margin = 0.75) + { + $this->_margin_right = $margin; + } + + /** + * Set the top margin in inches. + * + * @access public + * @param float $margin The margin to set in inches + */ + public function setMarginTop($margin = 1.00) + { + $this->_margin_top = $margin; + } + + /** + * Set the bottom margin in inches. + * + * @access public + * @param float $margin The margin to set in inches + */ + public function setMarginBottom($margin = 1.00) + { + $this->_margin_bottom = $margin; + } + + /** + * Set the rows to repeat at the top of each printed page. + * + * @access public + * @param integer $first_row First row to repeat + * @param integer $last_row Last row to repeat. Optional. + */ + public function repeatRows($first_row, $last_row = null) + { + $this->title_rowmin = $first_row; + if (isset($last_row)) { //Second row is optional + $this->title_rowmax = $last_row; + } else { + $this->title_rowmax = $first_row; + } + } + + /** + * Set the columns to repeat at the left hand side of each printed page. + * + * @access public + * @param integer $first_col First column to repeat + * @param integer $last_col Last column to repeat. Optional. + */ + public function repeatColumns($first_col, $last_col = null) + { + $this->title_colmin = $first_col; + if (isset($last_col)) { // Second col is optional + $this->title_colmax = $last_col; + } else { + $this->title_colmax = $first_col; + } + } + + /** + * Set the area of each worksheet that will be printed. + * + * @access public + * @param integer $first_row First row of the area to print + * @param integer $first_col First column of the area to print + * @param integer $last_row Last row of the area to print + * @param integer $last_col Last column of the area to print + */ + public function printArea($first_row, $first_col, $last_row, $last_col) + { + $this->print_rowmin = $first_row; + $this->print_colmin = $first_col; + $this->print_rowmax = $last_row; + $this->print_colmax = $last_col; + } + + + /** + * Set the option to hide gridlines on the printed page. + * + * @access public + */ + public function hideGridlines() + { + $this->_print_gridlines = 0; + } + + /** + * Set the option to hide gridlines on the worksheet (as seen on the screen). + * + * @access public + */ + public function hideScreenGridlines() + { + $this->_screen_gridlines = 0; + } + + /** + * Set the option to print the row and column headers on the printed page. + * + * @access public + * @param integer $print Whether to print the headers or not. Defaults to 1 (print). + */ + public function printRowColHeaders($print = 1) + { + $this->_print_headers = $print; + } + + /** + * Set the vertical and horizontal number of pages that will define the maximum area printed. + * It doesn't seem to work with OpenOffice. + * + * @access public + * @param integer $width Maximun width of printed area in pages + * @param integer $height Maximun heigth of printed area in pages + * @see setPrintScale() + */ + public function fitToPages($width, $height) + { + $this->_fit_page = 1; + $this->_fit_width = $width; + $this->_fit_height = $height; + } + + /** + * Store the horizontal page breaks on a worksheet (for printing). + * The breaks represent the row after which the break is inserted. + * + * @access public + * @param array $breaks Array containing the horizontal page breaks + */ + public function setHPagebreaks($breaks) + { + foreach ($breaks as $break) { + array_push($this->_hbreaks, $break); + } + } + + /** + * Store the vertical page breaks on a worksheet (for printing). + * The breaks represent the column after which the break is inserted. + * + * @access public + * @param array $breaks Array containing the vertical page breaks + */ + public function setVPagebreaks($breaks) + { + foreach ($breaks as $break) { + array_push($this->_vbreaks, $break); + } + } + + + /** + * Set the worksheet zoom factor. + * + * @access public + * @param integer $scale The zoom factor + */ + public function setZoom($scale = 100) + { + // Confine the scale to Excel's range + if ($scale < 10 || $scale > 400) { + $this->raiseError("Zoom factor $scale outside range: 10 <= zoom <= 400"); + $scale = 100; + } + + $this->_zoom = floor($scale); + } + + /** + * Set the scale factor for the printed page. + * It turns off the "fit to page" option + * + * @access public + * @param integer $scale The optional scale factor. Defaults to 100 + */ + public function setPrintScale($scale = 100) + { + // Confine the scale to Excel's range + if ($scale < 10 || $scale > 400) { + $this->raiseError("Print scale $scale outside range: 10 <= zoom <= 400"); + $scale = 100; + } + + // Turn off "fit to page" option + $this->_fit_page = 0; + + $this->_print_scale = floor($scale); + } + + /** + * Map to the appropriate write method acording to the token recieved. + * + * @access public + * @param integer $row The row of the cell we are writing to + * @param integer $col The column of the cell we are writing to + * @param mixed $token What we are writing + * @param mixed $format The optional format to apply to the cell + */ + public function write($row, $col, $token, $format = null) + { + // Check for a cell reference in A1 notation and substitute row and column + /*if ($_[0] =~ /^\D/) { + @_ = $this->_substituteCellref(@_); + }*/ + + if (preg_match("/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/", $token)) { + // Match number + return $this->writeNumber($row, $col, $token, $format); + } elseif (preg_match("/^[fh]tt?p:\/\//", $token)) { + // Match http or ftp URL + return $this->writeUrl($row, $col, $token, '', $format); + } elseif (preg_match("/^mailto:/", $token)) { + // Match mailto: + return $this->writeUrl($row, $col, $token, '', $format); + } elseif (preg_match("/^(?:in|ex)ternal:/", $token)) { + // Match internal or external sheet link + return $this->writeUrl($row, $col, $token, '', $format); + } elseif (preg_match("/^=/", $token)) { + // Match formula + return $this->writeFormula($row, $col, $token, $format); + } elseif ($token == '') { + // Match blank + return $this->writeBlank($row, $col, $format); + } else { + // Default: match string + return $this->writeString($row, $col, $token, $format); + } + } + + /** + * Write an array of values as a row + * + * @access public + * @param integer $row The row we are writing to + * @param integer $col The first col (leftmost col) we are writing to + * @param array $val The array of values to write + * @param mixed $format The optional format to apply to the cell + * @return mixed PEAR_Error on failure + */ + + public function writeRow($row, $col, $val, $format = null) + { + $retval = ''; + if (is_array($val)) { + foreach ($val as $v) { + if (is_array($v)) { + $this->writeCol($row, $col, $v, $format); + } else { + $this->write($row, $col, $v, $format); + } + $col++; + } + } else { + $retval = new PEAR_Error('$val needs to be an array'); + } + return($retval); + } + + /** + * Write an array of values as a column + * + * @access public + * @param integer $row The first row (uppermost row) we are writing to + * @param integer $col The col we are writing to + * @param array $val The array of values to write + * @param mixed $format The optional format to apply to the cell + * @return mixed PEAR_Error on failure + */ + + public function writeCol($row, $col, $val, $format = null) + { + $retval = ''; + if (is_array($val)) { + foreach ($val as $v) { + $this->write($row, $col, $v, $format); + $row++; + } + } else { + $retval = new PEAR_Error('$val needs to be an array'); + } + return($retval); + } + + /** + * Returns an index to the XF record in the workbook + * + * @access private + * @param mixed $format The optional XF format + * @return integer The XF record index + */ + protected function _XF($format) + { + if ($format) { + return($format->getXfIndex()); + } else { + return(0x0F); + } + } + + + /****************************************************************************** + ******************************************************************************* + * + * Internal methods + */ + + + /** + * Store Worksheet data in memory using the parent's class append() or to a + * temporary file, the default. + * + * @access private + * @param string $data The binary data to append + */ + protected function _append($data) + { + if ($this->_using_tmpfile) { + // Add CONTINUE records if necessary + if (strlen($data) > $this->_limit) { + $data = $this->_addContinue($data); + } + fwrite($this->_filehandle, $data); + $this->_datasize += strlen($data); + } else { + parent::_append($data); + } + } + + /** + * Substitute an Excel cell reference in A1 notation for zero based row and + * column values in an argument list. + * + * Ex: ("A4", "Hello") is converted to (3, 0, "Hello"). + * + * @access private + * @param string $cell The cell reference. Or range of cells. + * @return array + */ + protected function _substituteCellref($cell) + { + $cell = strtoupper($cell); + + // Convert a column range: 'A:A' or 'B:G' + if (preg_match("/([A-I]?[A-Z]):([A-I]?[A-Z])/", $cell, $match)) { + list($no_use, $col1) = $this->_cellToRowcol($match[1] .'1'); // Add a dummy row + list($no_use, $col2) = $this->_cellToRowcol($match[2] .'1'); // Add a dummy row + return(array($col1, $col2)); + } + + // Convert a cell range: 'A1:B7' + if (preg_match("/\$?([A-I]?[A-Z]\$?\d+):\$?([A-I]?[A-Z]\$?\d+)/", $cell, $match)) { + list($row1, $col1) = $this->_cellToRowcol($match[1]); + list($row2, $col2) = $this->_cellToRowcol($match[2]); + return(array($row1, $col1, $row2, $col2)); + } + + // Convert a cell reference: 'A1' or 'AD2000' + if (preg_match("/\$?([A-I]?[A-Z]\$?\d+)/", $cell)) { + list($row1, $col1) = $this->_cellToRowcol($match[1]); + return(array($row1, $col1)); + } + + // TODO use real error codes + $this->raiseError("Unknown cell reference $cell", 0, PEAR_ERROR_DIE); + } + + /** + * Convert an Excel cell reference in A1 notation to a zero based row and column + * reference; converts C1 to (0, 2). + * + * @access private + * @param string $cell The cell reference. + * @return array containing (row, column) + */ + protected function _cellToRowcol($cell) + { + preg_match("/\$?([A-I]?[A-Z])\$?(\d+)/",$cell,$match); + $col = $match[1]; + $row = $match[2]; + + // Convert base26 column string to number + $chars = explode('', $col); + $expn = 0; + $col = 0; + + while ($chars) { + $char = array_pop($chars); // LS char first + $col += (ord($char) -ord('A') +1) * pow(26,$expn); + $expn++; + } + + // Convert 1-index to zero-index + $row--; + $col--; + + return(array($row, $col)); + } + + /** + * Based on the algorithm provided by Daniel Rentz of OpenOffice. + * + * @access private + * @param string $plaintext The password to be encoded in plaintext. + * @return string The encoded password + */ + protected function _encodePassword($plaintext) + { + $password = 0x0000; + $i = 1; // char position + + // split the plain text password in its component characters + $chars = preg_split('//', $plaintext, -1, PREG_SPLIT_NO_EMPTY); + foreach ($chars as $char) { + $value = ord($char) << $i; // shifted ASCII value + $rotated_bits = $value >> 15; // rotated bits beyond bit 15 + $value &= 0x7fff; // first 15 bits + $password ^= ($value | $rotated_bits); + $i++; + } + + $password ^= strlen($plaintext); + $password ^= 0xCE4B; + + return($password); + } + + /** + * This method sets the properties for outlining and grouping. The defaults + * correspond to Excel's defaults. + * + * @param bool $visible + * @param bool $symbols_below + * @param bool $symbols_right + * @param bool $auto_style + */ + public function setOutline($visible = true, $symbols_below = true, $symbols_right = true, $auto_style = false) + { + $this->_outline_on = $visible; + $this->_outline_below = $symbols_below; + $this->_outline_right = $symbols_right; + $this->_outline_style = $auto_style; + + // Ensure this is a boolean vale for Window2 + if ($this->_outline_on) { + $this->_outline_on = 1; + } + } + + /** + * This method sets the worksheet direction to right-to-left (RTL) + * + * @param bool $rtl + */ + public function setRTL($rtl = true) + { + $this->_Arabic = ($rtl ? 1 : 0); + } + + /****************************************************************************** + ******************************************************************************* + * + * BIFF RECORDS + */ + + + /** + * Write a double to the specified row and column (zero indexed). + * An integer can be written as a double. Excel will display an + * integer. $format is optional. + * + * Returns 0 : normal termination + * -2 : row or column out of range + * + * @access public + * @param integer $row Zero indexed row + * @param integer $col Zero indexed column + * @param float $num The number to write + * @param mixed $format The optional XF format + * @return integer + */ + public function writeNumber($row, $col, $num, $format = null) + { + $record = 0x0203; // Record identifier + $length = 0x000E; // Number of bytes to follow + + $xf = $this->_XF($format); // The cell format + + // Check that row and col are valid and store max and min values + if ($row >= $this->_xls_rowmax) { + return(-2); + } + if ($col >= $this->_xls_colmax) { + return(-2); + } + if ($row < $this->_dim_rowmin) { + $this->_dim_rowmin = $row; + } + if ($row > $this->_dim_rowmax) { + $this->_dim_rowmax = $row; + } + if ($col < $this->_dim_colmin) { + $this->_dim_colmin = $col; + } + if ($col > $this->_dim_colmax) { + $this->_dim_colmax = $col; + } + + $header = pack("vv", $record, $length); + $data = pack("vvv", $row, $col, $xf); + $xl_double = pack("d", $num); + if ($this->_byte_order) { // if it's Big Endian + $xl_double = strrev($xl_double); + } + + $this->_append($header.$data.$xl_double); + return(0); + } + + /** + * Write a string to the specified row and column (zero indexed). + * NOTE: there is an Excel 5 defined limit of 255 characters. + * $format is optional. + * Returns 0 : normal termination + * -2 : row or column out of range + * -3 : long string truncated to 255 chars + * + * @access public + * @param integer $row Zero indexed row + * @param integer $col Zero indexed column + * @param string $str The string to write + * @param mixed $format The XF format for the cell + * @return integer + */ + public function writeString($row, $col, $str, $format = null) + { + if ($this->_BIFF_version == 0x0600) { + return $this->writeStringBIFF8($row, $col, $str, $format); + } + $strlen = strlen($str); + $record = 0x0204; // Record identifier + $length = 0x0008 + $strlen; // Bytes to follow + $xf = $this->_XF($format); // The cell format + + $str_error = 0; + + // Check that row and col are valid and store max and min values + if ($row >= $this->_xls_rowmax) { + return(-2); + } + if ($col >= $this->_xls_colmax) { + return(-2); + } + if ($row < $this->_dim_rowmin) { + $this->_dim_rowmin = $row; + } + if ($row > $this->_dim_rowmax) { + $this->_dim_rowmax = $row; + } + if ($col < $this->_dim_colmin) { + $this->_dim_colmin = $col; + } + if ($col > $this->_dim_colmax) { + $this->_dim_colmax = $col; + } + + if ($strlen > $this->_xls_strmax) { // LABEL must be < 255 chars + $str = substr($str, 0, $this->_xls_strmax); + $length = 0x0008 + $this->_xls_strmax; + $strlen = $this->_xls_strmax; + $str_error = -3; + } + + $header = pack("vv", $record, $length); + $data = pack("vvvv", $row, $col, $xf, $strlen); + $this->_append($header . $data . $str); + return($str_error); + } + + /** + * Sets Input Encoding for writing strings + * + * @access public + * @param string $encoding The encoding. Ex: 'UTF-16LE', 'utf-8', 'ISO-859-7' + */ + public function setInputEncoding($encoding) + { + if ($encoding != 'UTF-16LE' && !function_exists('iconv')) { + $this->raiseError("Using an input encoding other than UTF-16LE requires PHP support for iconv"); + } + $this->_input_encoding = $encoding; + } + + /** + * Write a string to the specified row and column (zero indexed). + * This is the BIFF8 version (no 255 chars limit). + * $format is optional. + * Returns 0 : normal termination + * -2 : row or column out of range + * -3 : long string truncated to 255 chars + * + * @access public + * @param integer $row Zero indexed row + * @param integer $col Zero indexed column + * @param string $str The string to write + * @param mixed $format The XF format for the cell + * @return integer + */ + public function writeStringBIFF8($row, $col, $str, $format = null) + { + // If the string is Unicode and contains any "surrogate pairs" then using mb_strlen($str, 'UTF-16LE') + // as the string length will cause a "found unreadable content" error when opening the worksheet in Excel + // (apparently the length is expected to be the number of 16-bit code points, not the number of characters). + // Instead, always use the byte length divided by two for Unicode strings, and if mb_strlen() exists use + // mb_strlen($str, '8bit') just in case mbstring.func_overload is set to overload strlen(). + if ($this->_input_encoding == 'UTF-16LE') + { + $strlen = (function_exists('mb_strlen') ? mb_strlen($str, '8bit') : strlen($str)) / 2; + $encoding = 0x1; + } + elseif ($this->_input_encoding != '') + { + $str = iconv($this->_input_encoding, 'UTF-16LE', $str); + $strlen = (function_exists('mb_strlen') ? mb_strlen($str, '8bit') : strlen($str)) / 2; + $encoding = 0x1; + } + else + { + $strlen = function_exists('mb_strlen') ? mb_strlen($str, '8bit') : strlen($str); + $encoding = 0x0; + } + $record = 0x00FD; // Record identifier + $length = 0x000A; // Bytes to follow + $xf = $this->_XF($format); // The cell format + + $str_error = 0; + + // Check that row and col are valid and store max and min values + if ($this->_checkRowCol($row, $col) == false) { + return -2; + } + + $str = pack('vC', $strlen, $encoding).$str; + + /* check if string is already present */ + if (!isset($this->_str_table[$str])) { + $this->_str_table[$str] = $this->_str_unique++; + } + $this->_str_total++; + + $header = pack('vv', $record, $length); + $data = pack('vvvV', $row, $col, $xf, $this->_str_table[$str]); + $this->_append($header.$data); + return $str_error; + } + + /** + * Check row and col before writing to a cell, and update the sheet's + * dimensions accordingly + * + * @access private + * @param integer $row Zero indexed row + * @param integer $col Zero indexed column + * @return boolean true for success, false if row and/or col are grester + * then maximums allowed. + */ + protected function _checkRowCol($row, $col) + { + if ($row >= $this->_xls_rowmax) { + return false; + } + if ($col >= $this->_xls_colmax) { + return false; + } + if ($row < $this->_dim_rowmin) { + $this->_dim_rowmin = $row; + } + if ($row > $this->_dim_rowmax) { + $this->_dim_rowmax = $row; + } + if ($col < $this->_dim_colmin) { + $this->_dim_colmin = $col; + } + if ($col > $this->_dim_colmax) { + $this->_dim_colmax = $col; + } + return true; + } + + /** + * Writes a note associated with the cell given by the row and column. + * NOTE records don't have a length limit. + * + * @access public + * @param integer $row Zero indexed row + * @param integer $col Zero indexed column + * @param string $note The note to write + */ + public function writeNote($row, $col, $note) + { + $note_length = strlen($note); + $record = 0x001C; // Record identifier + $max_length = 2048; // Maximun length for a NOTE record + //$length = 0x0006 + $note_length; // Bytes to follow + + // Check that row and col are valid and store max and min values + if ($row >= $this->_xls_rowmax) { + return(-2); + } + if ($col >= $this->_xls_colmax) { + return(-2); + } + if ($row < $this->_dim_rowmin) { + $this->_dim_rowmin = $row; + } + if ($row > $this->_dim_rowmax) { + $this->_dim_rowmax = $row; + } + if ($col < $this->_dim_colmin) { + $this->_dim_colmin = $col; + } + if ($col > $this->_dim_colmax) { + $this->_dim_colmax = $col; + } + + // Length for this record is no more than 2048 + 6 + $length = 0x0006 + min($note_length, 2048); + $header = pack("vv", $record, $length); + $data = pack("vvv", $row, $col, $note_length); + $this->_append($header . $data . substr($note, 0, 2048)); + + for ($i = $max_length; $i < $note_length; $i += $max_length) { + $chunk = substr($note, $i, $max_length); + $length = 0x0006 + strlen($chunk); + $header = pack("vv", $record, $length); + $data = pack("vvv", -1, 0, strlen($chunk)); + $this->_append($header.$data.$chunk); + } + return(0); + } + + /** + * Write a blank cell to the specified row and column (zero indexed). + * A blank cell is used to specify formatting without adding a string + * or a number. + * + * A blank cell without a format serves no purpose. Therefore, we don't write + * a BLANK record unless a format is specified. + * + * Returns 0 : normal termination (including no format) + * -1 : insufficient number of arguments + * -2 : row or column out of range + * + * @access public + * @param integer $row Zero indexed row + * @param integer $col Zero indexed column + * @param mixed $format The XF format + */ + public function writeBlank($row, $col, $format) + { + // Don't write a blank cell unless it has a format + if (!$format) { + return(0); + } + + $record = 0x0201; // Record identifier + $length = 0x0006; // Number of bytes to follow + $xf = $this->_XF($format); // The cell format + + // Check that row and col are valid and store max and min values + if ($row >= $this->_xls_rowmax) { + return(-2); + } + if ($col >= $this->_xls_colmax) { + return(-2); + } + if ($row < $this->_dim_rowmin) { + $this->_dim_rowmin = $row; + } + if ($row > $this->_dim_rowmax) { + $this->_dim_rowmax = $row; + } + if ($col < $this->_dim_colmin) { + $this->_dim_colmin = $col; + } + if ($col > $this->_dim_colmax) { + $this->_dim_colmax = $col; + } + + $header = pack("vv", $record, $length); + $data = pack("vvv", $row, $col, $xf); + $this->_append($header . $data); + return 0; + } + + /** + * Write a formula to the specified row and column (zero indexed). + * The textual representation of the formula is passed to the parser in + * Parser.php which returns a packed binary string. + * + * Returns 0 : normal termination + * -1 : formula errors (bad formula) + * -2 : row or column out of range + * + * @access public + * @param integer $row Zero indexed row + * @param integer $col Zero indexed column + * @param string $formula The formula text string + * @param mixed $format The optional XF format + * @return integer + */ + public function writeFormula($row, $col, $formula, $format = null) + { + $record = 0x0006; // Record identifier + + // Excel normally stores the last calculated value of the formula in $num. + // Clearly we are not in a position to calculate this a priori. Instead + // we set $num to zero and set the option flags in $grbit to ensure + // automatic calculation of the formula when the file is opened. + // + $xf = $this->_XF($format); // The cell format + $num = 0x00; // Current value of formula + $grbit = 0x03; // Option flags + $unknown = 0x0000; // Must be zero + + + // Check that row and col are valid and store max and min values + if ($this->_checkRowCol($row, $col) == false) { + return -2; + } + + // Strip the '=' or '@' sign at the beginning of the formula string + if (preg_match("/^=/", $formula)) { + $formula = preg_replace("/(^=)/", "", $formula); + } elseif (preg_match("/^@/", $formula)) { + $formula = preg_replace("/(^@)/", "", $formula); + } else { + // Error handling + $this->writeString($row, $col, 'Unrecognised character for formula'); + return -1; + } + + // Parse the formula using the parser in Parser.php + $error = $this->_parser->parse($formula); + if ($this->isError($error)) { + $this->writeString($row, $col, $error->getMessage()); + return -1; + } + + $formula = $this->_parser->toReversePolish(); + if ($this->isError($formula)) { + $this->writeString($row, $col, $formula->getMessage()); + return -1; + } + + $formlen = strlen($formula); // Length of the binary string + $length = 0x16 + $formlen; // Length of the record data + + $header = pack("vv", $record, $length); + $data = pack("vvvdvVv", $row, $col, $xf, $num, + $grbit, $unknown, $formlen); + + $this->_append($header . $data . $formula); + return 0; + } + + /** + * Write a hyperlink. + * This is comprised of two elements: the visible label and + * the invisible link. The visible label is the same as the link unless an + * alternative string is specified. The label is written using the + * writeString() method. Therefore the 255 characters string limit applies. + * $string and $format are optional. + * + * The hyperlink can be to a http, ftp, mail, internal sheet (not yet), or external + * directory url. + * + * Returns 0 : normal termination + * -2 : row or column out of range + * -3 : long string truncated to 255 chars + * + * @access public + * @param integer $row Row + * @param integer $col Column + * @param string $url URL string + * @param string $string Alternative label + * @param mixed $format The cell format + * @return integer + */ + public function writeUrl($row, $col, $url, $string = '', $format = null) + { + // Add start row and col to arg list + return($this->_writeUrlRange($row, $col, $row, $col, $url, $string, $format)); + } + + /** + * This is the more general form of writeUrl(). It allows a hyperlink to be + * written to a range of cells. This public function also decides the type of hyperlink + * to be written. These are either, Web (http, ftp, mailto), Internal + * (Sheet1!A1) or external ('c:\temp\foo.xls#Sheet1!A1'). + * + * @access private + * @see writeUrl() + * @param integer $row1 Start row + * @param integer $col1 Start column + * @param integer $row2 End row + * @param integer $col2 End column + * @param string $url URL string + * @param string $string Alternative label + * @param mixed $format The cell format + * @return integer + */ + + protected function _writeUrlRange($row1, $col1, $row2, $col2, $url, $string = '', $format = null) + { + + // Check for internal/external sheet links or default to web link + if (preg_match('[^internal:]', $url)) { + return($this->_writeUrlInternal($row1, $col1, $row2, $col2, $url, $string, $format)); + } + if (preg_match('[^external:]', $url)) { + return($this->_writeUrlExternal($row1, $col1, $row2, $col2, $url, $string, $format)); + } + return($this->_writeUrlWeb($row1, $col1, $row2, $col2, $url, $string, $format)); + } + + + /** + * Used to write http, ftp and mailto hyperlinks. + * The link type ($options) is 0x03 is the same as absolute dir ref without + * sheet. However it is differentiated by the $unknown2 data stream. + * + * @access private + * @see writeUrl() + * @param integer $row1 Start row + * @param integer $col1 Start column + * @param integer $row2 End row + * @param integer $col2 End column + * @param string $url URL string + * @param string $str Alternative label + * @param mixed $format The cell format + * @return integer + */ + protected function _writeUrlWeb($row1, $col1, $row2, $col2, $url, $str, $format = null) + { + $record = 0x01B8; // Record identifier + $length = 0x00000; // Bytes to follow + + if (!$format) { + $format = $this->_url_format; + } + + // Write the visible label using the writeString() method. + if ($str == '') { + $str = $url; + } + $str_error = is_numeric($str) ? $this->writeNumber($row1, $col1, $str, $format) : $this->writeString($row1, $col1, $str, $format); + if (($str_error == -2) || ($str_error == -3)) { + return $str_error; + } + + // Pack the undocumented parts of the hyperlink stream + $unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000"); + $unknown2 = pack("H*", "E0C9EA79F9BACE118C8200AA004BA90B"); + + // Pack the option flags + $options = pack("V", 0x03); + + // Convert URL to a null terminated wchar string + $url = join("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY)); + $url = $url . "\0\0\0"; + + // Pack the length of the URL + $url_len = pack("V", strlen($url)); + + // Calculate the data length + $length = 0x34 + strlen($url); + + // Pack the header data + $header = pack("vv", $record, $length); + $data = pack("vvvv", $row1, $row2, $col1, $col2); + + // Write the packed data + $this->_append($header . $data . + $unknown1 . $options . + $unknown2 . $url_len . $url); + return($str_error); + } + + /** + * Used to write internal reference hyperlinks such as "Sheet1!A1". + * + * @access private + * @see writeUrl() + * @param integer $row1 Start row + * @param integer $col1 Start column + * @param integer $row2 End row + * @param integer $col2 End column + * @param string $url URL string + * @param string $str Alternative label + * @param mixed $format The cell format + * @return integer + */ + protected function _writeUrlInternal($row1, $col1, $row2, $col2, $url, $str, $format = null) + { + $record = 0x01B8; // Record identifier + $length = 0x00000; // Bytes to follow + + if (!$format) { + $format = $this->_url_format; + } + + // Strip URL type + $url = preg_replace('/^internal:/', '', $url); + + // Write the visible label + if ($str == '') { + $str = $url; + } + $str_error = is_numeric($str) ? $this->writeNumber($row1, $col1, $str, $format) : $this->writeString($row1, $col1, $str, $format); + if (($str_error == -2) || ($str_error == -3)) { + return $str_error; + } + + // Pack the undocumented parts of the hyperlink stream + $unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000"); + + // Pack the option flags + $options = pack("V", 0x08); + + // Convert the URL type and to a null terminated wchar string + $url = join("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY)); + $url = $url . "\0\0\0"; + + // Pack the length of the URL as chars (not wchars) + $url_len = pack("V", floor(strlen($url)/2)); + + // Calculate the data length + $length = 0x24 + strlen($url); + + // Pack the header data + $header = pack("vv", $record, $length); + $data = pack("vvvv", $row1, $row2, $col1, $col2); + + // Write the packed data + $this->_append($header . $data . + $unknown1 . $options . + $url_len . $url); + return($str_error); + } + + /** + * Write links to external directory names such as 'c:\foo.xls', + * c:\foo.xls#Sheet1!A1', '../../foo.xls'. and '../../foo.xls#Sheet1!A1'. + * + * Note: Excel writes some relative links with the $dir_long string. We ignore + * these cases for the sake of simpler code. + * + * @access private + * @see writeUrl() + * @param integer $row1 Start row + * @param integer $col1 Start column + * @param integer $row2 End row + * @param integer $col2 End column + * @param string $url URL string + * @param string $str Alternative label + * @param mixed $format The cell format + * @return integer + */ + protected function _writeUrlExternal($row1, $col1, $row2, $col2, $url, $str, $format = null) + { + // Network drives are different. We will handle them separately + // MS/Novell network drives and shares start with \\ + if (preg_match('[^external:\\\\]', $url)) { + return; //($this->_writeUrlExternal_net($row1, $col1, $row2, $col2, $url, $str, $format)); + } + + $record = 0x01B8; // Record identifier + $length = 0x00000; // Bytes to follow + + if (!$format) { + $format = $this->_url_format; + } + + // Strip URL type and change Unix dir separator to Dos style (if needed) + // + $url = preg_replace('/^external:/', '', $url); + $url = preg_replace('/\//', "\\", $url); + + // Write the visible label + if ($str == '') { + $str = preg_replace('/\#/', ' - ', $url); + } + $str_error = is_numeric($str) ? $this->writeNumber($row1, $col1, $str, $format) : $this->writeString($row1, $col1, $str, $format); + if (($str_error == -2) or ($str_error == -3)) { + return $str_error; + } + + // Determine if the link is relative or absolute: + // relative if link contains no dir separator, "somefile.xls" + // relative if link starts with up-dir, "..\..\somefile.xls" + // otherwise, absolute + + $absolute = 0x02; // Bit mask + if (!preg_match("/\\\/", $url)) { + $absolute = 0x00; + } + if (preg_match("/^\.\.\\\/", $url)) { + $absolute = 0x00; + } + $link_type = 0x01 | $absolute; + + // Determine if the link contains a sheet reference and change some of the + // parameters accordingly. + // Split the dir name and sheet name (if it exists) + /*if (preg_match("/\#/", $url)) { + list($dir_long, $sheet) = split("\#", $url); + } else { + $dir_long = $url; + } + + if (isset($sheet)) { + $link_type |= 0x08; + $sheet_len = pack("V", strlen($sheet) + 0x01); + $sheet = join("\0", split('', $sheet)); + $sheet .= "\0\0\0"; + } else { + $sheet_len = ''; + $sheet = ''; + }*/ + $dir_long = $url; + if (preg_match("/\#/", $url)) { + $link_type |= 0x08; + } + + + + // Pack the link type + $link_type = pack("V", $link_type); + + // Calculate the up-level dir count e.g.. (..\..\..\ == 3) + $up_count = preg_match_all("/\.\.\\\/", $dir_long, $useless); + $up_count = pack("v", $up_count); + + // Store the short dos dir name (null terminated) + $dir_short = preg_replace("/\.\.\\\/", '', $dir_long) . "\0"; + + // Store the long dir name as a wchar string (non-null terminated) + //$dir_long = join("\0", split('', $dir_long)); + $dir_long = $dir_long . "\0"; + + // Pack the lengths of the dir strings + $dir_short_len = pack("V", strlen($dir_short) ); + $dir_long_len = pack("V", strlen($dir_long) ); + $stream_len = pack("V", 0);//strlen($dir_long) + 0x06); + + // Pack the undocumented parts of the hyperlink stream + $unknown1 = pack("H*",'D0C9EA79F9BACE118C8200AA004BA90B02000000' ); + $unknown2 = pack("H*",'0303000000000000C000000000000046' ); + $unknown3 = pack("H*",'FFFFADDE000000000000000000000000000000000000000'); + $unknown4 = pack("v", 0x03 ); + + // Pack the main data stream + $data = pack("vvvv", $row1, $row2, $col1, $col2) . + $unknown1 . + $link_type . + $unknown2 . + $up_count . + $dir_short_len. + $dir_short . + $unknown3 . + $stream_len ;/*. + $dir_long_len . + $unknown4 . + $dir_long . + $sheet_len . + $sheet ;*/ + + // Pack the header data + $length = strlen($data); + $header = pack("vv", $record, $length); + + // Write the packed data + $this->_append($header. $data); + return($str_error); + } + + + /** + * This method is used to set the height and format for a row. + * + * @access public + * @param integer $row The row to set + * @param integer $height Height we are giving to the row. + * Use null to set XF without setting height + * @param mixed $format XF format we are giving to the row + * @param bool $hidden The optional hidden attribute + * @param integer $level The optional outline level for row, in range [0,7] + */ + public function setRow($row, $height, $format = null, $hidden = false, $level = 0) + { + $record = 0x0208; // Record identifier + $length = 0x0010; // Number of bytes to follow + + $colMic = 0x0000; // First defined column + $colMac = 0x0000; // Last defined column + $irwMac = 0x0000; // Used by Excel to optimise loading + $reserved = 0x0000; // Reserved + $grbit = 0x0000; // Option flags + $ixfe = $this->_XF($format); // XF index + + // set _row_sizes so _sizeRow() can use it + $this->_row_sizes[$row] = $height; + + // Use setRow($row, null, $XF) to set XF format without setting height + if ($height != null) { + $miyRw = $height * 20; // row height + } else { + $miyRw = 0xff; // default row height is 256 + } + + $level = max(0, min($level, 7)); // level should be between 0 and 7 + $this->_outline_row_level = max($level, $this->_outline_row_level); + + + // Set the options flags. fUnsynced is used to show that the font and row + // heights are not compatible. This is usually the case for WriteExcel. + // The collapsed flag 0x10 doesn't seem to be used to indicate that a row + // is collapsed. Instead it is used to indicate that the previous row is + // collapsed. The zero height flag, 0x20, is used to collapse a row. + + $grbit |= $level; + if ($hidden) { + $grbit |= 0x0020; + } + $grbit |= 0x0040; // fUnsynced + if ($format) { + $grbit |= 0x0080; + } + $grbit |= 0x0100; + + $header = pack("vv", $record, $length); + $data = pack("vvvvvvvv", $row, $colMic, $colMac, $miyRw, + $irwMac,$reserved, $grbit, $ixfe); + $this->_append($header.$data); + } + + /** + * Writes Excel DIMENSIONS to define the area in which there is data. + * + * @access private + */ + protected function _storeDimensions() + { + $record = 0x0200; // Record identifier + $row_min = $this->_dim_rowmin; // First row + $row_max = $this->_dim_rowmax + 1; // Last row plus 1 + $col_min = $this->_dim_colmin; // First column + $col_max = $this->_dim_colmax + 1; // Last column plus 1 + $reserved = 0x0000; // Reserved by Excel + + if ($this->_BIFF_version == 0x0500) { + $length = 0x000A; // Number of bytes to follow + $data = pack("vvvvv", $row_min, $row_max, + $col_min, $col_max, $reserved); + } elseif ($this->_BIFF_version == 0x0600) { + $length = 0x000E; + $data = pack("VVvvv", $row_min, $row_max, + $col_min, $col_max, $reserved); + } + $header = pack("vv", $record, $length); + $this->_prepend($header.$data); + } + + /** + * Write BIFF record Window2. + * + * @access private + */ + protected function _storeWindow2() + { + $record = 0x023E; // Record identifier + if ($this->_BIFF_version == 0x0500) { + $length = 0x000A; // Number of bytes to follow + } elseif ($this->_BIFF_version == 0x0600) { + $length = 0x0012; + } + + $grbit = 0x00B6; // Option flags + $rwTop = 0x0000; // Top row visible in window + $colLeft = 0x0000; // Leftmost column visible in window + + + // The options flags that comprise $grbit + $fDspFmla = 0; // 0 - bit + $fDspGrid = $this->_screen_gridlines; // 1 + $fDspRwCol = 1; // 2 + $fFrozen = $this->_frozen; // 3 + $fDspZeros = 1; // 4 + $fDefaultHdr = 1; // 5 + $fArabic = $this->_Arabic; // 6 + $fDspGuts = $this->_outline_on; // 7 + $fFrozenNoSplit = 0; // 0 - bit + $fSelected = $this->selected; // 1 + $fPaged = 1; // 2 + + $grbit = $fDspFmla; + $grbit |= $fDspGrid << 1; + $grbit |= $fDspRwCol << 2; + $grbit |= $fFrozen << 3; + $grbit |= $fDspZeros << 4; + $grbit |= $fDefaultHdr << 5; + $grbit |= $fArabic << 6; + $grbit |= $fDspGuts << 7; + $grbit |= $fFrozenNoSplit << 8; + $grbit |= $fSelected << 9; + $grbit |= $fPaged << 10; + + $header = pack("vv", $record, $length); + $data = pack("vvv", $grbit, $rwTop, $colLeft); + // FIXME !!! + if ($this->_BIFF_version == 0x0500) { + $rgbHdr = 0x00000000; // Row/column heading and gridline color + $data .= pack("V", $rgbHdr); + } elseif ($this->_BIFF_version == 0x0600) { + $rgbHdr = 0x0040; // Row/column heading and gridline color index + $zoom_factor_page_break = 0x0000; + $zoom_factor_normal = 0x0000; + $data .= pack("vvvvV", $rgbHdr, 0x0000, $zoom_factor_page_break, $zoom_factor_normal, 0x00000000); + } + $this->_append($header.$data); + } + + /** + * Write BIFF record DEFCOLWIDTH if COLINFO records are in use. + * + * @access private + */ + protected function _storeDefcol() + { + $record = 0x0055; // Record identifier + $length = 0x0002; // Number of bytes to follow + $colwidth = 0x0008; // Default column width + + $header = pack("vv", $record, $length); + $data = pack("v", $colwidth); + $this->_prepend($header . $data); + } + + /** + * Write BIFF record COLINFO to define column widths + * + * Note: The SDK says the record length is 0x0B but Excel writes a 0x0C + * length record. + * + * @access private + * @param array $col_array This is the only parameter received and is composed of the following: + * 0 => First formatted column, + * 1 => Last formatted column, + * 2 => Col width (8.43 is Excel default), + * 3 => The optional XF format of the column, + * 4 => Option flags. + * 5 => Optional outline level + */ + protected function _storeColinfo($col_array) + { + if (isset($col_array[0])) { + $colFirst = $col_array[0]; + } + if (isset($col_array[1])) { + $colLast = $col_array[1]; + } + if (isset($col_array[2])) { + $coldx = $col_array[2]; + } else { + $coldx = 8.43; + } + if (isset($col_array[3])) { + $format = $col_array[3]; + } else { + $format = 0; + } + if (isset($col_array[4])) { + $grbit = $col_array[4]; + } else { + $grbit = 0; + } + if (isset($col_array[5])) { + $level = $col_array[5]; + } else { + $level = 0; + } + $record = 0x007D; // Record identifier + $length = 0x000B; // Number of bytes to follow + + $coldx += 0.72; // Fudge. Excel subtracts 0.72 !? + $coldx *= 256; // Convert to units of 1/256 of a char + + $ixfe = $this->_XF($format); + $reserved = 0x00; // Reserved + + $level = max(0, min($level, 7)); + $grbit |= $level << 8; + + $header = pack("vv", $record, $length); + $data = pack("vvvvvC", $colFirst, $colLast, $coldx, + $ixfe, $grbit, $reserved); + $this->_prepend($header.$data); + } + + /** + * Write BIFF record SELECTION. + * + * @access private + * @param array $array array containing ($rwFirst,$colFirst,$rwLast,$colLast) + * @see setSelection() + */ + protected function _storeSelection($array) + { + list($rwFirst,$colFirst,$rwLast,$colLast) = $array; + $record = 0x001D; // Record identifier + $length = 0x000F; // Number of bytes to follow + + $pnn = $this->_active_pane; // Pane position + $rwAct = $rwFirst; // Active row + $colAct = $colFirst; // Active column + $irefAct = 0; // Active cell ref + $cref = 1; // Number of refs + + if (!isset($rwLast)) { + $rwLast = $rwFirst; // Last row in reference + } + if (!isset($colLast)) { + $colLast = $colFirst; // Last col in reference + } + + // Swap last row/col for first row/col as necessary + if ($rwFirst > $rwLast) { + list($rwFirst, $rwLast) = array($rwLast, $rwFirst); + } + + if ($colFirst > $colLast) { + list($colFirst, $colLast) = array($colLast, $colFirst); + } + + $header = pack("vv", $record, $length); + $data = pack("CvvvvvvCC", $pnn, $rwAct, $colAct, + $irefAct, $cref, + $rwFirst, $rwLast, + $colFirst, $colLast); + $this->_append($header . $data); + } + + /** + * Store the MERGEDCELLS record for all ranges of merged cells + * + * @access private + */ + protected function _storeMergedCells() + { + // if there are no merged cell ranges set, return + if (count($this->_merged_ranges) == 0) { + return; + } + $record = 0x00E5; + foreach($this->_merged_ranges as $ranges) + { + $length = 2 + count($ranges) * 8; + $header = pack('vv', $record, $length); + $data = pack('v', count($ranges)); + foreach ($ranges as $range) + $data .= pack('vvvv', $range[0], $range[2], $range[1], $range[3]); + $string = $header.$data; + $this->_append($string, true); + } + } + + /** + * Write BIFF record EXTERNCOUNT to indicate the number of external sheet + * references in a worksheet. + * + * Excel only stores references to external sheets that are used in formulas. + * For simplicity we store references to all the sheets in the workbook + * regardless of whether they are used or not. This reduces the overall + * complexity and eliminates the need for a two way dialogue between the formula + * parser the worksheet objects. + * + * @access private + * @param integer $count The number of external sheet references in this worksheet + */ + protected function _storeExterncount($count) + { + $record = 0x0016; // Record identifier + $length = 0x0002; // Number of bytes to follow + + $header = pack("vv", $record, $length); + $data = pack("v", $count); + $this->_prepend($header . $data); + } + + /** + * Writes the Excel BIFF EXTERNSHEET record. These references are used by + * formulas. A formula references a sheet name via an index. Since we store a + * reference to all of the external worksheets the EXTERNSHEET index is the same + * as the worksheet index. + * + * @access private + * @param string $sheetname The name of a external worksheet + */ + protected function _storeExternsheet($sheetname) + { + $record = 0x0017; // Record identifier + + // References to the current sheet are encoded differently to references to + // external sheets. + // + if ($this->name == $sheetname) { + $sheetname = ''; + $length = 0x02; // The following 2 bytes + $cch = 1; // The following byte + $rgch = 0x02; // Self reference + } else { + $length = 0x02 + strlen($sheetname); + $cch = strlen($sheetname); + $rgch = 0x03; // Reference to a sheet in the current workbook + } + + $header = pack("vv", $record, $length); + $data = pack("CC", $cch, $rgch); + $this->_prepend($header . $data . $sheetname); + } + + /** + * Writes the Excel BIFF PANE record. + * The panes can either be frozen or thawed (unfrozen). + * Frozen panes are specified in terms of an integer number of rows and columns. + * Thawed panes are specified in terms of Excel's units for rows and columns. + * + * @access private + * @param array $panes This is the only parameter received and is composed of the following: + * 0 => Vertical split position, + * 1 => Horizontal split position + * 2 => Top row visible + * 3 => Leftmost column visible + * 4 => Active pane + */ + protected function _storePanes($panes) + { + $y = $panes[0]; + $x = $panes[1]; + $rwTop = $panes[2]; + $colLeft = $panes[3]; + if (count($panes) > 4) { // if Active pane was received + $pnnAct = $panes[4]; + } else { + $pnnAct = null; + } + $record = 0x0041; // Record identifier + $length = 0x000A; // Number of bytes to follow + + // Code specific to frozen or thawed panes. + if ($this->_frozen) { + // Set default values for $rwTop and $colLeft + if (!isset($rwTop)) { + $rwTop = $y; + } + if (!isset($colLeft)) { + $colLeft = $x; + } + } else { + // Set default values for $rwTop and $colLeft + if (!isset($rwTop)) { + $rwTop = 0; + } + if (!isset($colLeft)) { + $colLeft = 0; + } + + // Convert Excel's row and column units to the internal units. + // The default row height is 12.75 + // The default column width is 8.43 + // The following slope and intersection values were interpolated. + // + $y = 20*$y + 255; + $x = 113.879*$x + 390; + } + + + // Determine which pane should be active. There is also the undocumented + // option to override this should it be necessary: may be removed later. + // + if (!isset($pnnAct)) { + if ($x != 0 && $y != 0) { + $pnnAct = 0; // Bottom right + } + if ($x != 0 && $y == 0) { + $pnnAct = 1; // Top right + } + if ($x == 0 && $y != 0) { + $pnnAct = 2; // Bottom left + } + if ($x == 0 && $y == 0) { + $pnnAct = 3; // Top left + } + } + + $this->_active_pane = $pnnAct; // Used in _storeSelection + + $header = pack("vv", $record, $length); + $data = pack("vvvvv", $x, $y, $rwTop, $colLeft, $pnnAct); + $this->_append($header . $data); + } + + /** + * Store the page setup SETUP BIFF record. + * + * @access private + */ + protected function _storeSetup() + { + $record = 0x00A1; // Record identifier + $length = 0x0022; // Number of bytes to follow + + $iPaperSize = $this->_paper_size; // Paper size + $iScale = $this->_print_scale; // Print scaling factor + $iPageStart = 0x01; // Starting page number + $iFitWidth = $this->_fit_width; // Fit to number of pages wide + $iFitHeight = $this->_fit_height; // Fit to number of pages high + $grbit = 0x00; // Option flags + $iRes = 0x0258; // Print resolution + $iVRes = 0x0258; // Vertical print resolution + $numHdr = $this->_margin_head; // Header Margin + $numFtr = $this->_margin_foot; // Footer Margin + $iCopies = 0x01; // Number of copies + + $fLeftToRight = 0x0; // Print over then down + $fLandscape = $this->_orientation; // Page orientation + $fNoPls = 0x0; // Setup not read from printer + $fNoColor = 0x0; // Print black and white + $fDraft = 0x0; // Print draft quality + $fNotes = 0x0; // Print notes + $fNoOrient = 0x0; // Orientation not set + $fUsePage = 0x0; // Use custom starting page + + $grbit = $fLeftToRight; + $grbit |= $fLandscape << 1; + $grbit |= $fNoPls << 2; + $grbit |= $fNoColor << 3; + $grbit |= $fDraft << 4; + $grbit |= $fNotes << 5; + $grbit |= $fNoOrient << 6; + $grbit |= $fUsePage << 7; + + $numHdr = pack("d", $numHdr); + $numFtr = pack("d", $numFtr); + if ($this->_byte_order) { // if it's Big Endian + $numHdr = strrev($numHdr); + $numFtr = strrev($numFtr); + } + + $header = pack("vv", $record, $length); + $data1 = pack("vvvvvvvv", $iPaperSize, + $iScale, + $iPageStart, + $iFitWidth, + $iFitHeight, + $grbit, + $iRes, + $iVRes); + $data2 = $numHdr.$numFtr; + $data3 = pack("v", $iCopies); + $this->_prepend($header . $data1 . $data2 . $data3); + } + + /** + * Store the header caption BIFF record. + * + * @access private + */ + protected function _storeHeader() + { + $record = 0x0014; // Record identifier + + $str = $this->_header; // header string + $cch = strlen($str); // Length of header string + if ($this->_BIFF_version == 0x0600) { + $encoding = 0x0; // TODO: Unicode support + $length = 3 + $cch; // Bytes to follow + } else { + $length = 1 + $cch; // Bytes to follow + } + + $header = pack("vv", $record, $length); + if ($this->_BIFF_version == 0x0600) { + $data = pack("vC", $cch, $encoding); + } else { + $data = pack("C", $cch); + } + + $this->_prepend($header.$data.$str); + } + + /** + * Store the footer caption BIFF record. + * + * @access private + */ + protected function _storeFooter() + { + $record = 0x0015; // Record identifier + + $str = $this->_footer; // Footer string + $cch = strlen($str); // Length of footer string + if ($this->_BIFF_version == 0x0600) { + $encoding = 0x0; // TODO: Unicode support + $length = 3 + $cch; // Bytes to follow + } else { + $length = 1 + $cch; + } + + $header = pack("vv", $record, $length); + if ($this->_BIFF_version == 0x0600) { + $data = pack("vC", $cch, $encoding); + } else { + $data = pack("C", $cch); + } + + $this->_prepend($header . $data . $str); + } + + /** + * Store the horizontal centering HCENTER BIFF record. + * + * @access private + */ + protected function _storeHcenter() + { + $record = 0x0083; // Record identifier + $length = 0x0002; // Bytes to follow + + $fHCenter = $this->_hcenter; // Horizontal centering + + $header = pack("vv", $record, $length); + $data = pack("v", $fHCenter); + + $this->_prepend($header.$data); + } + + /** + * Store the vertical centering VCENTER BIFF record. + * + * @access private + */ + protected function _storeVcenter() + { + $record = 0x0084; // Record identifier + $length = 0x0002; // Bytes to follow + + $fVCenter = $this->_vcenter; // Horizontal centering + + $header = pack("vv", $record, $length); + $data = pack("v", $fVCenter); + $this->_prepend($header . $data); + } + + /** + * Store the LEFTMARGIN BIFF record. + * + * @access private + */ + protected function _storeMarginLeft() + { + $record = 0x0026; // Record identifier + $length = 0x0008; // Bytes to follow + + $margin = $this->_margin_left; // Margin in inches + + $header = pack("vv", $record, $length); + $data = pack("d", $margin); + if ($this->_byte_order) { // if it's Big Endian + $data = strrev($data); + } + + $this->_prepend($header . $data); + } + + /** + * Store the RIGHTMARGIN BIFF record. + * + * @access private + */ + protected function _storeMarginRight() + { + $record = 0x0027; // Record identifier + $length = 0x0008; // Bytes to follow + + $margin = $this->_margin_right; // Margin in inches + + $header = pack("vv", $record, $length); + $data = pack("d", $margin); + if ($this->_byte_order) { // if it's Big Endian + $data = strrev($data); + } + + $this->_prepend($header . $data); + } + + /** + * Store the TOPMARGIN BIFF record. + * + * @access private + */ + protected function _storeMarginTop() + { + $record = 0x0028; // Record identifier + $length = 0x0008; // Bytes to follow + + $margin = $this->_margin_top; // Margin in inches + + $header = pack("vv", $record, $length); + $data = pack("d", $margin); + if ($this->_byte_order) { // if it's Big Endian + $data = strrev($data); + } + + $this->_prepend($header . $data); + } + + /** + * Store the BOTTOMMARGIN BIFF record. + * + * @access private + */ + protected function _storeMarginBottom() + { + $record = 0x0029; // Record identifier + $length = 0x0008; // Bytes to follow + + $margin = $this->_margin_bottom; // Margin in inches + + $header = pack("vv", $record, $length); + $data = pack("d", $margin); + if ($this->_byte_order) { // if it's Big Endian + $data = strrev($data); + } + + $this->_prepend($header . $data); + } + + /** + * Merges the area given by its arguments. + * This is an Excel97/2000 method. It is required to perform more complicated + * merging than the normal setAlign('merge'). + * + * @access public + * @param integer $first_row First row of the area to merge + * @param integer $first_col First column of the area to merge + * @param integer $last_row Last row of the area to merge + * @param integer $last_col Last column of the area to merge + */ + public function mergeCells($first_row, $first_col, $last_row, $last_col) + { + $record = 0x00E5; // Record identifier + $length = 0x000A; // Bytes to follow + $cref = 1; // Number of refs + + // Swap last row/col for first row/col as necessary + if ($first_row > $last_row) { + list($first_row, $last_row) = array($last_row, $first_row); + } + + if ($first_col > $last_col) { + list($first_col, $last_col) = array($last_col, $first_col); + } + + $header = pack("vv", $record, $length); + $data = pack("vvvvv", $cref, $first_row, $last_row, + $first_col, $last_col); + + $this->_append($header.$data); + } + + /** + * Write the PRINTHEADERS BIFF record. + * + * @access private + */ + protected function _storePrintHeaders() + { + $record = 0x002a; // Record identifier + $length = 0x0002; // Bytes to follow + + $fPrintRwCol = $this->_print_headers; // Boolean flag + + $header = pack("vv", $record, $length); + $data = pack("v", $fPrintRwCol); + $this->_prepend($header . $data); + } + + /** + * Write the PRINTGRIDLINES BIFF record. Must be used in conjunction with the + * GRIDSET record. + * + * @access private + */ + protected function _storePrintGridlines() + { + $record = 0x002b; // Record identifier + $length = 0x0002; // Bytes to follow + + $fPrintGrid = $this->_print_gridlines; // Boolean flag + + $header = pack("vv", $record, $length); + $data = pack("v", $fPrintGrid); + $this->_prepend($header . $data); + } + + /** + * Write the GRIDSET BIFF record. Must be used in conjunction with the + * PRINTGRIDLINES record. + * + * @access private + */ + protected function _storeGridset() + { + $record = 0x0082; // Record identifier + $length = 0x0002; // Bytes to follow + + $fGridSet = !($this->_print_gridlines); // Boolean flag + + $header = pack("vv", $record, $length); + $data = pack("v", $fGridSet); + $this->_prepend($header . $data); + } + + /** + * Write the GUTS BIFF record. This is used to configure the gutter margins + * where Excel outline symbols are displayed. The visibility of the gutters is + * controlled by a flag in WSBOOL. + * + * @see _storeWsbool() + * @access private + */ + protected function _storeGuts() + { + $record = 0x0080; // Record identifier + $length = 0x0008; // Bytes to follow + + $dxRwGut = 0x0000; // Size of row gutter + $dxColGut = 0x0000; // Size of col gutter + + $row_level = $this->_outline_row_level; + $col_level = 0; + + // Calculate the maximum column outline level. The equivalent calculation + // for the row outline level is carried out in setRow(). + $colcount = count($this->_colinfo); + for ($i = 0; $i < $colcount; $i++) { + // Skip cols without outline level info. + if (count($this->_colinfo[$i]) >= 6) { + $col_level = max($this->_colinfo[$i][5], $col_level); + } + } + + // Set the limits for the outline levels (0 <= x <= 7). + $col_level = max(0, min($col_level, 7)); + + // The displayed level is one greater than the max outline levels + if ($row_level) { + $row_level++; + } + if ($col_level) { + $col_level++; + } + + $header = pack("vv", $record, $length); + $data = pack("vvvv", $dxRwGut, $dxColGut, $row_level, $col_level); + + $this->_prepend($header.$data); + } + + + /** + * Write the WSBOOL BIFF record, mainly for fit-to-page. Used in conjunction + * with the SETUP record. + * + * @access private + */ + protected function _storeWsbool() + { + $record = 0x0081; // Record identifier + $length = 0x0002; // Bytes to follow + $grbit = 0x0000; + + // The only option that is of interest is the flag for fit to page. So we + // set all the options in one go. + // + /*if ($this->_fit_page) { + $grbit = 0x05c1; + } else { + $grbit = 0x04c1; + }*/ + // Set the option flags + $grbit |= 0x0001; // Auto page breaks visible + if ($this->_outline_style) { + $grbit |= 0x0020; // Auto outline styles + } + if ($this->_outline_below) { + $grbit |= 0x0040; // Outline summary below + } + if ($this->_outline_right) { + $grbit |= 0x0080; // Outline summary right + } + if ($this->_fit_page) { + $grbit |= 0x0100; // Page setup fit to page + } + if ($this->_outline_on) { + $grbit |= 0x0400; // Outline symbols displayed + } + + $header = pack("vv", $record, $length); + $data = pack("v", $grbit); + $this->_prepend($header . $data); + } + + /** + * Write the HORIZONTALPAGEBREAKS BIFF record. + * + * @access private + */ + protected function _storeHbreak() + { + // Return if the user hasn't specified pagebreaks + if (empty($this->_hbreaks)) { + return; + } + + // Sort and filter array of page breaks + $breaks = $this->_hbreaks; + sort($breaks, SORT_NUMERIC); + if ($breaks[0] == 0) { // don't use first break if it's 0 + array_shift($breaks); + } + + $record = 0x001b; // Record identifier + $cbrk = count($breaks); // Number of page breaks + if ($this->_BIFF_version == 0x0600) { + $length = 2 + 6*$cbrk; // Bytes to follow + } else { + $length = 2 + 2*$cbrk; // Bytes to follow + } + + $header = pack("vv", $record, $length); + $data = pack("v", $cbrk); + + // Append each page break + foreach ($breaks as $break) { + if ($this->_BIFF_version == 0x0600) { + $data .= pack("vvv", $break, 0x0000, 0x00ff); + } else { + $data .= pack("v", $break); + } + } + + $this->_prepend($header.$data); + } + + + /** + * Write the VERTICALPAGEBREAKS BIFF record. + * + * @access private + */ + protected function _storeVbreak() + { + // Return if the user hasn't specified pagebreaks + if (empty($this->_vbreaks)) { + return; + } + + // 1000 vertical pagebreaks appears to be an internal Excel 5 limit. + // It is slightly higher in Excel 97/200, approx. 1026 + $breaks = array_slice($this->_vbreaks,0,1000); + + // Sort and filter array of page breaks + sort($breaks, SORT_NUMERIC); + if ($breaks[0] == 0) { // don't use first break if it's 0 + array_shift($breaks); + } + + $record = 0x001a; // Record identifier + $cbrk = count($breaks); // Number of page breaks + if ($this->_BIFF_version == 0x0600) { + $length = 2 + 6*$cbrk; // Bytes to follow + } else { + $length = 2 + 2*$cbrk; // Bytes to follow + } + + $header = pack("vv", $record, $length); + $data = pack("v", $cbrk); + + // Append each page break + foreach ($breaks as $break) { + if ($this->_BIFF_version == 0x0600) { + $data .= pack("vvv", $break, 0x0000, 0xffff); + } else { + $data .= pack("v", $break); + } + } + + $this->_prepend($header . $data); + } + + /** + * Set the Biff PROTECT record to indicate that the worksheet is protected. + * + * @access private + */ + protected function _storeProtect() + { + // Exit unless sheet protection has been specified + if ($this->_protect == 0) { + return; + } + + $record = 0x0012; // Record identifier + $length = 0x0002; // Bytes to follow + + $fLock = $this->_protect; // Worksheet is protected + + $header = pack("vv", $record, $length); + $data = pack("v", $fLock); + + $this->_prepend($header.$data); + } + + /** + * Write the worksheet PASSWORD record. + * + * @access private + */ + protected function _storePassword() + { + // Exit unless sheet protection and password have been specified + if (($this->_protect == 0) || (!isset($this->_password))) { + return; + } + + $record = 0x0013; // Record identifier + $length = 0x0002; // Bytes to follow + + $wPassword = $this->_password; // Encoded password + + $header = pack("vv", $record, $length); + $data = pack("v", $wPassword); + + $this->_prepend($header . $data); + } + + + /** + * Insert a 24bit bitmap image in a worksheet. + * + * @access public + * @param integer $row The row we are going to insert the bitmap into + * @param integer $col The column we are going to insert the bitmap into + * @param string $bitmap The bitmap filename + * @param integer $x The horizontal position (offset) of the image inside the cell. + * @param integer $y The vertical position (offset) of the image inside the cell. + * @param integer $scale_x The horizontal scale + * @param integer $scale_y The vertical scale + */ + public function insertBitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1) + { + $bitmap_array = $this->_processBitmap($bitmap); + if ($this->isError($bitmap_array)) { + $this->writeString($row, $col, $bitmap_array->getMessage()); + return; + } + list($width, $height, $size, $data) = $bitmap_array; //$this->_processBitmap($bitmap); + + // Scale the frame of the image. + $width *= $scale_x; + $height *= $scale_y; + + // Calculate the vertices of the image and write the OBJ record + $this->_positionImage($col, $row, $x, $y, $width, $height); + + // Write the IMDATA record to store the bitmap data + $record = 0x007f; + $length = 8 + $size; + $cf = 0x09; + $env = 0x01; + $lcb = $size; + + $header = pack("vvvvV", $record, $length, $cf, $env, $lcb); + $this->_append($header.$data); + } + + /** + * Calculate the vertices that define the position of the image as required by + * the OBJ record. + * + * +------------+------------+ + * | A | B | + * +-----+------------+------------+ + * | |(x1,y1) | | + * | 1 |(A1)._______|______ | + * | | | | | + * | | | | | + * +-----+----| BITMAP |-----+ + * | | | | | + * | 2 | |______________. | + * | | | (B2)| + * | | | (x2,y2)| + * +---- +------------+------------+ + * + * Example of a bitmap that covers some of the area from cell A1 to cell B2. + * + * Based on the width and height of the bitmap we need to calculate 8 vars: + * $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2. + * The width and height of the cells are also variable and have to be taken into + * account. + * The values of $col_start and $row_start are passed in from the calling + * public function. The values of $col_end and $row_end are calculated by subtracting + * the width and height of the bitmap from the width and height of the + * underlying cells. + * The vertices are expressed as a percentage of the underlying cell width as + * follows (rhs values are in pixels): + * + * x1 = X / W *1024 + * y1 = Y / H *256 + * x2 = (X-1) / W *1024 + * y2 = (Y-1) / H *256 + * + * Where: X is distance from the left side of the underlying cell + * Y is distance from the top of the underlying cell + * W is the width of the cell + * H is the height of the cell + * + * @access private + * @note the SDK incorrectly states that the height should be expressed as a + * percentage of 1024. + * @param integer $col_start Col containing upper left corner of object + * @param integer $row_start Row containing top left corner of object + * @param integer $x1 Distance to left side of object + * @param integer $y1 Distance to top of object + * @param integer $width Width of image frame + * @param integer $height Height of image frame + */ + protected function _positionImage($col_start, $row_start, $x1, $y1, $width, $height) + { + // Initialise end cell to the same as the start cell + $col_end = $col_start; // Col containing lower right corner of object + $row_end = $row_start; // Row containing bottom right corner of object + + // Zero the specified offset if greater than the cell dimensions + if ($x1 >= $this->_sizeCol($col_start)) { + $x1 = 0; + } + if ($y1 >= $this->_sizeRow($row_start)) { + $y1 = 0; + } + + $width = $width + $x1 -1; + $height = $height + $y1 -1; + + // Subtract the underlying cell widths to find the end cell of the image + while ($width >= $this->_sizeCol($col_end)) { + $width -= $this->_sizeCol($col_end); + $col_end++; + } + + // Subtract the underlying cell heights to find the end cell of the image + while ($height >= $this->_sizeRow($row_end)) { + $height -= $this->_sizeRow($row_end); + $row_end++; + } + + // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell + // with zero eight or width. + // + if ($this->_sizeCol($col_start) == 0) { + return; + } + if ($this->_sizeCol($col_end) == 0) { + return; + } + if ($this->_sizeRow($row_start) == 0) { + return; + } + if ($this->_sizeRow($row_end) == 0) { + return; + } + + // Convert the pixel values to the percentage value expected by Excel + $x1 = $x1 / $this->_sizeCol($col_start) * 1024; + $y1 = $y1 / $this->_sizeRow($row_start) * 256; + $x2 = $width / $this->_sizeCol($col_end) * 1024; // Distance to right side of object + $y2 = $height / $this->_sizeRow($row_end) * 256; // Distance to bottom of object + + $this->_storeObjPicture($col_start, $x1, + $row_start, $y1, + $col_end, $x2, + $row_end, $y2); + } + + /** + * Convert the width of a cell from user's units to pixels. By interpolation + * the relationship is: y = 7x +5. If the width hasn't been set by the user we + * use the default value. If the col is hidden we use a value of zero. + * + * @access private + * @param integer $col The column + * @return integer The width in pixels + */ + protected function _sizeCol($col) + { + // Look up the cell value to see if it has been changed + if (isset($this->col_sizes[$col])) { + if ($this->col_sizes[$col] == 0) { + return(0); + } else { + return(floor(7 * $this->col_sizes[$col] + 5)); + } + } else { + return(64); + } + } + + /** + * Convert the height of a cell from user's units to pixels. By interpolation + * the relationship is: y = 4/3x. If the height hasn't been set by the user we + * use the default value. If the row is hidden we use a value of zero. (Not + * possible to hide row yet). + * + * @access private + * @param integer $row The row + * @return integer The width in pixels + */ + protected function _sizeRow($row) + { + // Look up the cell value to see if it has been changed + if (isset($this->_row_sizes[$row])) { + if ($this->_row_sizes[$row] == 0) { + return(0); + } else { + return(floor(4/3 * $this->_row_sizes[$row])); + } + } else { + return(17); + } + } + + /** + * Store the OBJ record that precedes an IMDATA record. This could be generalise + * to support other Excel objects. + * + * @access private + * @param integer $colL Column containing upper left corner of object + * @param integer $dxL Distance from left side of cell + * @param integer $rwT Row containing top left corner of object + * @param integer $dyT Distance from top of cell + * @param integer $colR Column containing lower right corner of object + * @param integer $dxR Distance from right of cell + * @param integer $rwB Row containing bottom right corner of object + * @param integer $dyB Distance from bottom of cell + */ + protected function _storeObjPicture($colL,$dxL,$rwT,$dyT,$colR,$dxR,$rwB,$dyB) + { + $record = 0x005d; // Record identifier + $length = 0x003c; // Bytes to follow + + $cObj = 0x0001; // Count of objects in file (set to 1) + $OT = 0x0008; // Object type. 8 = Picture + $id = 0x0001; // Object ID + $grbit = 0x0614; // Option flags + + $cbMacro = 0x0000; // Length of FMLA structure + $Reserved1 = 0x0000; // Reserved + $Reserved2 = 0x0000; // Reserved + + $icvBack = 0x09; // Background colour + $icvFore = 0x09; // Foreground colour + $fls = 0x00; // Fill pattern + $fAuto = 0x00; // Automatic fill + $icv = 0x08; // Line colour + $lns = 0xff; // Line style + $lnw = 0x01; // Line weight + $fAutoB = 0x00; // Automatic border + $frs = 0x0000; // Frame style + $cf = 0x0009; // Image format, 9 = bitmap + $Reserved3 = 0x0000; // Reserved + $cbPictFmla = 0x0000; // Length of FMLA structure + $Reserved4 = 0x0000; // Reserved + $grbit2 = 0x0001; // Option flags + $Reserved5 = 0x0000; // Reserved + + + $header = pack("vv", $record, $length); + $data = pack("V", $cObj); + $data .= pack("v", $OT); + $data .= pack("v", $id); + $data .= pack("v", $grbit); + $data .= pack("v", $colL); + $data .= pack("v", $dxL); + $data .= pack("v", $rwT); + $data .= pack("v", $dyT); + $data .= pack("v", $colR); + $data .= pack("v", $dxR); + $data .= pack("v", $rwB); + $data .= pack("v", $dyB); + $data .= pack("v", $cbMacro); + $data .= pack("V", $Reserved1); + $data .= pack("v", $Reserved2); + $data .= pack("C", $icvBack); + $data .= pack("C", $icvFore); + $data .= pack("C", $fls); + $data .= pack("C", $fAuto); + $data .= pack("C", $icv); + $data .= pack("C", $lns); + $data .= pack("C", $lnw); + $data .= pack("C", $fAutoB); + $data .= pack("v", $frs); + $data .= pack("V", $cf); + $data .= pack("v", $Reserved3); + $data .= pack("v", $cbPictFmla); + $data .= pack("v", $Reserved4); + $data .= pack("v", $grbit2); + $data .= pack("V", $Reserved5); + + $this->_append($header . $data); + } + + /** + * Convert a 24 bit bitmap into the modified internal format used by Windows. + * This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the + * MSDN library. + * + * @access private + * @param string $bitmap The bitmap to process + * @return array Array with data and properties of the bitmap + */ + protected function _processBitmap($bitmap) + { + // Open file. + $bmp_fd = @fopen($bitmap,"rb"); + if (!$bmp_fd) { + $this->raiseError("Couldn't import $bitmap"); + } + + // Slurp the file into a string. + $data = fread($bmp_fd, filesize($bitmap)); + + // Check that the file is big enough to be a bitmap. + if (strlen($data) <= 0x36) { + $this->raiseError("$bitmap doesn't contain enough data.\n"); + } + + // The first 2 bytes are used to identify the bitmap. + $identity = unpack("A2ident", $data); + if ($identity['ident'] != "BM") { + $this->raiseError("$bitmap doesn't appear to be a valid bitmap image.\n"); + } + + // Remove bitmap data: ID. + $data = substr($data, 2); + + // Read and remove the bitmap size. This is more reliable than reading + // the data size at offset 0x22. + // + $size_array = unpack("Vsa", substr($data, 0, 4)); + $size = $size_array['sa']; + $data = substr($data, 4); + $size -= 0x36; // Subtract size of bitmap header. + $size += 0x0C; // Add size of BIFF header. + + // Remove bitmap data: reserved, offset, header length. + $data = substr($data, 12); + + // Read and remove the bitmap width and height. Verify the sizes. + $width_and_height = unpack("V2", substr($data, 0, 8)); + $width = $width_and_height[1]; + $height = $width_and_height[2]; + $data = substr($data, 8); + if ($width > 0xFFFF) { + $this->raiseError("$bitmap: largest image width supported is 65k.\n"); + } + if ($height > 0xFFFF) { + $this->raiseError("$bitmap: largest image height supported is 65k.\n"); + } + + // Read and remove the bitmap planes and bpp data. Verify them. + $planes_and_bitcount = unpack("v2", substr($data, 0, 4)); + $data = substr($data, 4); + if ($planes_and_bitcount[2] != 24) { // Bitcount + $this->raiseError("$bitmap isn't a 24bit true color bitmap.\n"); + } + if ($planes_and_bitcount[1] != 1) { + $this->raiseError("$bitmap: only 1 plane supported in bitmap image.\n"); + } + + // Read and remove the bitmap compression. Verify compression. + $compression = unpack("Vcomp", substr($data, 0, 4)); + $data = substr($data, 4); + + //$compression = 0; + if ($compression['comp'] != 0) { + $this->raiseError("$bitmap: compression not supported in bitmap image.\n"); + } + + // Remove bitmap data: data size, hres, vres, colours, imp. colours. + $data = substr($data, 20); + + // Add the BITMAPCOREHEADER data + $header = pack("Vvvvv", 0x000c, $width, $height, 0x01, 0x18); + $data = $header . $data; + + return (array($width, $height, $size, $data)); + } + + /** + * Store the window zoom factor. This should be a reduced fraction but for + * simplicity we will store all fractions with a numerator of 100. + * + * @access private + */ + protected function _storeZoom() + { + // If scale is 100 we don't need to write a record + if ($this->_zoom == 100) { + return; + } + + $record = 0x00A0; // Record identifier + $length = 0x0004; // Bytes to follow + + $header = pack("vv", $record, $length); + $data = pack("vv", $this->_zoom, 100); + $this->_append($header . $data); + } + + /** + * FIXME: add comments + */ + public function setValidation($row1, $col1, $row2, $col2, $validator) + { + $this->_dv[] = $validator->_getData() . + pack("vvvvv", 1, $row1, $row2, $col1, $col2); + } + + /** + * Store the DVAL and DV records. + * + * @access private + */ + protected function _storeDataValidity() + { + $record = 0x01b2; // Record identifier + $length = 0x0012; // Bytes to follow + + $grbit = 0x0002; // Prompt box at cell, no cached validity data at DV records + $horPos = 0x00000000; // Horizontal position of prompt box, if fixed position + $verPos = 0x00000000; // Vertical position of prompt box, if fixed position + $objId = 0xffffffff; // Object identifier of drop down arrow object, or -1 if not visible + + $header = pack('vv', $record, $length); + $data = pack('vVVVV', $grbit, $horPos, $verPos, $objId, + count($this->_dv)); + $this->_append($header.$data); + + $record = 0x01be; // Record identifier + foreach ($this->_dv as $dv) { + $length = strlen($dv); // Bytes to follow + $header = pack("vv", $record, $length); + $this->_append($header . $dv); + } + } +} \ No newline at end of file diff --git a/vendor/pear/spreadsheet_excel_writer/composer.json b/vendor/pear/spreadsheet_excel_writer/composer.json new file mode 100644 index 00000000..29f3f173 --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/composer.json @@ -0,0 +1,63 @@ +{ + "name": "pear/spreadsheet_excel_writer", + "type": "library", + "description": "Allows writing of Excel spreadsheets without the need for COM objects. Supports formulas, images (BMP) and all kinds of formatting for text and cells.", + "license": "LGPL-2.1-or-later", + "authors": [ + { + "name": "Carsten Schmitz", + "email": "cschmitz@limesurvey.org", + "role": "Lead" + }, + { + "name": "Xavier Noguer", + "email": "xnoguer@php.net", + "role": "Lead" + }, + { + "name": "Franck Lefevre", + "email": "progi1984@gmail.com", + "role": "Developer" + }, + { + "name": "Mika Tuupola", + "email": "tuupola@appelsiini.net", + "role": "Developer" + }, + { + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com", + "role": "Lead" + } + ], + "require": { + "php": ">=5.6", + "pear/ole": ">=1.0.0RC4", + "pear/pear-core-minimal": "^1.10" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2", + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": ">=5 <10", + "sanmai/phpunit-legacy-adapter": "^6 || ^8" + }, + "autoload": { + "psr-0": { + "Spreadsheet": "" + } + }, + "autoload-dev": { + "psr-0": { + "Test": "test" + } + }, + "minimum-stability": "dev", + "prefer-stable": true, + "include-path": [ + "./" + ], + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=Spreadsheet_Excel_Writer", + "source": "https://github.com/pear/Spreadsheet_Excel_Writer" + } +} diff --git a/vendor/pear/spreadsheet_excel_writer/package.xml b/vendor/pear/spreadsheet_excel_writer/package.xml new file mode 100644 index 00000000..387a4f6e --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/package.xml @@ -0,0 +1,357 @@ + + + Spreadsheet_Excel_Writer + pear.php.net + Package for generating Excel spreadsheets + Spreadsheet_Excel_Writer was born as a porting of the Spreadsheet::WriteExcel Perl module to PHP. + It allows writing of Excel spreadsheets without the need for COM objects. + It supports formulas, images (BMP) and all kinds of formatting for text and cells. + It currently supports the BIFF5 format (Excel 5.0), so functionality appeared in the latest Excel versions is not yet available. + + Carsten Schmitz + cschmitz + cschmitz@limesurvey.org + yes + + + Xavier Noguer + xnoguer + xnoguer@php.net + no + + + Alexey Kopytko + sanmai + alexey@kopytko.com + yes + + + Franck Lefevre + progi1984 + progi1984@gmail.com + yes + + + Mika Tuupola + tuupola + tuupola@appelsiini.net + no + + 2017-05-24 + + + 0.9.4 + 0.9.4 + + + beta + beta + + LGPL + +QA release. Comes with support for newer PHP versions. Fixed irritating "pass by reference" errors. + + + + + + + + + + + + + + + + + + + + + + 5.3.3 + + + 1.4.0b1 + + + OLE + pear.php.net + 1.0.0RC2 + + + + + + + + 0.9.3 + 0.9.3 + + + beta + beta + + 2012-01-26 + LGPL + +QA release +Bug #18590 Impossible to work from IIS7 +Bug #18024 deprecated line 180, 186 with php 5.3.2 +Bug #16025 MERGEDCELLS record split by CONTINUE record +Bug #17766 Patch: Avoid deprecated split +Bug #17572 Temporary files are not removed +Bug #16938 open_basedir check is wrong in Spreadsheet_Excel_Writer_Worksheet::_initialize +Bug #14585 open_basedir workaround doesn't work +Bug #12362 named worksheets & utf-8 +Bug #14515 writeUrl only uses writeString, never writeNumber +Bug #14281 Using a row > 16,384 reports error +Request #13486 Set the worksheet direction to right-to-left (RTL) +Bug #12720 Notice thrown when using setColumn (undefined colFirst and colLast) +Bug #12053 With SetVersion(8) setting bottom border color to 0 gives cross borders (!) + + + + + 0.2 + 0.2 + + + beta + beta + + 2003-03-17 + LGPL + +-added several formatting methods: setTextRotation(), setStrikeOut(), +setOutLine(), setShadow(), setScript(). +-fixed bug in Workbook::sheets() (Bjoern Schotte). +-fixed range for references in formulas (Edward). +-added support for external references in formulas. +-added support for comparisons in formulas. +-added support for strings in formulas. + + + + + 0.3 + 0.3 + + + stable + stable + + 2003-05-02 + LGPL + +New features: + -added support for row ranges (JT Hughes) + -added method method Format::setUnLocked() (Ajit Dixit) + -added Worksheet::writeRow() and Worksheet::writeCol() +Bug fixes: + -fixed problem with unparenthesized expresions in formulas (Brent Laminack) + -fixed problems with non ISO-8859-1 characters (KUBO Atsuhiro) + -fixed swapping of columns in formulas (JT Hughes) + -fixed assorted bugs in tokenizing formulas (JT Hughes) + -fixed Worksheet::activate() (JT Hughes) + + + + + 0.4 + 0.4 + + + stable + stable + + 2003-08-21 + LGPL + +New features: + -using OLE package (>= 0.3) to generate files bigger than 7MB + -changed setFgColor() and setBgColor()'s behavior to something more intuitive. +Bug fixes: + -fixed bug #25133, lowercase cell references (jkwiat03 at hotmail dot com) + -fixed Bug #23730, worksheet names containing spaces in formulas (Robin Ericsson) + -fixed Bug #24147, formulas ended in '0' (paul at classical dot com) + -fixed swapping of arguments in variable arguments functions (JT Hughes) + + + + + 0.5 + 0.5 + + + stable + stable + + 2003-10-01 + LGPL + +New features: + -added rowcolToCell() utility method for easy writing of formula's cell references (JT Hughes). + -added Worksheet::setOutline() method (Herman Kuiper) + -added Format::setFontFamily() method (Donnie Miller) +Bug fixes: + -fixed bug #21, cyrillic characters in sheet references (arhip at goldentele dot com) + + + + + 0.6 + 0.6 + + + stable + stable + + 2003-11-15 + LGPL + +New features: + - allow semicolon as argument separator (Axel Pratzner) + - added experimental Excel97 generation. You can test it with setVersion(): + Beware! this method will be deprecated in a future release (when + Excel97 becomes the default). It is only available for testing + purposes. Use it at your own risk. + - strings longer than 255 bytes are now available using the experimental + Excel97 generation. But not all Excel97 features are available yet! +Bug fixes: + - Fixed bug #225, error in writeUrl() (jamesn at tocquigny dot com) + - Fixed bug #59, retval undefined for writeRow() (Bertrand) + + + + + 0.7 + 0.7 + + + stable + stable + + 2004-02-27 + LGPL + +New features: + - allow setting temp dir other than default using setTempDir() (using OLE 5.0 for this). + - added setMerge() for merging (only for experimental Excel97 generation) + - added setCountry() method. + - added setLocked() method. +Bug fixes: + - Fixed bug #415, typo in BIFF8 code (papercrane at reversefold dot com) + + + + + 0.8 + 0.8 + + + stable + stable + + 2004-06-22 + LGPL + +New features: + - added hideScreenGridlines() (Paul Osman) +Bug fixes: + - Fixed SST table (long strings) (Bernd Jaenichen) + - Fixed bug #1218, SST table (boucher dot stephane at free dot fr) + - Fixed bug #781, insertBitmap ignores row height + - Fixed bug #578, setVPageBreaks doesn't handle multiple value arrays (natel at tocquigny dot com) + + + + + 0.9.0 + 0.9.0 + + + stable + stable + + 2005-11-21 + LGPL + +New features: +- adding new methods Format::setVAlign() and Format::setHAlign() +- adding support for uncapitalized functions in formulas (ej: "=sum(B27:B31)") +- adding support for different charsets with method Worksheet::setInputEncoding() +- adding support for sheetnames longer than 31 chars when using setVersion(8). +Bug fixes: +- Fixed Bug #1796, wrong regular expression in _writeUrlInternal +- Fixed Bug #2363, wrong export filename with spaces +- Fixed Bug #2425, Error using writeFormula with Now() and TODAY() +- Fixed Bug #2876, German Umlauts destroy sheet references +- Fixed Bug #1706, Formulas refer to other Worksheets with "spezial" names don't work +- Fixed Bug #2748, setMargins(), setHeader() and setFooter() work in excel but not in openoffice. +- Fixed Bug #5698, preg_replace in _writeUrlInternal +- Fixed Bug #2823, Inpropper results from writeUrl() method + + + + + 0.9.1 + 0.9.1 + + + stable + stable + + 2006-09-26 + LGPL + + + + + + + 0.9.2 + 0.9.2 + + + beta + stable + + 2009-11-28 + LGPL + + + + + + + 0.9.3 + 0.9.3 + + + beta + beta + + 2012-01-26 + LGPL + +QA release +Bug #18590 Impossible to work from IIS7 +Bug #18024 deprecated line 180, 186 with php 5.3.2 +Bug #16025 MERGEDCELLS record split by CONTINUE record +Bug #17766 Patch: Avoid deprecated split +Bug #17572 Temporary files are not removed +Bug #16938 open_basedir check is wrong in Spreadsheet_Excel_Writer_Worksheet::_initialize +Bug #14585 open_basedir workaround doesn't work +Bug #12362 named worksheets & utf-8 +Bug #14515 writeUrl only uses writeString, never writeNumber +Bug #14281 Using a row > 16,384 reports error +Request #13486 Set the worksheet direction to right-to-left (RTL) +Bug #12720 Notice thrown when using setColumn (undefined colFirst and colLast) +Bug #12053 With SetVersion(8) setting bottom border color to 0 gives cross borders (!) + + + + diff --git a/vendor/pear/spreadsheet_excel_writer/phpunit.xml.dist b/vendor/pear/spreadsheet_excel_writer/phpunit.xml.dist new file mode 100644 index 00000000..5c26d153 --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/phpunit.xml.dist @@ -0,0 +1,28 @@ + + + + + test/ + + + + + + Spreadsheet/ + + + + + + + + diff --git a/vendor/pear/spreadsheet_excel_writer/test/Test/Spreadsheet/Excel/Writer/WorkbookTest.php b/vendor/pear/spreadsheet_excel_writer/test/Test/Spreadsheet/Excel/Writer/WorkbookTest.php new file mode 100644 index 00000000..d15590ad --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/test/Test/Spreadsheet/Excel/Writer/WorkbookTest.php @@ -0,0 +1,81 @@ + + * @since 2016-01-17 + */ +class Test_Spreadsheet_Excel_Writer_WorkbookTest extends Test_Spreadsheet_Excel_WriterTestCase +{ + public static function doSetUpBeforeClass() + { + // Preload constants from OLE + @class_exists(OLE::class); + } + + public function testSetVersion() + { + $workbook = $this->getNewWorkbook(); + + $before = get_object_vars($workbook); + + $workbook->setVersion(1); + + $this->assertEquals($before, get_object_vars($workbook), "Version 1 should not change internal state"); + + $workbook->setVersion(8); + + $this->assertNotEquals($before, get_object_vars($workbook), "Version 8 should change internal state"); + + return $workbook; + } + + /** + * @depends testSetVersion + */ + public function testWriteSingleCell(Spreadsheet_Excel_Writer $workbook) + { + $sheet = $workbook->addWorksheet("Example"); + $sheet->write(0, 0, "Example"); + + $this->assertSameAsInFixture('example.xls', $workbook); + } + + public function testWriteWithFormat() + { + $workbook = $this->getNewWorkbook(); + $workbook->setVersion(8); + + $format = $workbook->addFormat(); + $format->setFontFamily('Helvetica'); + $format->setSize(16); + $format->setVAlign('vcenter'); + $format->setBorder(1); + + $sheet = $workbook->addWorksheet('Example report'); + $sheet->setInputEncoding('utf-8'); + + $sheet->setColumn(0, 10, 35); + + $sheet->writeString(0, 0, "Test string", $format); + $sheet->setRow(0, 40); + + $sheet->writeString(1, 0, "ใ“ใ‚“ใซใกใ‚"); + + $this->assertSameAsInFixture('with_format.xls', $workbook); + } + + public function testWithDefaultVersion() + { + $workbook = $this->getNewWorkbook(); + + $sheet = $workbook->addWorksheet("Example"); + + for ($i = 0; $i < 10; $i++) { + for ($j = 0; $j < 10; $j++) { + $sheet->write($i, $j, "Row $i $j"); + } + } + + $this->assertSameAsInFixture('example2.xls', $workbook); + } +} diff --git a/vendor/pear/spreadsheet_excel_writer/test/Test/Spreadsheet/Excel/WriterTestCase.php b/vendor/pear/spreadsheet_excel_writer/test/Test/Spreadsheet/Excel/WriterTestCase.php new file mode 100644 index 00000000..1e57b821 --- /dev/null +++ b/vendor/pear/spreadsheet_excel_writer/test/Test/Spreadsheet/Excel/WriterTestCase.php @@ -0,0 +1,55 @@ + + * @since 2016-01-17 + */ +class Test_Spreadsheet_Excel_WriterTestCase extends \LegacyPHPUnit\TestCase +{ + const FIXTURES_PATH = 'test/fixture/'; + + /** + * @param string $filename + * @return Spreadsheet_Excel_Writer + */ + protected function getNewWorkbook($filename = '') + { + // we're writing to the standard output by defaulr + return new Spreadsheet_Excel_Writer($filename); + } + + protected function assertSameAsInFixture($filename, Spreadsheet_Excel_Writer $workbook) + { + $this->assertEmpty($workbook->_filename, "Testing with fixtures works only for standard output"); + + // we have to fix timestamp for fixtures to work + $workbook->_timestamp = 1000000000; // somewhere in 2001 + + ob_start(); + $workbook->close(); + $data = ob_get_clean(); + + $fullPath = self::FIXTURES_PATH.$filename; + + if ($this->shouldUpdateFixtures()) { + file_put_contents($fullPath, $data); + } + + if (!is_file($fullPath)) { + $this->fail("Fixture $filename not found"); + } + + // TODO: should we save data for future analysis? + //file_put_contents("{$fullPath}.work", $data); + + $this->assertEquals(file_get_contents($fullPath), $data, "Output differs for $filename"); + } + + /** + * We should update golden files + */ + private function shouldUpdateFixtures() + { + return isset($_SERVER['GOLDEN']); + } +} \ No newline at end of file diff --git a/vendor/pear/spreadsheet_excel_writer/test/fixture/example.xls b/vendor/pear/spreadsheet_excel_writer/test/fixture/example.xls new file mode 100644 index 0000000000000000000000000000000000000000..f7955b3a5f310dbdbd7dbf03b551b7889d7eb591 GIT binary patch literal 3584 zcmeHJO-~d-5PdVuvaE{21~{0QY)Je*nYoY{T`?{{fQx%wBa;{wAsY{Ha=?$X(PWc8 z@(<*~MGnJ_!zAiISUGX@;!S8@RnL&s?1jV_3DYyLy1J&js#8_nHD5lD_cpgKf5RW` zE{1SqD;VyRd*p+BJmwgY9a(E-R3gY0?G$-H;^z}Xgv3^2C^0V+BSeKbN1P`v5TnFJ z;u0Y#FiuGPi*`CaP#IwqhfDZ0nwDo7ONsqMX2i$f9;)PlovWS68Ra}Q{b|jXJD9{C zW%lJeNg%coW;@SX?SJ_pfEXA1neiSbbT2<_O?yX@S|Jxt{Cz(FHRocbPQR-cl*{Fz zEvbF*d9%c@@39Y;Njxjil93UqA1Wae%c_jT>|+^_Ns@$J3}Y-z7_ri%NI5^^V<|_( zaViRFN*-ZVpK4GYVug!zUCQ;=8W@hP;acjosX-W7glS4SXA2AwQGI04?RLQl2n_`x zU&1IT3%QnpH<-d(xlU2`8dyaOOISf03;4+sCFv^Q{n}VW{#%CD2|1`~Q$^8l)iSNi3((rd>~Kd4{t<8K`E-|IK~_)SdH_EX)DRDq`7lv2Rf ztLHuU>dSracJ1h)Rs>fAfct(G+Zy%PP~x=AX&2i^UuSkbWWCIb12^F@t#`19C%TVCCp-bIGH-MH f(hsyhK;Lp^f54|RC6a%){QpmQ!68w!v*CeX@3&$i literal 0 HcmV?d00001 diff --git a/vendor/pear/spreadsheet_excel_writer/test/fixture/example2.xls b/vendor/pear/spreadsheet_excel_writer/test/fixture/example2.xls new file mode 100644 index 0000000000000000000000000000000000000000..963ff0c84015bb5c4504d4dff1963b5cc1ca5963 GIT binary patch literal 5120 zcmeI#ON$(36b9h0?p5)YXlB%Cw2bC5i9)*Tj_6=8{(!7z8_))EG+_|bmF;aW3Inyw zPjKVPMQ5kbp#FnVT)1@O(vxI07UVpI39o{ZbaxgxbY!!XEJieU9<`WIaRX+IwckPwLwX>)03Y0nHfhTMhR zjogFWi`<7u7dV03k34{!MAndXzmY z9=U*QAQzEK$kWI(i1fFk>94s0S&CMUBDbA=m0Uqj_#s@!+(Y|iE(xx_ef{;D+pj#Q zP3+tkXLr_GG=RenTmBjCI1@Dcm#7Tyek^?nQ}n{ltJk;xu6pR?ymD%ucTc;eb3YHc zTjb(#?x^OGa)?dz<4Dr|?BPCiG>Xmf<>a*KWL(U(PSHuW6-%)x)hs2Z)UcGAQp-|iN}ZJO7af!))O#q7f6ydXy@%_u zDyiPXGi_B;z2{c?Nv?ViPrTJ$s`u~!T$NPs;qt9Ys`t<`tCH$HjG3#F>ZO6k(v*4` zT~{U5`$j*_Rqq@9G*`WE^i%46qo3xg_lePHwj^?}hB)CWdiP#+k5L49EK1@(c^7u1JFUs4|$eMx<2^d`pD=j>La7CsE>@kqCPVEih6m1jQX1T*ywBOW23LBkBz>jJ~sNA`q=1e>SLp? zsgI4mram_Mn)=x2YwG3Ychoo3Cq~~;pBQ~ZePZ+t^@-6p)F(#YP@fomLw#cO4fTo9 zH`FIa-%u~F?W4Y>J~jH5`qb!K>Qkd{sZWi*r9L(KmipA_Tk2DzZ>dj>zNJ1j`j&e6 z!7=JP>NBJ7sLzbPqdqhGj{3~#JL)r|@2Hm_xvMkkh>3S!Q_>MLGy0DD%;>wkdmc~T z&!yw*bQ%ZHmk7R`N=+Wh|Fr3vyMfP}E_YYm8(8kRcm5D@9oKXGB_fY%m+_rs!K1vS zi}~>4x9x4u?Js4&x%{BSbVbkq8aMvL{1`gIcz#(Pdj3O>dvpK%hy2(7swBUqrNyMH U$^&!!{V#RNFUZmK-@O9A0`TUwY5)KL literal 0 HcmV?d00001 diff --git a/vendor/pear/spreadsheet_excel_writer/test/fixture/with_format.xls b/vendor/pear/spreadsheet_excel_writer/test/fixture/with_format.xls new file mode 100644 index 0000000000000000000000000000000000000000..97e501571725325794be6b5e990fef8c7b31accb GIT binary patch literal 3584 zcmeHJ&1(};5dUqOv`K3}5?et*Sn5|*kjP#NqS=ZS&wgO8QL|DKZHYnjAg*6$#X?|@ z{SWjaf*#VFhXwUNh=SnJi#OZnZ)P`Xlw1lTlw{K1d-LYKH}g6(@6CStm~E}S-uDH6 z(J2gJ(_}E*CAY{Y+vBN-5!t3OMn)-u?0|NV2PA$8Vu+B~N(?3DBSf0W5TnExv5Ocd zCWuKwQXos@h~30AA-OQ1o#TN_no%51;oW#RvcULB?9VbIUL{X!T!Ht8YBTec0v3vi zSlAQxBsdp`hn?Bgx{Q8A%hUKXXut~@sSoXlmjuI<`#p49}OBOm4^z9LFLUMgsv zi5n?8Dk0;Gg1GV7`!XQYY&O~X2m*t^@mQWhgk10OXDElqaVQFDN`AtsKGmQ)#0od* zzL5Kk2@r5>0`8?=69#ZR11AhA=W0PfcvSBNXfzt&0yqH$4*!TiL7Bt76gOq zygc5~C7=4^l3$^oG#==~K8m*o9lQYvEcPao4oCf2fM&?0lE&Lq3PEpO~$wzaFB z_#K%joXtqfdF_02?(_V*g}9e>u6$^au4-aea81uqiGe VS0eddlZeT!5MHoB45&Xm@EcNwYJ>m) literal 0 HcmV?d00001 diff --git a/vendor/ralouphie/getallheaders/LICENSE b/vendor/ralouphie/getallheaders/LICENSE new file mode 100644 index 00000000..be5540c2 --- /dev/null +++ b/vendor/ralouphie/getallheaders/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Ralph Khattar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/ralouphie/getallheaders/README.md b/vendor/ralouphie/getallheaders/README.md new file mode 100644 index 00000000..9430d76b --- /dev/null +++ b/vendor/ralouphie/getallheaders/README.md @@ -0,0 +1,27 @@ +getallheaders +============= + +PHP `getallheaders()` polyfill. Compatible with PHP >= 5.3. + +[![Build Status](https://travis-ci.org/ralouphie/getallheaders.svg?branch=master)](https://travis-ci.org/ralouphie/getallheaders) +[![Coverage Status](https://coveralls.io/repos/ralouphie/getallheaders/badge.png?branch=master)](https://coveralls.io/r/ralouphie/getallheaders?branch=master) +[![Latest Stable Version](https://poser.pugx.org/ralouphie/getallheaders/v/stable.png)](https://packagist.org/packages/ralouphie/getallheaders) +[![Latest Unstable Version](https://poser.pugx.org/ralouphie/getallheaders/v/unstable.png)](https://packagist.org/packages/ralouphie/getallheaders) +[![License](https://poser.pugx.org/ralouphie/getallheaders/license.png)](https://packagist.org/packages/ralouphie/getallheaders) + + +This is a simple polyfill for [`getallheaders()`](http://www.php.net/manual/en/function.getallheaders.php). + +## Install + +For PHP version **`>= 5.6`**: + +``` +composer require ralouphie/getallheaders +``` + +For PHP version **`< 5.6`**: + +``` +composer require ralouphie/getallheaders "^2" +``` diff --git a/vendor/ralouphie/getallheaders/composer.json b/vendor/ralouphie/getallheaders/composer.json new file mode 100644 index 00000000..de8ce62e --- /dev/null +++ b/vendor/ralouphie/getallheaders/composer.json @@ -0,0 +1,26 @@ +{ + "name": "ralouphie/getallheaders", + "description": "A polyfill for getallheaders.", + "license": "MIT", + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^5 || ^6.5", + "php-coveralls/php-coveralls": "^2.1" + }, + "autoload": { + "files": ["src/getallheaders.php"] + }, + "autoload-dev": { + "psr-4": { + "getallheaders\\Tests\\": "tests/" + } + } +} diff --git a/vendor/ralouphie/getallheaders/src/getallheaders.php b/vendor/ralouphie/getallheaders/src/getallheaders.php new file mode 100644 index 00000000..c7285a5b --- /dev/null +++ b/vendor/ralouphie/getallheaders/src/getallheaders.php @@ -0,0 +1,46 @@ + 'Content-Type', + 'CONTENT_LENGTH' => 'Content-Length', + 'CONTENT_MD5' => 'Content-Md5', + ); + + foreach ($_SERVER as $key => $value) { + if (substr($key, 0, 5) === 'HTTP_') { + $key = substr($key, 5); + if (!isset($copy_server[$key]) || !isset($_SERVER[$key])) { + $key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key)))); + $headers[$key] = $value; + } + } elseif (isset($copy_server[$key])) { + $headers[$copy_server[$key]] = $value; + } + } + + if (!isset($headers['Authorization'])) { + if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { + $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; + } elseif (isset($_SERVER['PHP_AUTH_USER'])) { + $basic_pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : ''; + $headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass); + } elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) { + $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST']; + } + } + + return $headers; + } + +} diff --git a/vendor/smarty/smarty/change_log.txt b/vendor/smarty/smarty/CHANGELOG.md similarity index 96% rename from vendor/smarty/smarty/change_log.txt rename to vendor/smarty/smarty/CHANGELOG.md index aeb17e4d..6c6d1aa5 100644 --- a/vendor/smarty/smarty/change_log.txt +++ b/vendor/smarty/smarty/CHANGELOG.md @@ -1,4 +1,94 @@ -๏ปฟ===== 3.1.34-dev-6 ===== +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [3.1.45] - 2022-05-17 + +### Security +- Prevent PHP injection through malicious block name or include file name. This addresses CVE-2022-29221 + +### Fixed +- Math equation `max(x, y)` didn't work anymore [#721](https://github.com/smarty-php/smarty/issues/721) + +## [3.1.44] - 2022-01-18 + +### Fixed +- Fixed illegal characters bug in math function security check [#702](https://github.com/smarty-php/smarty/issues/702) + +## [3.1.43] - 2022-01-10 + +### Security +- Prevent evasion of the `static_classes` security policy. This addresses CVE-2021-21408 + +## [3.1.42] - 2022-01-10 + +### Security +- Prevent arbitrary PHP code execution through maliciously crafted expression for the math function. This addresses CVE-2021-29454 + +## [3.1.41] - 2022-01-09 + +### Security +- Rewrote the mailto function to not use `eval` when encoding with javascript + +## [3.1.40] - 2021-10-13 + +### Changed +- modifier escape now triggers a E_USER_NOTICE when an unsupported escape type is used https://github.com/smarty-php/smarty/pull/649 + +### Security +- More advanced javascript escaping to handle https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements thanks to m-haritonov + +## [3.1.39] - 2021-02-17 + +### Security +- Prevent access to `$smarty.template_object` in sandbox mode. This addresses CVE-2021-26119. +- Fixed code injection vulnerability by using illegal function names in `{function name='blah'}{/function}`. This addresses CVE-2021-26120. + +## [3.1.38] - 2021-01-08 + +### Fixed +- Smarty::SMARTY_VERSION wasn't updated https://github.com/smarty-php/smarty/issues/628 + +## [3.1.37] - 2021-01-07 + +### Changed +- Changed error handlers and handling of undefined constants for php8-compatibility (set $errcontext argument optional) https://github.com/smarty-php/smarty/issues/605 +- Changed expected error levels in unit tests for php8-compatibility +- Travis unit tests now run for all php versions >= 5.3, including php8 +- Travis runs on Xenial where possible + +### Fixed +- PHP5.3 compatibility fixes +- Brought lexer source functionally up-to-date with compiled version + +## [3.1.36] - 2020-04-14 + +### Fixed + - Smarty::SMARTY_VERSION wasn't updated in v3.1.35 https://github.com/smarty-php/smarty/issues/584 + +## [3.1.35] - 2020-04-14 + - remove whitespaces after comments https://github.com/smarty-php/smarty/issues/447 + - fix foreachelse on arrayiterators https://github.com/smarty-php/smarty/issues/506 + - fix files contained in git export archive for package maintainers https://github.com/smarty-php/smarty/issues/325 + - throw SmartyException when setting caching attributes for cacheable plugin https://github.com/smarty-php/smarty/issues/457 + - fix errors that occured where isset was replaced with null check such as https://github.com/smarty-php/smarty/issues/453 + - unit tests are now in the repository + +## 3.1.34 release - 05.11.2019 +13.01.2020 + - fix typo in exception message (JercSi) + - fix typehint warning with callable (bets4breakfast) + - add travis badge and compatability info to readme (matks) + - fix stdClass cast when compiling foreach (carpii) + - fix wrong set/get methods for memcached (IT-Experte) + - fix pborm assigning value to object variables in smarty_internal_compile_assign (Hunman) + - exclude error_reporting.ini from git export (glensc) + +## 3.1.34-dev-6 - 30.10.2018 - bugfix a nested subblock in an inheritance child template was not replace by outer level block with same name in same child template https://github.com/smarty-php/smarty/issues/500 @@ -26,8 +116,8 @@ could fail in version 3.1.32 and 3.1.33 because PHP preg_match() restrictions https://github.com/smarty-php/smarty/issues/488 -===== 3.1.33 release ===== 12.09.2018 -===== 3.1.33-dev-12 ===== +## 3.1.33 release - 12.09.2018 +## 3.1.33-dev-12 - 03.09.2018 - bugfix {foreach} using new style property access like {$item@property} on Smarty 2 style named foreach loop could produce errors https://github.com/smarty-php/smarty/issues/484 @@ -49,14 +139,14 @@ - bugfix/enhancement {capture} allow variable as capture block name in Smarty special variable like $smarty.capture.$foo https://github.com/smarty-php/smarty/issues/478 https://github.com/smarty-php/smarty/pull/481 -===== 3.1.33-dev-6 ===== +## 3.1.33-dev-6 - 19.08.2018 - fix PSR-2 coding standards and PHPDoc blocks https://github.com/smarty-php/smarty/pull/452 https://github.com/smarty-php/smarty/pull/475 https://github.com/smarty-php/smarty/pull/473 - bugfix PHP5.2 compatibility https://github.com/smarty-php/smarty/pull/472 -===== 3.1.33-dev-4 ===== +## 3.1.33-dev-4 - 17.05.2018 - bugfix strip-block produces different output in Smarty v3.1.32 https://github.com/smarty-php/smarty/issues/436 - bugfix Smarty::compileAllTemplates ignores `$extension` parameter https://github.com/smarty-php/smarty/issues/437 @@ -68,7 +158,7 @@ - bugfix regarding Security Vulnerability did not solve the problem under Linux. Security issue CVE-2018-16831 -===== 3.1.32 ===== (24.04.2018) +## 3.1.32 - (24.04.2018) 24.04.2018 - bugfix possible Security Vulnerability in Smarty_Security class. @@ -209,7 +299,7 @@ 13.4.2017 - bugfix array_merge() parameter should be checked https://github.com/smarty-php/smarty/issues/350 -===== 3.1.31 ===== (14.12.2016) +## 3.1.31 - (14.12.2016) 23.11.2016 - move template object cache into static variables @@ -323,7 +413,7 @@ compiled or cached template files https://github.com/smarty-php/smarty/issues/269 - optimization remove unneeded call to update acopes when {assign} scope and template scope was local (default) -===== 3.1.30 ===== (07.08.2016) +## 3.1.30 - (07.08.2016) 07.08.2016 - bugfix update of 04.08.2016 was incomplete @@ -546,7 +636,7 @@ - optimization of filepath normalization - bugfix {strip} must remove all blanks between html tags https://github.com/smarty-php/smarty/issues/136 - ===== 3.1.29 ===== (21.12.2015) + - 3.1.29 - (21.12.2015) 21.12.2015 - optimization improve speed of filetime checks on extends and extendsall resource @@ -582,7 +672,7 @@ - bugfix {$smarty.config.foo} broken in 3.1.28 https://github.com/smarty-php/smarty/issues/120 - bugfix multiple calls of {section} with same name droped E_NOTICE error https://github.com/smarty-php/smarty/issues/118 - ===== 3.1.28 ===== (13.12.2015) + - 3.1.28 - (13.12.2015) 13.12.2015 - bugfix {foreach} and {section} with uppercase characters in name attribute did not work (forum topic 25819) - bugfix $smarty->debugging_ctrl = 'URL' did not work (forum topic 25811) @@ -761,18 +851,18 @@ 19.06.2015 - improvement allow closures as callback at $smarty->registerFilter() https://github.com/smarty-php/smarty/issues/59 - ===== 3.1.27===== (18.06.2015) + - 3.1.27- (18.06.2015) 18.06.2015 - bugfix another update on file path normalization failed on path containing something like "/.foo/" https://github.com/smarty-php/smarty/issues/56 - ===== 3.1.26===== (18.06.2015) + - 3.1.26- (18.06.2015) 18.06.2015 - bugfix file path normalization failed on path containing something like "/.foo/" https://github.com/smarty-php/smarty/issues/56 17.06.2015 - bugfix calling a plugin with nocache option but no other attributes like {foo nocache} caused call to undefined function https://github.com/smarty-php/smarty/issues/55 - ===== 3.1.25===== (15.06.2015) + - 3.1.25- (15.06.2015) 15.06.2015 - optimization of smarty_cachereource_keyvaluestore.php code @@ -802,7 +892,7 @@ 24.05.2015 - bugfix if condition string 'neq' broken due to a typo https://github.com/smarty-php/smarty/issues/42 - ===== 3.1.24===== (23.05.2015) + - 3.1.24- (23.05.2015) 23.05.2015 - improvement on php_handling to allow very large PHP sections, better error handling - improvement allow extreme large comment sections (forum 25538) @@ -840,12 +930,12 @@ - bugfix access to undefined config variable like {#undef#} did fail https://github.com/smarty-php/smarty/issues/29 - bugfix in nested {foreach} saved item attributes got overwritten https://github.com/smarty-php/smarty/issues/33 - ===== 3.1.23 ===== (12.05.2015) + - 3.1.23 - (12.05.2015) 12.05.2015 - bugfix of smaller performance issue introduce in 3.1.22 when caching is enabled - bugfix missig entry for smarty-temmplate-config in autoloader - ===== 3.1.22 ===== tag was deleted because 3.1.22 did fail caused by the missing entry for smarty-temmplate-config in autoloader + - 3.1.22 - tag was deleted because 3.1.22 did fail caused by the missing entry for smarty-temmplate-config in autoloader 10.05.2015 - bugfix custom cache resource did not observe compile_id and cache_id when $cache_locking == true - bugfix cache lock was not handled correctly after timeout when $cache_locking == true @@ -997,7 +1087,7 @@ - bugfix E_NOTICE message was created during compilation when ASP tags '<%' or '%>' are in template source text - bugfix merge_compiled_includes option failed when caching enables and same subtemplate was included cached and not cached - ===== 3.1.21 ===== (18.10.2014) + - 3.1.21 - (18.10.2014) 18.10.2014 - composer moved to github @@ -1020,7 +1110,7 @@ - bugfix change of 08.10.2014 could create E_NOTICE meassage when using "" with $php_handling PHP_PASSTHRU was executed in {nocache} sections - ===== 3.1.20 ===== (09.10.2014) + - 3.1.20 - (09.10.2014) 08.10.2014 - bugfix security mode of "'; + return ''; } elseif ($encode === 'javascript_charcode') { $string = '' . $text . ''; - for ($x = 0, $y = strlen($string); $x < $y; $x++) { + for ($x = 0, $_length = strlen($string); $x < $_length; $x++) { $ord[] = ord($string[ $x ]); } - $_ret = "\n"; - return $_ret; + return ''; } elseif ($encode === 'hex') { preg_match('!^(.*)(\?.*)$!', $address, $match); if (!empty($match[ 2 ])) { diff --git a/vendor/smarty/smarty/libs/plugins/function.math.php b/vendor/smarty/smarty/libs/plugins/function.math.php index 7348d964..d5f86a69 100644 --- a/vendor/smarty/smarty/libs/plugins/function.math.php +++ b/vendor/smarty/smarty/libs/plugins/function.math.php @@ -28,7 +28,12 @@ function smarty_function_math($params, $template) 'int' => true, 'abs' => true, 'ceil' => true, + 'acos' => true, + 'acosh' => true, 'cos' => true, + 'cosh' => true, + 'deg2rad' => true, + 'rad2deg' => true, 'exp' => true, 'floor' => true, 'log' => true, @@ -39,27 +44,51 @@ function smarty_function_math($params, $template) 'pow' => true, 'rand' => true, 'round' => true, + 'asin' => true, + 'asinh' => true, 'sin' => true, + 'sinh' => true, 'sqrt' => true, 'srand' => true, - 'tan' => true + 'atan' => true, + 'atanh' => true, + 'tan' => true, + 'tanh' => true ); + // be sure equation parameter is present if (empty($params[ 'equation' ])) { trigger_error("math: missing equation parameter", E_USER_WARNING); return; } $equation = $params[ 'equation' ]; + + // Remove whitespaces + $equation = preg_replace('/\s+/', '', $equation); + + // Adapted from https://www.php.net/manual/en/function.eval.php#107377 + $number = '(?:\d+(?:[,.]\d+)?|pi|ฯ€)'; // What is a number + $functionsOrVars = '((?:0x[a-fA-F0-9]+)|([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*))'; + $operators = '[,+\/*\^%-]'; // Allowed math operators + $regexp = '/^(('.$number.'|'.$functionsOrVars.'|('.$functionsOrVars.'\s*\((?1)+\)|\((?1)+\)))(?:'.$operators.'(?1))?)+$/'; + + if (!preg_match($regexp, $equation)) { + trigger_error("math: illegal characters", E_USER_WARNING); + return; + } + // make sure parenthesis are balanced if (substr_count($equation, '(') !== substr_count($equation, ')')) { trigger_error("math: unbalanced parenthesis", E_USER_WARNING); return; } + // disallow backticks if (strpos($equation, '`') !== false) { trigger_error("math: backtick character not allowed in equation", E_USER_WARNING); return; } + // also disallow dollar signs if (strpos($equation, '$') !== false) { trigger_error("math: dollar signs not allowed in equation", E_USER_WARNING); @@ -96,6 +125,7 @@ function smarty_function_math($params, $template) } $smarty_math_result = null; eval("\$smarty_math_result = " . $equation . ";"); + if (empty($params[ 'format' ])) { if (empty($params[ 'assign' ])) { return $smarty_math_result; diff --git a/vendor/smarty/smarty/libs/plugins/modifier.escape.php b/vendor/smarty/smarty/libs/plugins/modifier.escape.php index 150901c7..43353cfc 100644 --- a/vendor/smarty/smarty/libs/plugins/modifier.escape.php +++ b/vendor/smarty/smarty/libs/plugins/modifier.escape.php @@ -184,7 +184,11 @@ function smarty_modifier_escape($string, $esc_type = 'html', $char_set = null, $ '"' => '\\"', "\r" => '\\r', "\n" => '\\n', - ' '<\/' + ' '<\/', + // see https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements + '