From fa0a498733b5104dd4791a97ec3ff17c883ba847 Mon Sep 17 00:00:00 2001 From: Sumit Panwar Date: Fri, 23 May 2025 10:46:00 +0530 Subject: [PATCH] Libs changes for php 8.x --- .travis.yml | 6 +- Adapter/Adapter_ProductPriceCalculator.php | 2 +- classes/Cart.php | 2 +- classes/Context.php | 4 +- .../{Attribute.php => ProductAttribute.php} | 8 +- classes/Smarty/SmartyCustom.php | 2 + classes/controller/Controller.php | 7 +- classes/controller/FrontController.php | 41 +- config/smarty.config.inc.php | 2 +- .../AdminAttributeGeneratorController.php | 2 +- .../admin/AdminAttributesGroupsController.php | 22 +- controllers/admin/AdminCartsController.php | 4 +- .../admin/AdminGeolocationController.php | 8 +- controllers/admin/AdminOrdersController.php | 4 +- .../AdminSpecificPriceRuleController.php | 2 +- controllers/front/CartController.php | 8 +- tools/defuse/php-encryption/LICENSE | 4 +- tools/defuse/php-encryption/README.md | 54 +- .../php-encryption/bin/generate-defuse-key | 14 + .../defuse/php-encryption/defuse-crypto.phar | Bin 50825 -> 58571 bytes tools/defuse/php-encryption/dist/Makefile | 8 +- tools/defuse/php-encryption/dist/box.json | 3 - tools/defuse/php-encryption/dist/index.php | 29 - .../dist/phar-testing-autoload.php | 4 + .../php-encryption/dist/signingkey-new.asc | 53 + .../dist/signingkey-new.asc.sig | Bin 0 -> 566 bytes .../php-encryption/docs/CryptoDetails.md | 64 + tools/defuse/php-encryption/docs/FAQ.md | 51 + .../docs/InstallingAndVerifying.md | 53 + .../docs/InternalDeveloperDocs.md | 166 + tools/defuse/php-encryption/docs/Tutorial.md | 314 + .../php-encryption/docs/UpgradingFromV1.2.md | 51 + .../php-encryption/docs/classes/Crypto.md | 280 + .../php-encryption/docs/classes/File.md | 486 ++ .../defuse/php-encryption/docs/classes/Key.md | 117 + .../docs/classes/KeyProtectedByPassword.md | 259 + tools/defuse/php-encryption/index.php | 29 - tools/defuse/php-encryption/src/Core.php | 232 +- tools/defuse/php-encryption/src/Crypto.php | 205 +- .../defuse/php-encryption/src/DerivedKeys.php | 17 +- tools/defuse/php-encryption/src/Encoding.php | 97 +- .../php-encryption/src/Exception/index.php | 29 - tools/defuse/php-encryption/src/File.php | 200 +- tools/defuse/php-encryption/src/Key.php | 33 +- .../php-encryption/src/KeyOrPassword.php | 51 +- .../src/KeyProtectedByPassword.php | 55 +- .../php-encryption/src/RuntimeTests.php | 44 +- tools/defuse/php-encryption/src/index.php | 29 - tools/geoip/LICENSE | 219 +- tools/geoip/autoload.php | 7 + tools/geoip/composer/ClassLoader.php | 572 ++ tools/geoip/composer/InstalledVersions.php | 350 + tools/geoip/composer/LICENSE | 21 + tools/geoip/composer/autoload_classmap.php | 10 + tools/geoip/composer/autoload_namespaces.php | 9 + tools/geoip/composer/autoload_psr4.php | 14 + tools/geoip/composer/autoload_real.php | 57 + tools/geoip/composer/autoload_static.php | 62 + tools/geoip/composer/ca-bundle/LICENSE | 19 + tools/geoip/composer/ca-bundle/README.md | 85 + tools/geoip/composer/ca-bundle/composer.json | 54 + tools/geoip/composer/ca-bundle/res/cacert.pem | 3696 +++++++++ .../geoip/composer/ca-bundle/src/CaBundle.php | 321 + tools/geoip/composer/installed.json | 266 + tools/geoip/composer/installed.php | 59 + tools/geoip/composer/platform_check.php | 26 + tools/geoip/geoip.inc | 820 -- tools/geoip/geoip2/geoip2/CHANGELOG.md | 352 + tools/geoip/geoip2/geoip2/LICENSE | 202 + tools/geoip/geoip2/geoip2/README.md | 448 ++ tools/geoip/geoip2/geoip2/composer.json | 32 + .../geoip2/geoip2/examples/benchmark.php | 27 + .../geoip2/geoip2/src/Database/Reader.php | 271 + .../Exception/AddressNotFoundException.php | 11 + .../src/Exception/AuthenticationException.php | 11 + .../geoip2/src/Exception/GeoIp2Exception.php | 11 + .../geoip2/src/Exception/HttpException.php | 26 + .../src/Exception/InvalidRequestException.php | 28 + .../src/Exception/OutOfQueriesException.php | 11 + .../geoip2/geoip2/src/Model/AnonymousIp.php | 100 + tools/geoip/geoip2/geoip2/src/Model/Asn.php | 73 + tools/geoip/geoip2/geoip2/src/Model/City.php | 129 + .../geoip2/src/Model/ConnectionType.php | 61 + .../geoip/geoip2/geoip2/src/Model/Country.php | 120 + .../geoip/geoip2/geoip2/src/Model/Domain.php | 61 + .../geoip2/geoip2/src/Model/Enterprise.php | 14 + .../geoip2/geoip2/src/Model/Insights.php | 14 + tools/geoip/geoip2/geoip2/src/Model/Isp.php | 115 + .../geoip2/geoip2/src/ProviderInterface.php | 22 + .../geoip2/src/Record/AbstractNamedRecord.php | 55 + .../geoip2/src/Record/AbstractPlaceRecord.php | 52 + tools/geoip/geoip2/geoip2/src/Record/City.php | 14 + .../geoip2/geoip2/src/Record/Continent.php | 56 + .../geoip2/geoip2/src/Record/Country.php | 57 + .../geoip2/geoip2/src/Record/Location.php | 113 + .../geoip2/geoip2/src/Record/MaxMind.php | 42 + .../geoip/geoip2/geoip2/src/Record/Postal.php | 57 + .../geoip2/src/Record/RepresentedCountry.php | 48 + .../geoip2/geoip2/src/Record/Subdivision.php | 48 + .../geoip/geoip2/geoip2/src/Record/Traits.php | 306 + tools/geoip/geoip2/geoip2/src/Util.php | 37 + .../geoip2/geoip2/src/WebService/Client.php | 263 + tools/geoip/geoipcity.inc | 237 - tools/geoip/geoipregionvars.php | 4191 ---------- tools/geoip/index.php | 44 +- tools/geoip/maxmind-db/reader/CHANGELOG.md | 244 + tools/geoip/maxmind-db/reader/LICENSE | 202 + tools/geoip/maxmind-db/reader/README.md | 185 + tools/geoip/maxmind-db/reader/autoload.php | 47 + tools/geoip/maxmind-db/reader/composer.json | 42 + tools/geoip/maxmind-db/reader/ext/config.m4 | 40 + tools/geoip/maxmind-db/reader/ext/config.w32 | 10 + tools/geoip/maxmind-db/reader/ext/maxminddb.c | 811 ++ .../maxmind-db/reader/ext/php_maxminddb.h | 24 + .../maxmind-db/reader/ext/tests/001-load.phpt | 12 + .../reader/ext/tests/002-final.phpt | 13 + .../reader/ext/tests/003-open-basedir.phpt | 12 + tools/geoip/maxmind-db/reader/package.xml | 63 + .../reader/src/MaxMind/Db/Reader.php | 410 + .../reader/src/MaxMind/Db/Reader/Decoder.php | 452 ++ .../Db/Reader/InvalidDatabaseException.php | 11 + .../reader/src/MaxMind/Db/Reader/Metadata.php | 123 + .../reader/src/MaxMind/Db/Reader/Util.php | 33 + .../maxmind/web-service-common/CHANGELOG.md | 117 + .../geoip/maxmind/web-service-common/LICENSE | 202 + .../maxmind/web-service-common/README.md | 25 + .../maxmind/web-service-common/composer.json | 32 + .../web-service-common/dev-bin/release.sh | 56 + .../maxmind/web-service-common/phpstan.neon | 6 + .../src/Exception/AuthenticationException.php | 11 + .../src/Exception/HttpException.php | 44 + .../Exception/InsufficientFundsException.php | 11 + .../src/Exception/InvalidInputException.php | 13 + .../src/Exception/InvalidRequestException.php | 41 + .../Exception/IpAddressNotFoundException.php | 8 + .../Exception/PermissionRequiredException.php | 11 + .../src/Exception/WebServiceException.php | 11 + .../src/WebService/Client.php | 552 ++ .../src/WebService/Http/CurlRequest.php | 146 + .../src/WebService/Http/Request.php | 28 + .../src/WebService/Http/RequestFactory.php | 51 + .../HTMLPurifier.autoload-legacy.php | 7 +- tools/htmlpurifier/HTMLPurifier.autoload.php | 1 + tools/htmlpurifier/HTMLPurifier.includes.php | 4 +- tools/htmlpurifier/HTMLPurifier.php | 6 +- .../HTMLPurifier.safe-includes.php | 2 + .../htmlpurifier/HTMLPurifier/AttrDef/CSS.php | 14 +- .../HTMLPurifier/AttrDef/CSS/Background.php | 2 + .../HTMLPurifier/AttrDef/CSS/FontFamily.php | 32 +- .../HTMLPurifier/AttrDef/CSS/Ratio.php | 46 + .../HTMLPurifier/AttrDef/CSS/index.php | 29 - .../AttrDef/HTML/ContentEditable.php | 16 + .../HTMLPurifier/AttrDef/HTML/index.php | 29 - .../HTMLPurifier/AttrDef/URI/Host.php | 20 +- .../HTMLPurifier/AttrDef/URI/index.php | 29 - .../HTMLPurifier/AttrDef/index.php | 29 - .../HTMLPurifier/AttrTransform/NameSync.php | 5 + .../HTMLPurifier/AttrTransform/SafeParam.php | 5 + .../AttrTransform/TargetBlank.php | 6 +- .../HTMLPurifier/AttrTransform/index.php | 29 - tools/htmlpurifier/HTMLPurifier/AttrTypes.php | 1 + tools/htmlpurifier/HTMLPurifier/Bootstrap.php | 41 +- .../HTMLPurifier/CSSDefinition.php | 212 +- .../HTMLPurifier/ChildDef/List.php | 2 + .../HTMLPurifier/ChildDef/Table.php | 5 +- .../HTMLPurifier/ChildDef/index.php | 29 - tools/htmlpurifier/HTMLPurifier/Config.php | 4 +- .../ConfigSchema/Builder/index.php | 29 - .../ConfigSchema/Interchange/index.php | 29 - .../HTMLPurifier/ConfigSchema/index.php | 29 - .../HTMLPurifier/ConfigSchema/schema.ser | 2 +- .../ConfigSchema/schema/Core.RemoveBlanks.txt | 10 + .../ConfigSchema/schema/index.php | 29 - .../DefinitionCache/Decorator/index.php | 29 - .../DefinitionCache/Serializer.php | 11 +- .../DefinitionCache/Serializer/index.php | 29 - .../HTMLPurifier/DefinitionCache/index.php | 29 - .../HTMLPurifier/DefinitionCacheFactory.php | 2 +- .../htmlpurifier/HTMLPurifier/ElementDef.php | 2 +- tools/htmlpurifier/HTMLPurifier/Encoder.php | 8 +- .../HTMLPurifier/EntityLookup/index.php | 29 - .../HTMLPurifier/EntityParser.php | 4 +- .../Filter/ExtractStyleBlocks.php | 337 +- .../HTMLPurifier/Filter/index.php | 29 - .../htmlpurifier/HTMLPurifier/HTMLModule.php | 3 +- .../HTMLModule/CommonAttributes.php | 1 + .../HTMLPurifier/HTMLModule/Iframe.php | 28 +- .../HTMLPurifier/HTMLModule/Tidy.php | 6 +- .../HTMLModule/Tidy/XHTMLAndHTML4.php | 4 +- .../HTMLPurifier/HTMLModule/Tidy/index.php | 29 - .../HTMLPurifier/HTMLModule/index.php | 29 - .../HTMLPurifier/Injector/Linkify.php | 3 + .../Injector/RemoveSpansWithoutAttributes.php | 15 +- .../HTMLPurifier/Injector/index.php | 29 - .../HTMLPurifier/Language/index.php | 29 - .../HTMLPurifier/Language/messages/index.php | 29 - .../HTMLPurifier/LanguageFactory.php | 2 +- tools/htmlpurifier/HTMLPurifier/Length.php | 2 +- tools/htmlpurifier/HTMLPurifier/Lexer.php | 27 +- .../HTMLPurifier/Lexer/DOMLex.php | 4 +- .../htmlpurifier/HTMLPurifier/Lexer/PH5P.php | 2 +- .../htmlpurifier/HTMLPurifier/Lexer/index.php | 29 - .../htmlpurifier/HTMLPurifier/Node/index.php | 29 - .../HTMLPurifier/Printer/ConfigForm.php | 5 + .../HTMLPurifier/Printer/index.php | 29 - .../HTMLPurifier/PropertyListIterator.php | 1 + .../HTMLPurifier/Strategy/index.php | 29 - .../htmlpurifier/HTMLPurifier/StringHash.php | 1 + .../HTMLPurifier/TagTransform/index.php | 29 - tools/htmlpurifier/HTMLPurifier/Token/Tag.php | 2 +- .../htmlpurifier/HTMLPurifier/Token/index.php | 29 - .../HTMLPurifier/URIFilter/HostBlacklist.php | 2 +- .../HTMLPurifier/URIFilter/Munge.php | 10 +- .../HTMLPurifier/URIFilter/index.php | 29 - .../HTMLPurifier/URIScheme/index.php | 29 - .../HTMLPurifier/URIScheme/tel.php | 6 +- .../HTMLPurifier/UnitConverter.php | 6 +- .../HTMLPurifier/VarParser/index.php | 29 - tools/htmlpurifier/HTMLPurifier/index.php | 29 - tools/htmlpurifier/LICENSE | 504 -- tools/htmlpurifier/index.php | 29 - tools/http_build_url/http_build_url.php | 21 +- tools/js_minify/LICENSE | 42 +- tools/js_minify/jsmin.php | 984 ++- tools/mailer/autoload.php | 7 + tools/mailer/composer/ClassLoader.php | 572 ++ tools/mailer/composer/InstalledVersions.php | 350 + tools/mailer/composer/LICENSE | 21 + tools/mailer/composer/autoload_classmap.php | 11 + tools/mailer/composer/autoload_files.php | 13 + tools/mailer/composer/autoload_namespaces.php | 9 + tools/mailer/composer/autoload_psr4.php | 22 + tools/mailer/composer/autoload_real.php | 80 + tools/mailer/composer/autoload_static.php | 113 + tools/mailer/composer/installed.json | 1059 +++ tools/mailer/composer/installed.php | 161 + tools/mailer/composer/platform_check.php | 26 + tools/mailer/doctrine/lexer/LICENSE | 19 + tools/mailer/doctrine/lexer/README.md | 9 + tools/mailer/doctrine/lexer/UPGRADE.md | 22 + tools/mailer/doctrine/lexer/composer.json | 55 + .../doctrine/lexer/src/AbstractLexer.php | 328 + tools/mailer/doctrine/lexer/src/Token.php | 56 + .../egulias/email-validator/CHANGELOG.md | 32 + .../egulias/email-validator/CONTRIBUTING.md | 153 + tools/mailer/egulias/email-validator/LICENSE | 19 + .../egulias/email-validator/composer.json | 37 + .../email-validator/src/EmailLexer.php | 330 + .../email-validator/src/EmailParser.php | 90 + .../email-validator/src/EmailValidator.php | 67 + .../email-validator/src/MessageIDParser.php | 91 + .../egulias/email-validator/src/Parser.php | 78 + .../email-validator/src/Parser/Comment.php | 102 + .../CommentStrategy/CommentStrategy.php | 22 + .../Parser/CommentStrategy/DomainComment.php | 33 + .../Parser/CommentStrategy/LocalComment.php | 37 + .../src/Parser/DomainLiteral.php | 210 + .../email-validator/src/Parser/DomainPart.php | 326 + .../src/Parser/DoubleQuote.php | 91 + .../src/Parser/FoldingWhiteSpace.php | 87 + .../email-validator/src/Parser/IDLeftPart.php | 15 + .../src/Parser/IDRightPart.php | 29 + .../email-validator/src/Parser/LocalPart.php | 162 + .../email-validator/src/Parser/PartParser.php | 63 + .../src/Result/InvalidEmail.php | 49 + .../src/Result/MultipleErrors.php | 56 + .../src/Result/Reason/AtextAfterCFWS.php | 16 + .../src/Result/Reason/CRLFAtTheEnd.php | 19 + .../src/Result/Reason/CRLFX2.php | 16 + .../src/Result/Reason/CRNoLF.php | 16 + .../src/Result/Reason/CharNotAllowed.php | 16 + .../src/Result/Reason/CommaInDomain.php | 16 + .../src/Result/Reason/CommentsInIDRight.php | 16 + .../src/Result/Reason/ConsecutiveAt.php | 17 + .../src/Result/Reason/ConsecutiveDot.php | 16 + .../src/Result/Reason/DetailedReason.php | 13 + .../src/Result/Reason/DomainAcceptsNoMail.php | 16 + .../src/Result/Reason/DomainHyphened.php | 16 + .../src/Result/Reason/DomainTooLong.php | 16 + .../src/Result/Reason/DotAtEnd.php | 16 + .../src/Result/Reason/DotAtStart.php | 16 + .../src/Result/Reason/EmptyReason.php | 16 + .../src/Result/Reason/ExceptionFound.php | 26 + .../src/Result/Reason/ExpectingATEXT.php | 16 + .../src/Result/Reason/ExpectingCTEXT.php | 16 + .../src/Result/Reason/ExpectingDTEXT.php | 16 + .../Reason/ExpectingDomainLiteralClose.php | 16 + .../src/Result/Reason/LabelTooLong.php | 16 + .../Result/Reason/LocalOrReservedDomain.php | 16 + .../src/Result/Reason/NoDNSRecord.php | 16 + .../src/Result/Reason/NoDomainPart.php | 16 + .../src/Result/Reason/NoLocalPart.php | 16 + .../src/Result/Reason/RFCWarnings.php | 16 + .../src/Result/Reason/Reason.php | 16 + .../src/Result/Reason/SpoofEmail.php | 17 + .../src/Result/Reason/UnOpenedComment.php | 16 + .../Result/Reason/UnableToGetDNSRecord.php | 19 + .../src/Result/Reason/UnclosedComment.php | 16 + .../Result/Reason/UnclosedQuotedString.php | 16 + .../src/Result/Reason/UnusualElements.php | 26 + .../email-validator/src/Result/Result.php | 27 + .../email-validator/src/Result/SpoofEmail.php | 13 + .../email-validator/src/Result/ValidEmail.php | 27 + .../src/Validation/DNSCheckValidation.php | 211 + .../src/Validation/DNSGetRecordWrapper.php | 31 + .../src/Validation/DNSRecords.php | 27 + .../src/Validation/EmailValidation.php | 34 + .../Exception/EmptyValidationList.php | 16 + .../Validation/Extra/SpoofCheckValidation.php | 49 + .../src/Validation/MessageIDValidation.php | 55 + .../Validation/MultipleValidationWithAnd.php | 105 + .../Validation/NoRFCWarningsValidation.php | 41 + .../src/Validation/RFCValidation.php | 54 + .../src/Warning/AddressLiteral.php | 14 + .../src/Warning/CFWSNearAt.php | 13 + .../src/Warning/CFWSWithFWS.php | 13 + .../email-validator/src/Warning/Comment.php | 13 + .../src/Warning/DeprecatedComment.php | 13 + .../src/Warning/DomainLiteral.php | 14 + .../src/Warning/EmailTooLong.php | 15 + .../src/Warning/IPV6BadChar.php | 14 + .../src/Warning/IPV6ColonEnd.php | 14 + .../src/Warning/IPV6ColonStart.php | 14 + .../src/Warning/IPV6Deprecated.php | 14 + .../src/Warning/IPV6DoubleColon.php | 14 + .../src/Warning/IPV6GroupCount.php | 14 + .../src/Warning/IPV6MaxGroups.php | 14 + .../src/Warning/LocalTooLong.php | 15 + .../src/Warning/NoDNSMXRecord.php | 14 + .../src/Warning/ObsoleteDTEXT.php | 14 + .../src/Warning/QuotedPart.php | 17 + .../src/Warning/QuotedString.php | 17 + .../email-validator/src/Warning/TLD.php | 13 + .../email-validator/src/Warning/Warning.php | 53 + tools/mailer/psr/container/.gitignore | 3 + tools/mailer/psr/container/LICENSE | 21 + tools/mailer/psr/container/README.md | 13 + tools/mailer/psr/container/composer.json | 27 + .../src/ContainerExceptionInterface.php | 12 + .../psr/container/src/ContainerInterface.php | 36 + .../src/NotFoundExceptionInterface.php | 10 + .../mailer/psr/event-dispatcher/.editorconfig | 15 + tools/mailer/psr/event-dispatcher/.gitignore | 2 + tools/mailer/psr/event-dispatcher/LICENSE | 21 + tools/mailer/psr/event-dispatcher/README.md | 6 + .../mailer/psr/event-dispatcher/composer.json | 26 + .../src/EventDispatcherInterface.php | 21 + .../src/ListenerProviderInterface.php | 19 + .../src/StoppableEventInterface.php | 26 + tools/mailer/psr/log/LICENSE | 19 + tools/mailer/psr/log/README.md | 58 + tools/mailer/psr/log/composer.json | 26 + tools/mailer/psr/log/src/AbstractLogger.php | 15 + .../psr/log/src/InvalidArgumentException.php | 7 + tools/mailer/psr/log/src/LogLevel.php | 18 + .../psr/log/src/LoggerAwareInterface.php | 14 + tools/mailer/psr/log/src/LoggerAwareTrait.php | 22 + tools/mailer/psr/log/src/LoggerInterface.php | 98 + tools/mailer/psr/log/src/LoggerTrait.php | 98 + tools/mailer/psr/log/src/NullLogger.php | 26 + .../deprecation-contracts/CHANGELOG.md | 5 + .../symfony/deprecation-contracts}/LICENSE | 2 +- .../symfony/deprecation-contracts/README.md | 26 + .../deprecation-contracts/composer.json | 35 + .../deprecation-contracts/function.php | 27 + .../event-dispatcher-contracts/CHANGELOG.md | 5 + .../event-dispatcher-contracts/Event.php | 51 + .../EventDispatcherInterface.php | 33 + .../event-dispatcher-contracts/LICENSE | 19 + .../event-dispatcher-contracts/README.md | 9 + .../event-dispatcher-contracts/composer.json | 35 + .../Attribute/AsEventListener.php | 35 + .../symfony/event-dispatcher/CHANGELOG.md | 96 + .../Debug/TraceableEventDispatcher.php | 351 + .../Debug/WrappedListener.php | 143 + .../AddEventAliasesPass.php | 38 + .../RegisterListenersPass.php | 213 + .../event-dispatcher/EventDispatcher.php | 256 + .../EventDispatcherInterface.php | 66 + .../EventSubscriberInterface.php | 49 + .../symfony/event-dispatcher/GenericEvent.php | 155 + .../ImmutableEventDispatcher.php | 65 + tools/mailer/symfony/event-dispatcher/LICENSE | 19 + .../mailer/symfony/event-dispatcher/README.md | 15 + .../symfony/event-dispatcher/composer.json | 47 + tools/mailer/symfony/mailer/CHANGELOG.md | 98 + .../mailer/Command/MailerTestCommand.php | 75 + .../DataCollector/MessageDataCollector.php | 59 + .../mailer/symfony/mailer/DelayedEnvelope.php | 98 + tools/mailer/symfony/mailer/Envelope.php | 88 + .../mailer/Event/FailedMessageEvent.php | 37 + .../symfony/mailer/Event/MessageEvent.php | 105 + .../symfony/mailer/Event/MessageEvents.php | 74 + .../symfony/mailer/Event/SentMessageEvent.php | 30 + .../mailer/EventListener/EnvelopeListener.php | 71 + .../mailer/EventListener/MessageListener.php | 134 + .../EventListener/MessageLoggerListener.php | 57 + .../MessengerTransportListener.php | 49 + .../mailer/Exception/ExceptionInterface.php | 21 + .../Exception/HttpTransportException.php | 34 + .../Exception/IncompleteDsnException.php | 19 + .../Exception/InvalidArgumentException.php | 19 + .../mailer/Exception/LogicException.php | 19 + .../mailer/Exception/RuntimeException.php | 19 + .../mailer/Exception/TransportException.php | 30 + .../Exception/TransportExceptionInterface.php | 22 + .../Exception/UnexpectedResponseException.php | 16 + .../Exception/UnsupportedSchemeException.php | 101 + .../symfony/mailer/Header/MetadataHeader.php | 34 + .../symfony/mailer/Header/TagHeader.php | 25 + tools/mailer/symfony/mailer/LICENSE | 19 + tools/mailer/symfony/mailer/Mailer.php | 76 + .../mailer/symfony/mailer/MailerInterface.php | 30 + .../mailer/Messenger/MessageHandler.php | 33 + .../mailer/Messenger/SendEmailMessage.php | 40 + tools/mailer/symfony/mailer/README.md | 74 + tools/mailer/symfony/mailer/SentMessage.php | 95 + .../mailer/Test/Constraint/EmailCount.php | 65 + .../mailer/Test/Constraint/EmailIsQueued.php | 39 + .../mailer/Test/TransportFactoryTestCase.php | 117 + tools/mailer/symfony/mailer/Transport.php | 188 + .../mailer/Transport/AbstractApiTransport.php | 47 + .../Transport/AbstractHttpTransport.php | 78 + .../mailer/Transport/AbstractTransport.php | 136 + .../Transport/AbstractTransportFactory.php | 51 + tools/mailer/symfony/mailer/Transport/Dsn.php | 89 + .../mailer/Transport/FailoverTransport.php | 41 + .../Transport/NativeTransportFactory.php | 63 + .../mailer/Transport/NullTransport.php | 31 + .../mailer/Transport/NullTransportFactory.php | 34 + .../mailer/Transport/RoundRobinTransport.php | 125 + .../mailer/Transport/SendmailTransport.php | 124 + .../Transport/SendmailTransportFactory.php | 34 + .../Smtp/Auth/AuthenticatorInterface.php | 35 + .../Smtp/Auth/CramMd5Authenticator.php | 65 + .../Smtp/Auth/LoginAuthenticator.php | 37 + .../Smtp/Auth/PlainAuthenticator.php | 35 + .../Smtp/Auth/XOAuth2Authenticator.php | 37 + .../mailer/Transport/Smtp/EsmtpTransport.php | 228 + .../Transport/Smtp/EsmtpTransportFactory.php | 78 + .../mailer/Transport/Smtp/SmtpTransport.php | 392 + .../Transport/Smtp/Stream/AbstractStream.php | 145 + .../Transport/Smtp/Stream/ProcessStream.php | 81 + .../Transport/Smtp/Stream/SocketStream.php | 193 + .../Transport/TransportFactoryInterface.php | 29 + .../mailer/Transport/TransportInterface.php | 33 + .../symfony/mailer/Transport/Transports.php | 75 + tools/mailer/symfony/mailer/composer.json | 47 + tools/mailer/symfony/mime/Address.php | 120 + .../symfony/mime/BodyRendererInterface.php | 20 + tools/mailer/symfony/mime/CHANGELOG.md | 57 + tools/mailer/symfony/mime/CharacterStream.php | 211 + .../symfony/mime/Crypto/DkimOptions.php | 97 + .../mailer/symfony/mime/Crypto/DkimSigner.php | 217 + tools/mailer/symfony/mime/Crypto/SMime.php | 111 + .../symfony/mime/Crypto/SMimeEncrypter.php | 63 + .../symfony/mime/Crypto/SMimeSigner.php | 65 + .../AddMimeTypeGuesserPass.php | 34 + tools/mailer/symfony/mime/DraftEmail.php | 45 + tools/mailer/symfony/mime/Email.php | 576 ++ .../mime/Encoder/AddressEncoderInterface.php | 28 + .../mime/Encoder/Base64ContentEncoder.php | 45 + .../symfony/mime/Encoder/Base64Encoder.php | 41 + .../mime/Encoder/Base64MimeHeaderEncoder.php | 43 + .../mime/Encoder/ContentEncoderInterface.php | 30 + .../mime/Encoder/EightBitContentEncoder.php | 35 + .../symfony/mime/Encoder/EncoderInterface.php | 26 + .../mime/Encoder/IdnAddressEncoder.php | 44 + .../Encoder/MimeHeaderEncoderInterface.php} | 15 +- .../symfony/mime/Encoder/QpContentEncoder.php | 55 + .../symfony/mime}/Encoder/QpEncoder.php | 188 +- .../mime/Encoder/QpMimeHeaderEncoder.php | 40 + .../symfony/mime/Encoder/Rfc2231Encoder.php | 50 + .../Exception/AddressEncoderException.php | 19 + .../mime/Exception/ExceptionInterface.php | 19 + .../Exception/InvalidArgumentException.php | 19 + .../symfony/mime/Exception/LogicException.php | 19 + .../mime/Exception/RfcComplianceException.php | 19 + .../mime/Exception/RuntimeException.php | 19 + .../mime/FileBinaryMimeTypeGuesser.php | 85 + .../symfony/mime/FileinfoMimeTypeGuesser.php | 61 + .../symfony/mime/Header/AbstractHeader.php | 294 + .../mailer/symfony/mime/Header/DateHeader.php | 62 + .../symfony/mime/Header/HeaderInterface.php | 61 + tools/mailer/symfony/mime/Header/Headers.php | 316 + .../mime/Header/IdentificationHeader.php | 107 + .../symfony/mime/Header/MailboxHeader.php | 85 + .../symfony/mime/Header/MailboxListHeader.php | 136 + .../mime/Header/ParameterizedHeader.php | 191 + .../mailer/symfony/mime/Header/PathHeader.php | 62 + .../mime/Header/UnstructuredHeader.php | 66 + .../DefaultHtmlToTextConverter.php | 23 + .../HtmlToTextConverterInterface.php | 25 + .../LeagueHtmlToMarkdownConverter.php | 35 + tools/mailer/symfony/mime/LICENSE | 19 + tools/mailer/symfony/mime/Message.php | 163 + .../mailer/symfony/mime/MessageConverter.php | 122 + .../symfony/mime/MimeTypeGuesserInterface.php | 33 + tools/mailer/symfony/mime/MimeTypes.php | 3703 +++++++++ .../symfony/mime/MimeTypesInterface.php | 32 + .../mime/Part/AbstractMultipartPart.php | 95 + .../mailer/symfony/mime/Part/AbstractPart.php | 65 + tools/mailer/symfony/mime/Part/DataPart.php | 165 + tools/mailer/symfony/mime/Part/File.php | 51 + .../mailer/symfony/mime/Part/MessagePart.php | 69 + .../mime/Part/Multipart/AlternativePart.php | 25 + .../mime/Part/Multipart/DigestPart.php | 31 + .../mime/Part/Multipart/FormDataPart.php | 105 + .../symfony/mime/Part/Multipart/MixedPart.php | 25 + .../mime/Part/Multipart/RelatedPart.php | 55 + tools/mailer/symfony/mime/Part/SMimePart.php | 105 + tools/mailer/symfony/mime/Part/TextPart.php | 245 + tools/mailer/symfony/mime/README.md | 13 + tools/mailer/symfony/mime/RawMessage.php | 110 + .../Test/Constraint/EmailAddressContains.php | 64 + .../Test/Constraint/EmailAttachmentCount.php | 50 + .../mime/Test/Constraint/EmailHasHeader.php | 48 + .../mime/Test/Constraint/EmailHeaderSame.php | 59 + .../Test/Constraint/EmailHtmlBodyContains.php | 49 + .../Test/Constraint/EmailSubjectContains.php | 47 + .../Test/Constraint/EmailTextBodyContains.php | 49 + tools/mailer/symfony/mime/composer.json | 47 + .../mailer/symfony/polyfill-intl-idn/Idn.php | 933 +++ .../mailer/symfony/polyfill-intl-idn/Info.php | 23 + .../mailer/symfony/polyfill-intl-idn/LICENSE | 19 + .../symfony/polyfill-intl-idn/README.md | 12 + .../Resources/unidata/DisallowedRanges.php | 384 + .../Resources/unidata/Regex.php | 33 + .../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 | 145 + .../symfony/polyfill-intl-idn/bootstrap80.php | 125 + .../symfony/polyfill-intl-idn/composer.json | 40 + .../symfony/polyfill-intl-normalizer/LICENSE | 19 + .../polyfill-intl-normalizer/Normalizer.php | 310 + .../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 | 23 + .../polyfill-intl-normalizer/bootstrap80.php | 19 + .../polyfill-intl-normalizer/composer.json | 36 + .../mailer/symfony/polyfill-mbstring/LICENSE | 19 + .../symfony/polyfill-mbstring/Mbstring.php | 1045 +++ .../symfony/polyfill-mbstring/README.md | 13 + .../Resources/unidata/caseFolding.php | 119 + .../Resources/unidata/lowerCase.php | 1397 ++++ .../Resources/unidata/titleCaseRegexp.php | 5 + .../Resources/unidata/upperCase.php | 1489 ++++ .../symfony/polyfill-mbstring/bootstrap.php | 172 + .../symfony/polyfill-mbstring/bootstrap80.php | 167 + .../symfony/polyfill-mbstring/composer.json | 38 + .../service-contracts/Attribute/Required.php | 25 + .../Attribute/SubscribedService.php | 47 + .../symfony/service-contracts/CHANGELOG.md | 5 + .../mailer/symfony/service-contracts/LICENSE | 19 + .../symfony/service-contracts/README.md | 9 + .../service-contracts/ResetInterface.php | 33 + .../ServiceCollectionInterface.php | 26 + .../service-contracts/ServiceLocatorTrait.php | 115 + .../ServiceMethodsSubscriberTrait.php | 80 + .../ServiceProviderInterface.php | 45 + .../ServiceSubscriberInterface.php | 62 + .../ServiceSubscriberTrait.php | 84 + .../Test/ServiceLocatorTest.php | 23 + .../Test/ServiceLocatorTestCase.php | 96 + .../symfony/service-contracts/composer.json | 42 + tools/minify_html/LICENSE | 26 + tools/minify_html/minify_html.class.php | 107 +- tools/mobile_Detect/LICENSE | 48 - tools/mobile_Detect/Mobile_Detect.php | 1290 ---- tools/mobile_Detect/index.php | 35 - .../.htaccess | 0 tools/mobile_detect/autoload.php | 7 + tools/mobile_detect/composer/ClassLoader.php | 572 ++ .../composer/InstalledVersions.php | 350 + tools/mobile_detect/composer/LICENSE | 21 + .../composer/autoload_classmap.php | 10 + .../composer/autoload_namespaces.php | 9 + .../mobile_detect/composer/autoload_psr4.php | 12 + .../mobile_detect/composer/autoload_real.php | 57 + .../composer/autoload_static.php | 49 + tools/mobile_detect/composer/installed.json | 180 + tools/mobile_detect/composer/installed.php | 50 + .../mobile_detect/composer/platform_check.php | 26 + .../mobiledetect/mobiledetectlib/CHANGELOG.md | 72 + .../mobiledetect/mobiledetectlib/CNAME | 1 + .../mobiledetectlib/CONTRIBUTING.md | 149 + .../mobiledetectlib/KNOWN_LIMITATIONS.md | 15 + .../mobiledetect/mobiledetectlib/LICENSE | 21 + .../mobiledetectlib/MobileDetect.json | 435 ++ .../mobiledetect/mobiledetectlib/README.md | 63 + .../mobiledetect/mobiledetectlib/SECURITY.md | 18 + .../mobiledetectlib/composer.json | 41 + .../mobiledetectlib/docker-compose.yml | 62 + .../mobiledetectlib/docker/Dockerfile.setup | 9 + .../mobiledetectlib/docker/build.sh | 6 + .../mobiledetectlib/phpbench.json | 4 + .../mobiledetectlib/src/Cache/Cache.php | 104 + .../src/Cache/CacheException.php | 16 + .../mobiledetectlib/src/Cache/CacheItem.php | 127 + .../src/Exception/MobileDetectException.php | 7 + .../mobiledetectlib/src/MobileDetect.php | 1756 +++++ tools/mobile_detect/psr/cache/CHANGELOG.md | 16 + tools/mobile_detect/psr/cache/LICENSE.txt | 19 + tools/mobile_detect/psr/cache/README.md | 12 + tools/mobile_detect/psr/cache/composer.json | 25 + .../psr/cache/src/CacheException.php | 10 + .../psr/cache/src/CacheItemInterface.php | 105 + .../psr/cache/src/CacheItemPoolInterface.php | 138 + .../cache/src/InvalidArgumentException.php | 13 + .../psr/simple-cache/.editorconfig | 12 + .../mobile_detect/psr/simple-cache/LICENSE.md | 21 + .../mobile_detect/psr/simple-cache/README.md | 8 + .../psr/simple-cache/composer.json | 25 + .../psr/simple-cache/src/CacheException.php | 10 + .../psr/simple-cache/src/CacheInterface.php | 114 + .../src/InvalidArgumentException.php | 13 + tools/parser_sql/PHPSQLCreator.php | 2 + .../parser_sql/builders/ColumnTypeBuilder.php | 16 + .../builders/FulltextIndexBuilder.php | 99 + tools/parser_sql/builders/FunctionBuilder.php | 8 +- tools/parser_sql/builders/OrderByBuilder.php | 2 +- .../builders/OrderByPositionBuilder.php | 66 + .../TableBracketExpressionBuilder.php | 12 + .../builders/UniqueIndexBuilder.php | 97 + tools/parser_sql/builders/index.php | 29 - tools/parser_sql/exceptions/index.php | 29 - tools/parser_sql/index.php | 29 - tools/parser_sql/lexer/PHPSQLLexer.php | 2 +- tools/parser_sql/lexer/index.php | 29 - .../positions/PositionCalculator.php | 16 +- tools/parser_sql/positions/index.php | 29 - .../processors/AbstractProcessor.php | 2 +- .../processors/ColumnDefinitionProcessor.php | 37 +- .../processors/ExpressionListProcessor.php | 11 +- tools/parser_sql/processors/FromProcessor.php | 32 +- .../parser_sql/processors/IndexProcessor.php | 5 +- tools/parser_sql/processors/SQLProcessor.php | 20 +- .../parser_sql/processors/TableProcessor.php | 5 +- tools/parser_sql/processors/index.php | 29 - .../utils/PHPSQLParserConstants.php | 4 +- tools/parser_sql/utils/index.php | 29 - tools/pear/LICENSE | 87 +- tools/pear/OS/Guess.php | 254 +- tools/pear/PEAR.php | 9 +- tools/pear/PEAR/ErrorStack.php | 138 +- tools/pear/System.php | 6 +- tools/profiling/Controller.php | 4 +- tools/profiling/Tools.php | 2 +- tools/random_compat/build-phar.sh | 5 + tools/random_compat/composer.json | 38 - tools/random_compat/dist/index.php | 29 - tools/random_compat/index.php | 29 - tools/random_compat/lib/byte_safe_strings.php | 195 - tools/random_compat/lib/cast_to_int.php | 77 - tools/random_compat/lib/error_polyfill.php | 49 - tools/random_compat/lib/index.php | 29 - tools/random_compat/lib/random.php | 200 +- .../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 - tools/random_compat/lib/random_int.php | 204 - tools/random_compat/other/build_phar.php | 57 + tools/random_compat/psalm-autoload.php | 9 + tools/random_compat/psalm.xml | 19 + tools/smarty/.htaccess | 10 - tools/smarty/Autoloader.php | 17 +- tools/smarty/CHANGELOG.md | 3466 --------- tools/smarty/LICENSE | 179 - tools/smarty/README.md | 78 - tools/smarty/Smarty.class.php | 115 +- tools/smarty/SmartyBC.class.php | 477 -- tools/smarty/bootstrap.php | 2 +- tools/smarty/debug.tpl | 57 +- tools/smarty/functions.php | 51 + tools/smarty/index.php | 29 - tools/smarty/plugins/block.textformat.php | 2 +- tools/smarty/plugins/function.counter.php | 2 +- tools/smarty/plugins/function.cycle.php | 2 +- tools/smarty/plugins/function.fetch.php | 2 +- .../plugins/function.html_checkboxes.php | 2 +- tools/smarty/plugins/function.html_image.php | 2 +- .../smarty/plugins/function.html_options.php | 2 +- tools/smarty/plugins/function.html_radios.php | 2 +- .../plugins/function.html_select_date.php | 75 +- .../plugins/function.html_select_time.php | 2 +- tools/smarty/plugins/function.html_table.php | 2 +- tools/smarty/plugins/function.mailto.php | 37 +- tools/smarty/plugins/function.math.php | 34 +- tools/smarty/plugins/index.php | 29 - tools/smarty/plugins/modifier.capitalize.php | 2 + tools/smarty/plugins/modifier.count.php | 36 + tools/smarty/plugins/modifier.date_format.php | 5 +- tools/smarty/plugins/modifier.escape.php | 98 +- tools/smarty/plugins/modifier.explode.php | 25 + tools/smarty/plugins/modifier.implode.php | 15 + tools/smarty/plugins/modifier.mb_wordwrap.php | 2 +- .../smarty/plugins/modifier.number_format.php | 26 + .../smarty/plugins/modifier.regex_replace.php | 2 +- tools/smarty/plugins/modifier.replace.php | 2 +- tools/smarty/plugins/modifier.spacify.php | 2 +- tools/smarty/plugins/modifier.truncate.php | 10 +- tools/smarty/plugins/modifiercompiler.cat.php | 2 +- .../modifiercompiler.count_characters.php | 6 +- .../modifiercompiler.count_paragraphs.php | 2 +- .../modifiercompiler.count_sentences.php | 2 +- .../plugins/modifiercompiler.count_words.php | 4 +- .../plugins/modifiercompiler.default.php | 4 +- .../plugins/modifiercompiler.escape.php | 59 +- .../plugins/modifiercompiler.indent.php | 2 +- .../plugins/modifiercompiler.json_encode.php | 11 + .../smarty/plugins/modifiercompiler.lower.php | 6 +- .../smarty/plugins/modifiercompiler.nl2br.php | 23 + .../smarty/plugins/modifiercompiler.round.php | 23 + .../plugins/modifiercompiler.str_repeat.php | 23 + .../modifiercompiler.string_format.php | 2 +- .../smarty/plugins/modifiercompiler.strip.php | 2 +- .../plugins/modifiercompiler.strip_tags.php | 6 +- .../plugins/modifiercompiler.strlen.php | 23 + .../plugins/modifiercompiler.substr.php | 12 + .../plugins/modifiercompiler.unescape.php | 26 +- .../smarty/plugins/modifiercompiler.upper.php | 6 +- .../plugins/modifiercompiler.wordwrap.php | 2 +- .../plugins/outputfilter.trimwhitespace.php | 4 +- .../plugins/shared.escape_special_chars.php | 8 +- .../smarty/plugins/shared.mb_str_replace.php | 36 +- .../variablefilter.htmlspecialchars.php | 2 +- tools/smarty/sysplugins/index.php | 29 - .../sysplugins/smarty_cacheresource.php | 12 +- .../smarty_cacheresource_custom.php | 8 +- .../smarty_cacheresource_keyvaluestore.php | 12 +- .../smarty_internal_cacheresource_file.php | 16 +- .../smarty_internal_compile_block.php | 4 +- .../smarty_internal_compile_extends.php | 66 +- .../smarty_internal_compile_for.php | 2 +- .../smarty_internal_compile_foreach.php | 4 +- .../smarty_internal_compile_function.php | 10 +- .../smarty_internal_compile_include.php | 4 +- .../smarty_internal_compile_include_php.php | 110 - .../smarty_internal_compile_insert.php | 4 +- ...nternal_compile_private_foreachsection.php | 6 +- ...arty_internal_compile_private_modifier.php | 5 + .../smarty_internal_compile_private_php.php | 253 - ...ernal_compile_private_print_expression.php | 2 +- ...ernal_compile_private_special_variable.php | 6 +- .../smarty_internal_config_file_compiler.php | 10 +- .../sysplugins/smarty_internal_data.php | 28 +- .../sysplugins/smarty_internal_debug.php | 13 +- .../smarty_internal_errorhandler.php | 149 +- .../smarty_internal_extension_handler.php | 28 +- .../smarty_internal_method_append.php | 2 +- .../smarty_internal_method_appendbyref.php | 2 +- .../smarty_internal_method_clearallassign.php | 2 +- .../smarty_internal_method_clearallcache.php | 2 +- .../smarty_internal_method_clearassign.php | 2 +- .../smarty_internal_method_clearcache.php | 2 +- ..._internal_method_clearcompiledtemplate.php | 2 +- .../smarty_internal_method_clearconfig.php | 2 +- .../smarty_internal_method_configload.php | 4 +- .../smarty_internal_method_createdata.php | 12 +- .../smarty_internal_method_getconfigvars.php | 2 +- ...ty_internal_method_getregisteredobject.php | 2 +- .../smarty_internal_method_gettags.php | 2 +- ...smarty_internal_method_gettemplatevars.php | 14 +- .../smarty_internal_method_loadfilter.php | 2 +- .../smarty_internal_method_loadplugin.php | 4 +- .../smarty_internal_method_mustcompile.php | 2 +- ..._internal_method_registercacheresource.php | 2 +- .../smarty_internal_method_registerclass.php | 2 +- ...al_method_registerdefaultpluginhandler.php | 2 +- .../smarty_internal_method_registerfilter.php | 2 +- .../smarty_internal_method_registerobject.php | 2 +- .../smarty_internal_method_registerplugin.php | 2 +- ...marty_internal_method_registerresource.php | 15 +- .../smarty_internal_method_unloadfilter.php | 2 +- ...nternal_method_unregistercacheresource.php | 2 +- ...marty_internal_method_unregisterfilter.php | 2 +- ...marty_internal_method_unregisterobject.php | 2 +- ...marty_internal_method_unregisterplugin.php | 2 +- ...rty_internal_method_unregisterresource.php | 2 +- .../smarty_internal_parsetree_template.php | 138 +- .../smarty_internal_parsetree_text.php | 34 +- .../smarty_internal_resource_eval.php | 4 +- .../smarty_internal_resource_extends.php | 4 +- .../smarty_internal_resource_file.php | 8 +- .../smarty_internal_resource_registered.php | 101 - .../smarty_internal_resource_stream.php | 6 +- .../smarty_internal_resource_string.php | 4 +- .../smarty_internal_runtime_codeframe.php | 21 +- .../smarty_internal_runtime_inheritance.php | 2 +- .../smarty_internal_runtime_make_nocache.php | 2 +- .../smarty_internal_runtime_writefile.php | 15 +- .../sysplugins/smarty_internal_template.php | 7 +- .../smarty_internal_templatebase.php | 27 +- .../smarty_internal_templatecompilerbase.php | 122 +- .../smarty_internal_templatelexer.php | 652 +- .../smarty_internal_templateparser.php | 5338 ++++++------- .../smarty_internal_testinstall.php | 6 +- tools/smarty/sysplugins/smarty_resource.php | 24 +- .../sysplugins/smarty_resource_custom.php | 21 +- tools/smarty/sysplugins/smarty_security.php | 49 +- .../sysplugins/smarty_template_compiled.php | 2 +- .../sysplugins/smarty_template_config.php | 10 +- .../sysplugins/smarty_template_source.php | 10 +- tools/smarty/sysplugins/smarty_variable.php | 1 + .../sysplugins/smartycompilerexception.php | 36 +- tools/swift/.htaccess | 10 - tools/swift/CHANGES | 287 - tools/swift/README | 15 - tools/swift/VERSION | 1 - tools/swift/classes/Swift.php | 80 - tools/swift/classes/Swift/Attachment.php | 71 - .../AbstractFilterableInputStream.php | 181 - .../Swift/ByteStream/ArrayByteStream.php | 182 - .../Swift/ByteStream/FileByteStream.php | 231 - .../ByteStream/TemporaryFileByteStream.php | 42 - tools/swift/classes/Swift/CharacterReader.php | 67 - .../GenericFixedWidthReader.php | 97 - .../Swift/CharacterReader/UsAsciiReader.php | 84 - .../Swift/CharacterReader/Utf8Reader.php | 176 - .../classes/Swift/CharacterReaderFactory.php | 26 - .../SimpleCharacterReaderFactory.php | 124 - tools/swift/classes/Swift/CharacterStream.php | 89 - .../CharacterStream/ArrayCharacterStream.php | 293 - .../CharacterStream/NgCharacterStream.php | 267 - .../swift/classes/Swift/ConfigurableSpool.php | 63 - .../classes/Swift/DependencyContainer.php | 373 - .../classes/Swift/DependencyException.php | 27 - tools/swift/classes/Swift/EmbeddedFile.php | 69 - tools/swift/classes/Swift/Encoder.php | 28 - .../classes/Swift/Encoder/Base64Encoder.php | 58 - .../classes/Swift/Encoder/Rfc2231Encoder.php | 92 - tools/swift/classes/Swift/Encoding.php | 62 - .../classes/Swift/Events/CommandEvent.php | 65 - .../classes/Swift/Events/CommandListener.php | 24 - tools/swift/classes/Swift/Events/Event.php | 38 - .../classes/Swift/Events/EventDispatcher.php | 83 - .../classes/Swift/Events/EventListener.php | 18 - .../classes/Swift/Events/EventObject.php | 63 - .../classes/Swift/Events/ResponseEvent.php | 65 - .../classes/Swift/Events/ResponseListener.php | 24 - .../swift/classes/Swift/Events/SendEvent.php | 129 - .../classes/Swift/Events/SendListener.php | 31 - .../Swift/Events/SimpleEventDispatcher.php | 156 - .../Swift/Events/TransportChangeEvent.php | 27 - .../Swift/Events/TransportChangeListener.php | 45 - .../Swift/Events/TransportExceptionEvent.php | 46 - .../Events/TransportExceptionListener.php | 24 - .../swift/classes/Swift/FailoverTransport.php | 45 - tools/swift/classes/Swift/FileSpool.php | 208 - tools/swift/classes/Swift/FileStream.php | 24 - tools/swift/classes/Swift/Filterable.php | 32 - tools/swift/classes/Swift/Image.php | 57 - tools/swift/classes/Swift/InputByteStream.php | 75 - tools/swift/classes/Swift/IoException.php | 29 - tools/swift/classes/Swift/KeyCache.php | 105 - .../classes/Swift/KeyCache/ArrayKeyCache.php | 206 - .../classes/Swift/KeyCache/DiskKeyCache.php | 321 - .../Swift/KeyCache/KeyCacheInputStream.php | 51 - .../classes/Swift/KeyCache/NullKeyCache.php | 115 - .../KeyCache/SimpleKeyCacheInputStream.php | 127 - .../classes/Swift/LoadBalancedTransport.php | 45 - tools/swift/classes/Swift/MailTransport.php | 47 - tools/swift/classes/Swift/Mailer.php | 114 - .../Swift/Mailer/ArrayRecipientIterator.php | 55 - .../Swift/Mailer/RecipientIterator.php | 32 - tools/swift/classes/Swift/MemorySpool.php | 110 - tools/swift/classes/Swift/Message.php | 289 - tools/swift/classes/Swift/Mime/Attachment.php | 149 - .../classes/Swift/Mime/CharsetObserver.php | 24 - .../classes/Swift/Mime/ContentEncoder.php | 34 - .../ContentEncoder/Base64ContentEncoder.php | 104 - .../ContentEncoder/NativeQpContentEncoder.php | 123 - .../ContentEncoder/PlainContentEncoder.php | 162 - .../Mime/ContentEncoder/QpContentEncoder.php | 134 - .../ContentEncoder/QpContentEncoderProxy.php | 98 - .../Mime/ContentEncoder/RawContentEncoder.php | 64 - .../swift/classes/Swift/Mime/EmbeddedFile.php | 45 - .../classes/Swift/Mime/EncodingObserver.php | 24 - tools/swift/classes/Swift/Mime/Grammar.php | 176 - tools/swift/classes/Swift/Mime/Header.php | 93 - .../HeaderEncoder/Base64HeaderEncoder.php | 55 - .../Mime/HeaderEncoder/QpHeaderEncoder.php | 65 - .../classes/Swift/Mime/HeaderFactory.php | 78 - tools/swift/classes/Swift/Mime/HeaderSet.php | 169 - .../Swift/Mime/Headers/AbstractHeader.php | 501 -- .../classes/Swift/Mime/Headers/DateHeader.php | 125 - .../Mime/Headers/IdentificationHeader.php | 180 - .../Swift/Mime/Headers/MailboxHeader.php | 351 - .../Swift/Mime/Headers/OpenDKIMHeader.php | 133 - .../Mime/Headers/ParameterizedHeader.php | 258 - .../classes/Swift/Mime/Headers/PathHeader.php | 143 - .../Swift/Mime/Headers/UnstructuredHeader.php | 112 - tools/swift/classes/Swift/Mime/Message.php | 223 - tools/swift/classes/Swift/Mime/MimeEntity.php | 117 - tools/swift/classes/Swift/Mime/MimePart.php | 212 - .../Swift/Mime/ParameterizedHeader.php | 34 - .../Swift/Mime/SimpleHeaderFactory.php | 193 - .../classes/Swift/Mime/SimpleHeaderSet.php | 414 - .../classes/Swift/Mime/SimpleMessage.php | 655 -- .../classes/Swift/Mime/SimpleMimeEntity.php | 846 --- tools/swift/classes/Swift/MimePart.php | 59 - tools/swift/classes/Swift/NullTransport.php | 36 - .../swift/classes/Swift/OutputByteStream.php | 46 - .../classes/Swift/Plugins/AntiFloodPlugin.php | 141 - .../Swift/Plugins/BandwidthMonitorPlugin.php | 164 - .../Swift/Plugins/Decorator/Replacements.php | 31 - .../classes/Swift/Plugins/DecoratorPlugin.php | 204 - .../Swift/Plugins/ImpersonatePlugin.php | 69 - tools/swift/classes/Swift/Plugins/Logger.php | 36 - .../classes/Swift/Plugins/LoggerPlugin.php | 142 - .../Swift/Plugins/Loggers/ArrayLogger.php | 72 - .../Swift/Plugins/Loggers/EchoLogger.php | 58 - .../classes/Swift/Plugins/MessageLogger.php | 74 - .../Swift/Plugins/Pop/Pop3Connection.php | 31 - .../Swift/Plugins/Pop/Pop3Exception.php | 27 - .../Swift/Plugins/PopBeforeSmtpPlugin.php | 273 - .../Swift/Plugins/RedirectingPlugin.php | 213 - .../swift/classes/Swift/Plugins/Reporter.php | 32 - .../classes/Swift/Plugins/ReporterPlugin.php | 61 - .../Swift/Plugins/Reporters/HitReporter.php | 59 - .../Swift/Plugins/Reporters/HtmlReporter.php | 39 - tools/swift/classes/Swift/Plugins/Sleeper.php | 24 - .../classes/Swift/Plugins/ThrottlerPlugin.php | 200 - tools/swift/classes/Swift/Plugins/Timer.php | 24 - tools/swift/classes/Swift/Preferences.php | 100 - .../Swift/ReplacementFilterFactory.php | 27 - .../classes/Swift/RfcComplianceException.php | 27 - .../swift/classes/Swift/SendmailTransport.php | 45 - tools/swift/classes/Swift/SignedMessage.php | 23 - tools/swift/classes/Swift/Signer.php | 20 - .../classes/Swift/Signers/BodySigner.php | 33 - .../classes/Swift/Signers/DKIMSigner.php | 712 -- .../classes/Swift/Signers/DomainKeySigner.php | 524 -- .../classes/Swift/Signers/HeaderSigner.php | 65 - .../classes/Swift/Signers/OpenDKIMSigner.php | 190 - .../classes/Swift/Signers/SMimeSigner.php | 436 -- tools/swift/classes/Swift/SmtpTransport.php | 58 - tools/swift/classes/Swift/Spool.php | 53 - tools/swift/classes/Swift/SpoolTransport.php | 47 - tools/swift/classes/Swift/StreamFilter.php | 35 - .../ByteArrayReplacementFilter.php | 170 - .../StreamFilters/StringReplacementFilter.php | 70 - .../StringReplacementFilterFactory.php | 45 - tools/swift/classes/Swift/SwiftException.php | 29 - tools/swift/classes/Swift/Transport.php | 54 - .../Swift/Transport/AbstractSmtpTransport.php | 499 -- .../Esmtp/Auth/CramMd5Authenticator.php | 81 - .../Esmtp/Auth/LoginAuthenticator.php | 51 - .../Esmtp/Auth/NTLMAuthenticator.php | 725 -- .../Esmtp/Auth/PlainAuthenticator.php | 50 - .../Esmtp/Auth/XOAuth2Authenticator.php | 70 - .../Swift/Transport/Esmtp/AuthHandler.php | 263 - .../Swift/Transport/Esmtp/Authenticator.php | 35 - .../classes/Swift/Transport/EsmtpHandler.php | 86 - .../Swift/Transport/EsmtpTransport.php | 411 - .../Swift/Transport/FailoverTransport.php | 88 - .../classes/Swift/Transport/IoBuffer.php | 67 - .../Swift/Transport/LoadBalancedTransport.php | 183 - .../classes/Swift/Transport/MailInvoker.php | 32 - .../classes/Swift/Transport/MailTransport.php | 297 - .../classes/Swift/Transport/NullTransport.php | 93 - .../Swift/Transport/SendmailTransport.php | 160 - .../Swift/Transport/SimpleMailInvoker.php | 39 - .../classes/Swift/Transport/SmtpAgent.php | 36 - .../Swift/Transport/SpoolTransport.php | 117 - .../classes/Swift/Transport/StreamBuffer.php | 334 - .../classes/Swift/TransportException.php | 29 - tools/swift/classes/Swift/Validate.php | 43 - tools/swift/dependency_maps/cache_deps.php | 23 - tools/swift/dependency_maps/message_deps.php | 9 - tools/swift/dependency_maps/mime_deps.php | 123 - .../swift/dependency_maps/transport_deps.php | 76 - tools/swift/index.php | 35 - tools/swift/mime_types.php | 1007 --- tools/swift/preferences.php | 25 - tools/swift/swift_init.php | 28 - tools/swift/swift_required.php | 30 - tools/swift/swift_required_pear.php | 30 - .../swiftmailer_generate_mimes_config.php | 193 - tools/tar/Tar.php | 78 +- tools/tcpdf/CHANGELOG.TXT | 203 +- tools/tcpdf/LICENSE.TXT | 2 +- tools/tcpdf/README.md | 7 +- tools/tcpdf/VERSION | 2 +- tools/tcpdf/config/index.php | 35 - tools/tcpdf/config/tcpdf_config.php | 8 + .../examples/barcodes/example_1d_html.php | 57 + .../examples/barcodes/example_1d_png.php | 56 + .../examples/barcodes/example_1d_svg.php | 57 + .../examples/barcodes/example_1d_svgi.php | 57 + .../barcodes/example_2d_datamatrix_html.php | 57 + .../barcodes/example_2d_datamatrix_png.php | 56 + .../barcodes/example_2d_datamatrix_svg.php | 57 + .../barcodes/example_2d_datamatrix_svgi.php | 57 + .../barcodes/example_2d_pdf417_html.php | 57 + .../barcodes/example_2d_pdf417_png.php | 56 + .../barcodes/example_2d_pdf417_svg.php | 57 + .../barcodes/example_2d_pdf417_svgi.php | 57 + .../barcodes/example_2d_qrcode_html.php | 56 + .../barcodes/example_2d_qrcode_png.php | 56 + .../barcodes/example_2d_qrcode_svg.php | 56 + .../barcodes/example_2d_qrcode_svgi.php | 56 + .../barcodes/tcpdf_barcodes_1d_include.php | 46 + .../barcodes/tcpdf_barcodes_2d_include.php | 46 + .../examples/config/tcpdf_config_alt.php | 230 + tools/tcpdf/examples/data/cert/tcpdf.crt | 40 + tools/tcpdf/examples/data/cert/tcpdf.fdf | Bin 0 -> 1286 bytes tools/tcpdf/examples/data/cert/tcpdf.p12 | Bin 0 -> 1749 bytes tools/tcpdf/examples/data/chapter_demo_1.txt | 19 + tools/tcpdf/examples/data/chapter_demo_2.txt | 23 + tools/tcpdf/examples/data/table_data_demo.txt | 15 + tools/tcpdf/examples/data/utf8test.txt | 128 + tools/tcpdf/examples/example_001.php | 110 + tools/tcpdf/examples/example_002.php | 91 + tools/tcpdf/examples/example_003.php | 122 + tools/tcpdf/examples/example_004.php | 123 + tools/tcpdf/examples/example_005.php | 160 + tools/tcpdf/examples/example_006.php | 347 + tools/tcpdf/examples/example_007.php | 117 + tools/tcpdf/examples/example_008.php | 99 + tools/tcpdf/examples/example_009.php | 148 + tools/tcpdf/examples/example_010.php | 152 + tools/tcpdf/examples/example_011.php | 141 + tools/tcpdf/examples/example_012.pdf | Bin 0 -> 13214 bytes tools/tcpdf/examples/example_012.php | 207 + tools/tcpdf/examples/example_013.php | 231 + tools/tcpdf/examples/example_014.php | 197 + tools/tcpdf/examples/example_015.php | 164 + tools/tcpdf/examples/example_016.php | 136 + tools/tcpdf/examples/example_017.php | 120 + tools/tcpdf/examples/example_018.php | 130 + tools/tcpdf/examples/example_019.php | 100 + tools/tcpdf/examples/example_020.php | 149 + tools/tcpdf/examples/example_021.php | 93 + tools/tcpdf/examples/example_022.php | 148 + tools/tcpdf/examples/example_023.php | 115 + tools/tcpdf/examples/example_024.php | 142 + tools/tcpdf/examples/example_025.php | 120 + tools/tcpdf/examples/example_026.php | 146 + tools/tcpdf/examples/example_027.php | 420 + tools/tcpdf/examples/example_028.php | 140 + tools/tcpdf/examples/example_029.php | 126 + tools/tcpdf/examples/example_030.php | 190 + tools/tcpdf/examples/example_031.php | 105 + tools/tcpdf/examples/example_032.php | 93 + tools/tcpdf/examples/example_033.php | 107 + tools/tcpdf/examples/example_034.php | 98 + tools/tcpdf/examples/example_035.php | 113 + tools/tcpdf/examples/example_036.php | 91 + tools/tcpdf/examples/example_037.php | 149 + tools/tcpdf/examples/example_038.php | 94 + tools/tcpdf/examples/example_039.php | 106 + tools/tcpdf/examples/example_040.php | 118 + tools/tcpdf/examples/example_041.php | 93 + tools/tcpdf/examples/example_042.php | 104 + tools/tcpdf/examples/example_043.php | 87 + tools/tcpdf/examples/example_044.php | 130 + tools/tcpdf/examples/example_045.php | 143 + tools/tcpdf/examples/example_046.php | 125 + tools/tcpdf/examples/example_047.php | 119 + tools/tcpdf/examples/example_048.php | 316 + tools/tcpdf/examples/example_049.php | 128 + tools/tcpdf/examples/example_050.php | 212 + tools/tcpdf/examples/example_051.php | 148 + tools/tcpdf/examples/example_052.php | 123 + tools/tcpdf/examples/example_053.php | 110 + tools/tcpdf/examples/example_054.php | 131 + tools/tcpdf/examples/example_055.php | 118 + tools/tcpdf/examples/example_056.php | 135 + tools/tcpdf/examples/example_057.php | 270 + tools/tcpdf/examples/example_058.php | 97 + tools/tcpdf/examples/example_059.php | 193 + tools/tcpdf/examples/example_060.php | 110 + tools/tcpdf/examples/example_061.php | 267 + tools/tcpdf/examples/example_062.php | 142 + tools/tcpdf/examples/example_063.php | 133 + tools/tcpdf/examples/example_064.php | 178 + tools/tcpdf/examples/example_065.php | 100 + tools/tcpdf/examples/example_066.php | 88 + tools/tcpdf/examples/example_067.php | 223 + tools/tcpdf/examples/images/_blank.png | Bin 0 -> 137 bytes tools/tcpdf/examples/images/alpha.png | Bin 0 -> 23862 bytes tools/tcpdf/examples/images/image_demo.jpg | Bin 0 -> 573845 bytes .../examples/images/image_with_alpha.png | Bin 0 -> 243788 bytes tools/tcpdf/examples/images/img.png | Bin 0 -> 194711 bytes tools/tcpdf/examples/images/logo_example.gif | Bin 0 -> 21022 bytes tools/tcpdf/examples/images/logo_example.jpg | Bin 0 -> 32732 bytes tools/tcpdf/examples/images/logo_example.png | Bin 0 -> 17829 bytes tools/tcpdf/examples/images/tcpdf_box.ai | 214 + tools/tcpdf/examples/images/tcpdf_box.svg | 69 + tools/tcpdf/examples/images/tcpdf_cell.png | Bin 0 -> 38367 bytes tools/tcpdf/examples/images/tcpdf_logo.jpg | Bin 0 -> 17633 bytes .../tcpdf/examples/images/tcpdf_signature.png | Bin 0 -> 67764 bytes tools/tcpdf/examples/images/testsvg.svg | 328 + tools/tcpdf/examples/images/tux.svg | 1487 ++++ tools/tcpdf/examples/index.php | 117 + tools/tcpdf/examples/lang/afr.php | 44 + tools/tcpdf/examples/lang/ara.php | 44 + tools/tcpdf/examples/lang/aze.php | 44 + tools/tcpdf/examples/lang/bel.php | 44 + tools/tcpdf/examples/lang/bra.php | 44 + tools/tcpdf/examples/lang/bul.php | 44 + tools/tcpdf/examples/lang/cat.php | 44 + tools/tcpdf/examples/lang/ces.php | 44 + tools/tcpdf/examples/lang/chi.php | 44 + tools/tcpdf/examples/lang/cym.php | 44 + tools/tcpdf/examples/lang/dan.php | 44 + tools/tcpdf/examples/lang/eng.php | 44 + tools/tcpdf/examples/lang/est.php | 44 + tools/tcpdf/examples/lang/eus.php | 44 + tools/tcpdf/examples/lang/far.php | 44 + tools/tcpdf/examples/lang/fra.php | 44 + tools/tcpdf/examples/lang/ger.php | 44 + tools/tcpdf/examples/lang/gle.php | 44 + tools/tcpdf/examples/lang/glg.php | 44 + tools/tcpdf/examples/lang/hat.php | 44 + tools/tcpdf/examples/lang/heb.php | 44 + tools/tcpdf/examples/lang/hrv.php | 44 + tools/tcpdf/examples/lang/hun.php | 44 + tools/tcpdf/examples/lang/hye.php | 44 + tools/tcpdf/examples/lang/ind.php | 44 + tools/tcpdf/examples/lang/ita.php | 44 + tools/tcpdf/examples/lang/jpn.php | 44 + tools/tcpdf/examples/lang/kat.php | 44 + tools/tcpdf/examples/lang/kor.php | 44 + tools/tcpdf/examples/lang/mkd.php | 44 + tools/tcpdf/examples/lang/mlt.php | 44 + tools/tcpdf/examples/lang/msa.php | 44 + tools/tcpdf/examples/lang/nld.php | 44 + tools/tcpdf/examples/lang/nob.php | 44 + tools/tcpdf/examples/lang/pol.php | 44 + tools/tcpdf/examples/lang/por.php | 44 + tools/tcpdf/examples/lang/ron.php | 44 + tools/tcpdf/examples/lang/rus.php | 44 + tools/tcpdf/examples/lang/slv.php | 44 + tools/tcpdf/examples/lang/spa.php | 44 + tools/tcpdf/examples/lang/sqi.php | 44 + tools/tcpdf/examples/lang/srp.php | 44 + tools/tcpdf/examples/lang/swa.php | 44 + tools/tcpdf/examples/lang/swe.php | 44 + tools/tcpdf/examples/lang/ukr.php | 44 + tools/tcpdf/examples/lang/urd.php | 44 + tools/tcpdf/examples/lang/yid.php | 44 + tools/tcpdf/examples/lang/zho.php | 44 + tools/tcpdf/examples/tcpdf_include.php | 49 + tools/tcpdf/fonts/ae_fonts_2.0/index.php | 35 - .../fonts/dejavu-fonts-ttf-2.33/index.php | 35 - .../fonts/dejavu-fonts-ttf-2.33/status.txt | 6657 ---------------- .../fonts/dejavu-fonts-ttf-2.34/index.php | 35 - .../fonts/dejavu-fonts-ttf-2.34/status.txt | 6766 ----------------- tools/tcpdf/fonts/freefont-20100919/CREDITS | 2 +- tools/tcpdf/fonts/freefont-20100919/index.php | 35 - tools/tcpdf/fonts/freefont-20120503/CREDITS | 2 +- tools/tcpdf/fonts/freefont-20120503/index.php | 35 - tools/tcpdf/fonts/index.php | 35 - tools/tcpdf/include/barcodes/datamatrix.php | 120 +- tools/tcpdf/include/barcodes/index.php | 35 - tools/tcpdf/include/barcodes/pdf417.php | 36 +- tools/tcpdf/include/barcodes/qrcode.php | 410 +- tools/tcpdf/include/index.php | 35 - tools/tcpdf/include/tcpdf_colors.php | 24 +- tools/tcpdf/include/tcpdf_filters.php | 52 +- tools/tcpdf/include/tcpdf_fonts.php | 229 +- tools/tcpdf/include/tcpdf_images.php | 37 +- tools/tcpdf/include/tcpdf_static.php | 401 +- tools/tcpdf/index.php | 35 - tools/tcpdf/tcpdf.php | 3477 +++++---- tools/tcpdf/tcpdf_autoconfig.php | 4 + tools/tcpdf/tcpdf_barcodes_1d.php | 147 +- tools/tcpdf/tcpdf_barcodes_2d.php | 46 +- tools/tcpdf/tcpdf_import.php | 4 +- tools/tcpdf/tcpdf_parser.php | 42 +- tools/tcpdf/tools/.htaccess | 14 +- tools/tcpdf/tools/index.php | 35 - 1185 files changed, 92175 insertions(+), 58962 deletions(-) rename classes/{Attribute.php => ProductAttribute.php} (98%) create mode 100755 tools/defuse/php-encryption/bin/generate-defuse-key delete mode 100644 tools/defuse/php-encryption/dist/index.php create mode 100644 tools/defuse/php-encryption/dist/phar-testing-autoload.php create mode 100644 tools/defuse/php-encryption/dist/signingkey-new.asc create mode 100644 tools/defuse/php-encryption/dist/signingkey-new.asc.sig create mode 100644 tools/defuse/php-encryption/docs/CryptoDetails.md create mode 100644 tools/defuse/php-encryption/docs/FAQ.md create mode 100644 tools/defuse/php-encryption/docs/InstallingAndVerifying.md create mode 100644 tools/defuse/php-encryption/docs/InternalDeveloperDocs.md create mode 100644 tools/defuse/php-encryption/docs/Tutorial.md create mode 100644 tools/defuse/php-encryption/docs/UpgradingFromV1.2.md create mode 100644 tools/defuse/php-encryption/docs/classes/Crypto.md create mode 100644 tools/defuse/php-encryption/docs/classes/File.md create mode 100644 tools/defuse/php-encryption/docs/classes/Key.md create mode 100644 tools/defuse/php-encryption/docs/classes/KeyProtectedByPassword.md delete mode 100644 tools/defuse/php-encryption/index.php delete mode 100644 tools/defuse/php-encryption/src/Exception/index.php delete mode 100644 tools/defuse/php-encryption/src/index.php create mode 100644 tools/geoip/autoload.php create mode 100644 tools/geoip/composer/ClassLoader.php create mode 100644 tools/geoip/composer/InstalledVersions.php create mode 100644 tools/geoip/composer/LICENSE create mode 100644 tools/geoip/composer/autoload_classmap.php create mode 100644 tools/geoip/composer/autoload_namespaces.php create mode 100644 tools/geoip/composer/autoload_psr4.php create mode 100644 tools/geoip/composer/autoload_real.php create mode 100644 tools/geoip/composer/autoload_static.php create mode 100644 tools/geoip/composer/ca-bundle/LICENSE create mode 100644 tools/geoip/composer/ca-bundle/README.md create mode 100644 tools/geoip/composer/ca-bundle/composer.json create mode 100644 tools/geoip/composer/ca-bundle/res/cacert.pem create mode 100644 tools/geoip/composer/ca-bundle/src/CaBundle.php create mode 100644 tools/geoip/composer/installed.json create mode 100644 tools/geoip/composer/installed.php create mode 100644 tools/geoip/composer/platform_check.php delete mode 100644 tools/geoip/geoip.inc create mode 100644 tools/geoip/geoip2/geoip2/CHANGELOG.md create mode 100644 tools/geoip/geoip2/geoip2/LICENSE create mode 100644 tools/geoip/geoip2/geoip2/README.md create mode 100644 tools/geoip/geoip2/geoip2/composer.json create mode 100644 tools/geoip/geoip2/geoip2/examples/benchmark.php create mode 100644 tools/geoip/geoip2/geoip2/src/Database/Reader.php create mode 100644 tools/geoip/geoip2/geoip2/src/Exception/AddressNotFoundException.php create mode 100644 tools/geoip/geoip2/geoip2/src/Exception/AuthenticationException.php create mode 100644 tools/geoip/geoip2/geoip2/src/Exception/GeoIp2Exception.php create mode 100644 tools/geoip/geoip2/geoip2/src/Exception/HttpException.php create mode 100644 tools/geoip/geoip2/geoip2/src/Exception/InvalidRequestException.php create mode 100644 tools/geoip/geoip2/geoip2/src/Exception/OutOfQueriesException.php create mode 100644 tools/geoip/geoip2/geoip2/src/Model/AnonymousIp.php create mode 100644 tools/geoip/geoip2/geoip2/src/Model/Asn.php create mode 100644 tools/geoip/geoip2/geoip2/src/Model/City.php create mode 100644 tools/geoip/geoip2/geoip2/src/Model/ConnectionType.php create mode 100644 tools/geoip/geoip2/geoip2/src/Model/Country.php create mode 100644 tools/geoip/geoip2/geoip2/src/Model/Domain.php create mode 100644 tools/geoip/geoip2/geoip2/src/Model/Enterprise.php create mode 100644 tools/geoip/geoip2/geoip2/src/Model/Insights.php create mode 100644 tools/geoip/geoip2/geoip2/src/Model/Isp.php create mode 100644 tools/geoip/geoip2/geoip2/src/ProviderInterface.php create mode 100644 tools/geoip/geoip2/geoip2/src/Record/AbstractNamedRecord.php create mode 100644 tools/geoip/geoip2/geoip2/src/Record/AbstractPlaceRecord.php create mode 100644 tools/geoip/geoip2/geoip2/src/Record/City.php create mode 100644 tools/geoip/geoip2/geoip2/src/Record/Continent.php create mode 100644 tools/geoip/geoip2/geoip2/src/Record/Country.php create mode 100644 tools/geoip/geoip2/geoip2/src/Record/Location.php create mode 100644 tools/geoip/geoip2/geoip2/src/Record/MaxMind.php create mode 100644 tools/geoip/geoip2/geoip2/src/Record/Postal.php create mode 100644 tools/geoip/geoip2/geoip2/src/Record/RepresentedCountry.php create mode 100644 tools/geoip/geoip2/geoip2/src/Record/Subdivision.php create mode 100644 tools/geoip/geoip2/geoip2/src/Record/Traits.php create mode 100644 tools/geoip/geoip2/geoip2/src/Util.php create mode 100644 tools/geoip/geoip2/geoip2/src/WebService/Client.php delete mode 100644 tools/geoip/geoipcity.inc delete mode 100644 tools/geoip/geoipregionvars.php create mode 100644 tools/geoip/maxmind-db/reader/CHANGELOG.md create mode 100644 tools/geoip/maxmind-db/reader/LICENSE create mode 100644 tools/geoip/maxmind-db/reader/README.md create mode 100644 tools/geoip/maxmind-db/reader/autoload.php create mode 100644 tools/geoip/maxmind-db/reader/composer.json create mode 100644 tools/geoip/maxmind-db/reader/ext/config.m4 create mode 100644 tools/geoip/maxmind-db/reader/ext/config.w32 create mode 100644 tools/geoip/maxmind-db/reader/ext/maxminddb.c create mode 100644 tools/geoip/maxmind-db/reader/ext/php_maxminddb.h create mode 100644 tools/geoip/maxmind-db/reader/ext/tests/001-load.phpt create mode 100644 tools/geoip/maxmind-db/reader/ext/tests/002-final.phpt create mode 100644 tools/geoip/maxmind-db/reader/ext/tests/003-open-basedir.phpt create mode 100644 tools/geoip/maxmind-db/reader/package.xml create mode 100644 tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader.php create mode 100644 tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php create mode 100644 tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php create mode 100644 tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php create mode 100644 tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php create mode 100644 tools/geoip/maxmind/web-service-common/CHANGELOG.md create mode 100644 tools/geoip/maxmind/web-service-common/LICENSE create mode 100644 tools/geoip/maxmind/web-service-common/README.md create mode 100644 tools/geoip/maxmind/web-service-common/composer.json create mode 100755 tools/geoip/maxmind/web-service-common/dev-bin/release.sh create mode 100644 tools/geoip/maxmind/web-service-common/phpstan.neon create mode 100644 tools/geoip/maxmind/web-service-common/src/Exception/AuthenticationException.php create mode 100644 tools/geoip/maxmind/web-service-common/src/Exception/HttpException.php create mode 100644 tools/geoip/maxmind/web-service-common/src/Exception/InsufficientFundsException.php create mode 100644 tools/geoip/maxmind/web-service-common/src/Exception/InvalidInputException.php create mode 100644 tools/geoip/maxmind/web-service-common/src/Exception/InvalidRequestException.php create mode 100644 tools/geoip/maxmind/web-service-common/src/Exception/IpAddressNotFoundException.php create mode 100644 tools/geoip/maxmind/web-service-common/src/Exception/PermissionRequiredException.php create mode 100644 tools/geoip/maxmind/web-service-common/src/Exception/WebServiceException.php create mode 100644 tools/geoip/maxmind/web-service-common/src/WebService/Client.php create mode 100644 tools/geoip/maxmind/web-service-common/src/WebService/Http/CurlRequest.php create mode 100644 tools/geoip/maxmind/web-service-common/src/WebService/Http/Request.php create mode 100644 tools/geoip/maxmind/web-service-common/src/WebService/Http/RequestFactory.php create mode 100644 tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/Ratio.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/index.php create mode 100644 tools/htmlpurifier/HTMLPurifier/AttrDef/HTML/ContentEditable.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/AttrDef/HTML/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/AttrDef/URI/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/AttrDef/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/AttrTransform/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/ChildDef/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/ConfigSchema/Builder/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/ConfigSchema/Interchange/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/ConfigSchema/index.php create mode 100644 tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveBlanks.txt delete mode 100644 tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/DefinitionCache/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/EntityLookup/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/Filter/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/HTMLModule/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/Injector/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/Language/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/Language/messages/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/Lexer/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/Node/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/Printer/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/Strategy/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/TagTransform/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/Token/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/URIFilter/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/URIScheme/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/VarParser/index.php delete mode 100644 tools/htmlpurifier/HTMLPurifier/index.php delete mode 100644 tools/htmlpurifier/LICENSE delete mode 100644 tools/htmlpurifier/index.php create mode 100644 tools/mailer/autoload.php create mode 100644 tools/mailer/composer/ClassLoader.php create mode 100644 tools/mailer/composer/InstalledVersions.php create mode 100644 tools/mailer/composer/LICENSE create mode 100644 tools/mailer/composer/autoload_classmap.php create mode 100644 tools/mailer/composer/autoload_files.php create mode 100644 tools/mailer/composer/autoload_namespaces.php create mode 100644 tools/mailer/composer/autoload_psr4.php create mode 100644 tools/mailer/composer/autoload_real.php create mode 100644 tools/mailer/composer/autoload_static.php create mode 100644 tools/mailer/composer/installed.json create mode 100644 tools/mailer/composer/installed.php create mode 100644 tools/mailer/composer/platform_check.php create mode 100644 tools/mailer/doctrine/lexer/LICENSE create mode 100644 tools/mailer/doctrine/lexer/README.md create mode 100644 tools/mailer/doctrine/lexer/UPGRADE.md create mode 100644 tools/mailer/doctrine/lexer/composer.json create mode 100644 tools/mailer/doctrine/lexer/src/AbstractLexer.php create mode 100644 tools/mailer/doctrine/lexer/src/Token.php create mode 100644 tools/mailer/egulias/email-validator/CHANGELOG.md create mode 100644 tools/mailer/egulias/email-validator/CONTRIBUTING.md create mode 100644 tools/mailer/egulias/email-validator/LICENSE create mode 100644 tools/mailer/egulias/email-validator/composer.json create mode 100644 tools/mailer/egulias/email-validator/src/EmailLexer.php create mode 100644 tools/mailer/egulias/email-validator/src/EmailParser.php create mode 100644 tools/mailer/egulias/email-validator/src/EmailValidator.php create mode 100644 tools/mailer/egulias/email-validator/src/MessageIDParser.php create mode 100644 tools/mailer/egulias/email-validator/src/Parser.php create mode 100644 tools/mailer/egulias/email-validator/src/Parser/Comment.php create mode 100644 tools/mailer/egulias/email-validator/src/Parser/CommentStrategy/CommentStrategy.php create mode 100644 tools/mailer/egulias/email-validator/src/Parser/CommentStrategy/DomainComment.php create mode 100644 tools/mailer/egulias/email-validator/src/Parser/CommentStrategy/LocalComment.php create mode 100644 tools/mailer/egulias/email-validator/src/Parser/DomainLiteral.php create mode 100644 tools/mailer/egulias/email-validator/src/Parser/DomainPart.php create mode 100644 tools/mailer/egulias/email-validator/src/Parser/DoubleQuote.php create mode 100644 tools/mailer/egulias/email-validator/src/Parser/FoldingWhiteSpace.php create mode 100644 tools/mailer/egulias/email-validator/src/Parser/IDLeftPart.php create mode 100644 tools/mailer/egulias/email-validator/src/Parser/IDRightPart.php create mode 100644 tools/mailer/egulias/email-validator/src/Parser/LocalPart.php create mode 100644 tools/mailer/egulias/email-validator/src/Parser/PartParser.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/InvalidEmail.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/MultipleErrors.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/AtextAfterCFWS.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/CRLFAtTheEnd.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/CRLFX2.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/CRNoLF.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/CharNotAllowed.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/CommaInDomain.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/CommentsInIDRight.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/ConsecutiveAt.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/ConsecutiveDot.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/DetailedReason.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/DomainAcceptsNoMail.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/DomainHyphened.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/DomainTooLong.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/DotAtEnd.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/DotAtStart.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/EmptyReason.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/ExceptionFound.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/ExpectingATEXT.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/ExpectingCTEXT.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/ExpectingDTEXT.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/ExpectingDomainLiteralClose.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/LabelTooLong.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/LocalOrReservedDomain.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/NoDNSRecord.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/NoDomainPart.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/NoLocalPart.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/RFCWarnings.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/Reason.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/SpoofEmail.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/UnOpenedComment.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/UnableToGetDNSRecord.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/UnclosedComment.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/UnclosedQuotedString.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Reason/UnusualElements.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/Result.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/SpoofEmail.php create mode 100644 tools/mailer/egulias/email-validator/src/Result/ValidEmail.php create mode 100644 tools/mailer/egulias/email-validator/src/Validation/DNSCheckValidation.php create mode 100644 tools/mailer/egulias/email-validator/src/Validation/DNSGetRecordWrapper.php create mode 100644 tools/mailer/egulias/email-validator/src/Validation/DNSRecords.php create mode 100644 tools/mailer/egulias/email-validator/src/Validation/EmailValidation.php create mode 100644 tools/mailer/egulias/email-validator/src/Validation/Exception/EmptyValidationList.php create mode 100644 tools/mailer/egulias/email-validator/src/Validation/Extra/SpoofCheckValidation.php create mode 100644 tools/mailer/egulias/email-validator/src/Validation/MessageIDValidation.php create mode 100644 tools/mailer/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php create mode 100644 tools/mailer/egulias/email-validator/src/Validation/NoRFCWarningsValidation.php create mode 100644 tools/mailer/egulias/email-validator/src/Validation/RFCValidation.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/AddressLiteral.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/CFWSNearAt.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/CFWSWithFWS.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/Comment.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/DeprecatedComment.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/DomainLiteral.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/EmailTooLong.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/IPV6BadChar.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/IPV6ColonEnd.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/IPV6ColonStart.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/IPV6Deprecated.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/IPV6DoubleColon.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/IPV6GroupCount.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/IPV6MaxGroups.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/LocalTooLong.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/NoDNSMXRecord.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/ObsoleteDTEXT.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/QuotedPart.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/QuotedString.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/TLD.php create mode 100644 tools/mailer/egulias/email-validator/src/Warning/Warning.php create mode 100644 tools/mailer/psr/container/.gitignore create mode 100644 tools/mailer/psr/container/LICENSE create mode 100644 tools/mailer/psr/container/README.md create mode 100644 tools/mailer/psr/container/composer.json create mode 100644 tools/mailer/psr/container/src/ContainerExceptionInterface.php create mode 100644 tools/mailer/psr/container/src/ContainerInterface.php create mode 100644 tools/mailer/psr/container/src/NotFoundExceptionInterface.php create mode 100644 tools/mailer/psr/event-dispatcher/.editorconfig create mode 100644 tools/mailer/psr/event-dispatcher/.gitignore create mode 100644 tools/mailer/psr/event-dispatcher/LICENSE create mode 100644 tools/mailer/psr/event-dispatcher/README.md create mode 100644 tools/mailer/psr/event-dispatcher/composer.json create mode 100644 tools/mailer/psr/event-dispatcher/src/EventDispatcherInterface.php create mode 100644 tools/mailer/psr/event-dispatcher/src/ListenerProviderInterface.php create mode 100644 tools/mailer/psr/event-dispatcher/src/StoppableEventInterface.php create mode 100644 tools/mailer/psr/log/LICENSE create mode 100644 tools/mailer/psr/log/README.md create mode 100644 tools/mailer/psr/log/composer.json create mode 100644 tools/mailer/psr/log/src/AbstractLogger.php create mode 100644 tools/mailer/psr/log/src/InvalidArgumentException.php create mode 100644 tools/mailer/psr/log/src/LogLevel.php create mode 100644 tools/mailer/psr/log/src/LoggerAwareInterface.php create mode 100644 tools/mailer/psr/log/src/LoggerAwareTrait.php create mode 100644 tools/mailer/psr/log/src/LoggerInterface.php create mode 100644 tools/mailer/psr/log/src/LoggerTrait.php create mode 100644 tools/mailer/psr/log/src/NullLogger.php create mode 100644 tools/mailer/symfony/deprecation-contracts/CHANGELOG.md rename tools/{swift => mailer/symfony/deprecation-contracts}/LICENSE (95%) create mode 100644 tools/mailer/symfony/deprecation-contracts/README.md create mode 100644 tools/mailer/symfony/deprecation-contracts/composer.json create mode 100644 tools/mailer/symfony/deprecation-contracts/function.php create mode 100644 tools/mailer/symfony/event-dispatcher-contracts/CHANGELOG.md create mode 100644 tools/mailer/symfony/event-dispatcher-contracts/Event.php create mode 100644 tools/mailer/symfony/event-dispatcher-contracts/EventDispatcherInterface.php create mode 100644 tools/mailer/symfony/event-dispatcher-contracts/LICENSE create mode 100644 tools/mailer/symfony/event-dispatcher-contracts/README.md create mode 100644 tools/mailer/symfony/event-dispatcher-contracts/composer.json create mode 100644 tools/mailer/symfony/event-dispatcher/Attribute/AsEventListener.php create mode 100644 tools/mailer/symfony/event-dispatcher/CHANGELOG.md create mode 100644 tools/mailer/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php create mode 100644 tools/mailer/symfony/event-dispatcher/Debug/WrappedListener.php create mode 100644 tools/mailer/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php create mode 100644 tools/mailer/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php create mode 100644 tools/mailer/symfony/event-dispatcher/EventDispatcher.php create mode 100644 tools/mailer/symfony/event-dispatcher/EventDispatcherInterface.php create mode 100644 tools/mailer/symfony/event-dispatcher/EventSubscriberInterface.php create mode 100644 tools/mailer/symfony/event-dispatcher/GenericEvent.php create mode 100644 tools/mailer/symfony/event-dispatcher/ImmutableEventDispatcher.php create mode 100644 tools/mailer/symfony/event-dispatcher/LICENSE create mode 100644 tools/mailer/symfony/event-dispatcher/README.md create mode 100644 tools/mailer/symfony/event-dispatcher/composer.json create mode 100644 tools/mailer/symfony/mailer/CHANGELOG.md create mode 100644 tools/mailer/symfony/mailer/Command/MailerTestCommand.php create mode 100644 tools/mailer/symfony/mailer/DataCollector/MessageDataCollector.php create mode 100644 tools/mailer/symfony/mailer/DelayedEnvelope.php create mode 100644 tools/mailer/symfony/mailer/Envelope.php create mode 100644 tools/mailer/symfony/mailer/Event/FailedMessageEvent.php create mode 100644 tools/mailer/symfony/mailer/Event/MessageEvent.php create mode 100644 tools/mailer/symfony/mailer/Event/MessageEvents.php create mode 100644 tools/mailer/symfony/mailer/Event/SentMessageEvent.php create mode 100644 tools/mailer/symfony/mailer/EventListener/EnvelopeListener.php create mode 100644 tools/mailer/symfony/mailer/EventListener/MessageListener.php create mode 100644 tools/mailer/symfony/mailer/EventListener/MessageLoggerListener.php create mode 100644 tools/mailer/symfony/mailer/EventListener/MessengerTransportListener.php create mode 100644 tools/mailer/symfony/mailer/Exception/ExceptionInterface.php create mode 100644 tools/mailer/symfony/mailer/Exception/HttpTransportException.php create mode 100644 tools/mailer/symfony/mailer/Exception/IncompleteDsnException.php create mode 100644 tools/mailer/symfony/mailer/Exception/InvalidArgumentException.php create mode 100644 tools/mailer/symfony/mailer/Exception/LogicException.php create mode 100644 tools/mailer/symfony/mailer/Exception/RuntimeException.php create mode 100644 tools/mailer/symfony/mailer/Exception/TransportException.php create mode 100644 tools/mailer/symfony/mailer/Exception/TransportExceptionInterface.php create mode 100644 tools/mailer/symfony/mailer/Exception/UnexpectedResponseException.php create mode 100644 tools/mailer/symfony/mailer/Exception/UnsupportedSchemeException.php create mode 100644 tools/mailer/symfony/mailer/Header/MetadataHeader.php create mode 100644 tools/mailer/symfony/mailer/Header/TagHeader.php create mode 100644 tools/mailer/symfony/mailer/LICENSE create mode 100644 tools/mailer/symfony/mailer/Mailer.php create mode 100644 tools/mailer/symfony/mailer/MailerInterface.php create mode 100644 tools/mailer/symfony/mailer/Messenger/MessageHandler.php create mode 100644 tools/mailer/symfony/mailer/Messenger/SendEmailMessage.php create mode 100644 tools/mailer/symfony/mailer/README.md create mode 100644 tools/mailer/symfony/mailer/SentMessage.php create mode 100644 tools/mailer/symfony/mailer/Test/Constraint/EmailCount.php create mode 100644 tools/mailer/symfony/mailer/Test/Constraint/EmailIsQueued.php create mode 100644 tools/mailer/symfony/mailer/Test/TransportFactoryTestCase.php create mode 100644 tools/mailer/symfony/mailer/Transport.php create mode 100644 tools/mailer/symfony/mailer/Transport/AbstractApiTransport.php create mode 100644 tools/mailer/symfony/mailer/Transport/AbstractHttpTransport.php create mode 100644 tools/mailer/symfony/mailer/Transport/AbstractTransport.php create mode 100644 tools/mailer/symfony/mailer/Transport/AbstractTransportFactory.php create mode 100644 tools/mailer/symfony/mailer/Transport/Dsn.php create mode 100644 tools/mailer/symfony/mailer/Transport/FailoverTransport.php create mode 100644 tools/mailer/symfony/mailer/Transport/NativeTransportFactory.php create mode 100644 tools/mailer/symfony/mailer/Transport/NullTransport.php create mode 100644 tools/mailer/symfony/mailer/Transport/NullTransportFactory.php create mode 100644 tools/mailer/symfony/mailer/Transport/RoundRobinTransport.php create mode 100644 tools/mailer/symfony/mailer/Transport/SendmailTransport.php create mode 100644 tools/mailer/symfony/mailer/Transport/SendmailTransportFactory.php create mode 100644 tools/mailer/symfony/mailer/Transport/Smtp/Auth/AuthenticatorInterface.php create mode 100644 tools/mailer/symfony/mailer/Transport/Smtp/Auth/CramMd5Authenticator.php create mode 100644 tools/mailer/symfony/mailer/Transport/Smtp/Auth/LoginAuthenticator.php create mode 100644 tools/mailer/symfony/mailer/Transport/Smtp/Auth/PlainAuthenticator.php create mode 100644 tools/mailer/symfony/mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php create mode 100644 tools/mailer/symfony/mailer/Transport/Smtp/EsmtpTransport.php create mode 100644 tools/mailer/symfony/mailer/Transport/Smtp/EsmtpTransportFactory.php create mode 100644 tools/mailer/symfony/mailer/Transport/Smtp/SmtpTransport.php create mode 100644 tools/mailer/symfony/mailer/Transport/Smtp/Stream/AbstractStream.php create mode 100644 tools/mailer/symfony/mailer/Transport/Smtp/Stream/ProcessStream.php create mode 100644 tools/mailer/symfony/mailer/Transport/Smtp/Stream/SocketStream.php create mode 100644 tools/mailer/symfony/mailer/Transport/TransportFactoryInterface.php create mode 100644 tools/mailer/symfony/mailer/Transport/TransportInterface.php create mode 100644 tools/mailer/symfony/mailer/Transport/Transports.php create mode 100644 tools/mailer/symfony/mailer/composer.json create mode 100644 tools/mailer/symfony/mime/Address.php create mode 100644 tools/mailer/symfony/mime/BodyRendererInterface.php create mode 100644 tools/mailer/symfony/mime/CHANGELOG.md create mode 100644 tools/mailer/symfony/mime/CharacterStream.php create mode 100644 tools/mailer/symfony/mime/Crypto/DkimOptions.php create mode 100644 tools/mailer/symfony/mime/Crypto/DkimSigner.php create mode 100644 tools/mailer/symfony/mime/Crypto/SMime.php create mode 100644 tools/mailer/symfony/mime/Crypto/SMimeEncrypter.php create mode 100644 tools/mailer/symfony/mime/Crypto/SMimeSigner.php create mode 100644 tools/mailer/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php create mode 100644 tools/mailer/symfony/mime/DraftEmail.php create mode 100644 tools/mailer/symfony/mime/Email.php create mode 100644 tools/mailer/symfony/mime/Encoder/AddressEncoderInterface.php create mode 100644 tools/mailer/symfony/mime/Encoder/Base64ContentEncoder.php create mode 100644 tools/mailer/symfony/mime/Encoder/Base64Encoder.php create mode 100644 tools/mailer/symfony/mime/Encoder/Base64MimeHeaderEncoder.php create mode 100644 tools/mailer/symfony/mime/Encoder/ContentEncoderInterface.php create mode 100644 tools/mailer/symfony/mime/Encoder/EightBitContentEncoder.php create mode 100644 tools/mailer/symfony/mime/Encoder/EncoderInterface.php create mode 100644 tools/mailer/symfony/mime/Encoder/IdnAddressEncoder.php rename tools/{swift/classes/Swift/Mime/HeaderEncoder.php => mailer/symfony/mime/Encoder/MimeHeaderEncoderInterface.php} (52%) create mode 100644 tools/mailer/symfony/mime/Encoder/QpContentEncoder.php rename tools/{swift/classes/Swift => mailer/symfony/mime}/Encoder/QpEncoder.php (55%) create mode 100644 tools/mailer/symfony/mime/Encoder/QpMimeHeaderEncoder.php create mode 100644 tools/mailer/symfony/mime/Encoder/Rfc2231Encoder.php create mode 100644 tools/mailer/symfony/mime/Exception/AddressEncoderException.php create mode 100644 tools/mailer/symfony/mime/Exception/ExceptionInterface.php create mode 100644 tools/mailer/symfony/mime/Exception/InvalidArgumentException.php create mode 100644 tools/mailer/symfony/mime/Exception/LogicException.php create mode 100644 tools/mailer/symfony/mime/Exception/RfcComplianceException.php create mode 100644 tools/mailer/symfony/mime/Exception/RuntimeException.php create mode 100644 tools/mailer/symfony/mime/FileBinaryMimeTypeGuesser.php create mode 100644 tools/mailer/symfony/mime/FileinfoMimeTypeGuesser.php create mode 100644 tools/mailer/symfony/mime/Header/AbstractHeader.php create mode 100644 tools/mailer/symfony/mime/Header/DateHeader.php create mode 100644 tools/mailer/symfony/mime/Header/HeaderInterface.php create mode 100644 tools/mailer/symfony/mime/Header/Headers.php create mode 100644 tools/mailer/symfony/mime/Header/IdentificationHeader.php create mode 100644 tools/mailer/symfony/mime/Header/MailboxHeader.php create mode 100644 tools/mailer/symfony/mime/Header/MailboxListHeader.php create mode 100644 tools/mailer/symfony/mime/Header/ParameterizedHeader.php create mode 100644 tools/mailer/symfony/mime/Header/PathHeader.php create mode 100644 tools/mailer/symfony/mime/Header/UnstructuredHeader.php create mode 100644 tools/mailer/symfony/mime/HtmlToTextConverter/DefaultHtmlToTextConverter.php create mode 100644 tools/mailer/symfony/mime/HtmlToTextConverter/HtmlToTextConverterInterface.php create mode 100644 tools/mailer/symfony/mime/HtmlToTextConverter/LeagueHtmlToMarkdownConverter.php create mode 100644 tools/mailer/symfony/mime/LICENSE create mode 100644 tools/mailer/symfony/mime/Message.php create mode 100644 tools/mailer/symfony/mime/MessageConverter.php create mode 100644 tools/mailer/symfony/mime/MimeTypeGuesserInterface.php create mode 100644 tools/mailer/symfony/mime/MimeTypes.php create mode 100644 tools/mailer/symfony/mime/MimeTypesInterface.php create mode 100644 tools/mailer/symfony/mime/Part/AbstractMultipartPart.php create mode 100644 tools/mailer/symfony/mime/Part/AbstractPart.php create mode 100644 tools/mailer/symfony/mime/Part/DataPart.php create mode 100644 tools/mailer/symfony/mime/Part/File.php create mode 100644 tools/mailer/symfony/mime/Part/MessagePart.php create mode 100644 tools/mailer/symfony/mime/Part/Multipart/AlternativePart.php create mode 100644 tools/mailer/symfony/mime/Part/Multipart/DigestPart.php create mode 100644 tools/mailer/symfony/mime/Part/Multipart/FormDataPart.php create mode 100644 tools/mailer/symfony/mime/Part/Multipart/MixedPart.php create mode 100644 tools/mailer/symfony/mime/Part/Multipart/RelatedPart.php create mode 100644 tools/mailer/symfony/mime/Part/SMimePart.php create mode 100644 tools/mailer/symfony/mime/Part/TextPart.php create mode 100644 tools/mailer/symfony/mime/README.md create mode 100644 tools/mailer/symfony/mime/RawMessage.php create mode 100644 tools/mailer/symfony/mime/Test/Constraint/EmailAddressContains.php create mode 100644 tools/mailer/symfony/mime/Test/Constraint/EmailAttachmentCount.php create mode 100644 tools/mailer/symfony/mime/Test/Constraint/EmailHasHeader.php create mode 100644 tools/mailer/symfony/mime/Test/Constraint/EmailHeaderSame.php create mode 100644 tools/mailer/symfony/mime/Test/Constraint/EmailHtmlBodyContains.php create mode 100644 tools/mailer/symfony/mime/Test/Constraint/EmailSubjectContains.php create mode 100644 tools/mailer/symfony/mime/Test/Constraint/EmailTextBodyContains.php create mode 100644 tools/mailer/symfony/mime/composer.json create mode 100644 tools/mailer/symfony/polyfill-intl-idn/Idn.php create mode 100644 tools/mailer/symfony/polyfill-intl-idn/Info.php create mode 100644 tools/mailer/symfony/polyfill-intl-idn/LICENSE create mode 100644 tools/mailer/symfony/polyfill-intl-idn/README.md create mode 100644 tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php create mode 100644 tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/Regex.php create mode 100644 tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/deviation.php create mode 100644 tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php create mode 100644 tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php create mode 100644 tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php create mode 100644 tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/ignored.php create mode 100644 tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/mapped.php create mode 100644 tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/virama.php create mode 100644 tools/mailer/symfony/polyfill-intl-idn/bootstrap.php create mode 100644 tools/mailer/symfony/polyfill-intl-idn/bootstrap80.php create mode 100644 tools/mailer/symfony/polyfill-intl-idn/composer.json create mode 100644 tools/mailer/symfony/polyfill-intl-normalizer/LICENSE create mode 100644 tools/mailer/symfony/polyfill-intl-normalizer/Normalizer.php create mode 100644 tools/mailer/symfony/polyfill-intl-normalizer/README.md create mode 100644 tools/mailer/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php create mode 100644 tools/mailer/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php create mode 100644 tools/mailer/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php create mode 100644 tools/mailer/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php create mode 100644 tools/mailer/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php create mode 100644 tools/mailer/symfony/polyfill-intl-normalizer/bootstrap.php create mode 100644 tools/mailer/symfony/polyfill-intl-normalizer/bootstrap80.php create mode 100644 tools/mailer/symfony/polyfill-intl-normalizer/composer.json create mode 100644 tools/mailer/symfony/polyfill-mbstring/LICENSE create mode 100644 tools/mailer/symfony/polyfill-mbstring/Mbstring.php create mode 100644 tools/mailer/symfony/polyfill-mbstring/README.md create mode 100644 tools/mailer/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php create mode 100644 tools/mailer/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php create mode 100644 tools/mailer/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php create mode 100644 tools/mailer/symfony/polyfill-mbstring/Resources/unidata/upperCase.php create mode 100644 tools/mailer/symfony/polyfill-mbstring/bootstrap.php create mode 100644 tools/mailer/symfony/polyfill-mbstring/bootstrap80.php create mode 100644 tools/mailer/symfony/polyfill-mbstring/composer.json create mode 100644 tools/mailer/symfony/service-contracts/Attribute/Required.php create mode 100644 tools/mailer/symfony/service-contracts/Attribute/SubscribedService.php create mode 100644 tools/mailer/symfony/service-contracts/CHANGELOG.md create mode 100644 tools/mailer/symfony/service-contracts/LICENSE create mode 100644 tools/mailer/symfony/service-contracts/README.md create mode 100644 tools/mailer/symfony/service-contracts/ResetInterface.php create mode 100644 tools/mailer/symfony/service-contracts/ServiceCollectionInterface.php create mode 100644 tools/mailer/symfony/service-contracts/ServiceLocatorTrait.php create mode 100644 tools/mailer/symfony/service-contracts/ServiceMethodsSubscriberTrait.php create mode 100644 tools/mailer/symfony/service-contracts/ServiceProviderInterface.php create mode 100644 tools/mailer/symfony/service-contracts/ServiceSubscriberInterface.php create mode 100644 tools/mailer/symfony/service-contracts/ServiceSubscriberTrait.php create mode 100644 tools/mailer/symfony/service-contracts/Test/ServiceLocatorTest.php create mode 100644 tools/mailer/symfony/service-contracts/Test/ServiceLocatorTestCase.php create mode 100644 tools/mailer/symfony/service-contracts/composer.json create mode 100644 tools/minify_html/LICENSE delete mode 100644 tools/mobile_Detect/LICENSE delete mode 100644 tools/mobile_Detect/Mobile_Detect.php delete mode 100644 tools/mobile_Detect/index.php rename tools/{mobile_Detect => mobile_detect}/.htaccess (100%) create mode 100644 tools/mobile_detect/autoload.php create mode 100644 tools/mobile_detect/composer/ClassLoader.php create mode 100644 tools/mobile_detect/composer/InstalledVersions.php create mode 100644 tools/mobile_detect/composer/LICENSE create mode 100644 tools/mobile_detect/composer/autoload_classmap.php create mode 100644 tools/mobile_detect/composer/autoload_namespaces.php create mode 100644 tools/mobile_detect/composer/autoload_psr4.php create mode 100644 tools/mobile_detect/composer/autoload_real.php create mode 100644 tools/mobile_detect/composer/autoload_static.php create mode 100644 tools/mobile_detect/composer/installed.json create mode 100644 tools/mobile_detect/composer/installed.php create mode 100644 tools/mobile_detect/composer/platform_check.php create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/CHANGELOG.md create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/CNAME create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/CONTRIBUTING.md create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/KNOWN_LIMITATIONS.md create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/LICENSE create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/MobileDetect.json create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/README.md create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/SECURITY.md create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/composer.json create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/docker-compose.yml create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/docker/Dockerfile.setup create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/docker/build.sh create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/phpbench.json create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/src/Cache/Cache.php create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/src/Cache/CacheException.php create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/src/Cache/CacheItem.php create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/src/Exception/MobileDetectException.php create mode 100644 tools/mobile_detect/mobiledetect/mobiledetectlib/src/MobileDetect.php create mode 100644 tools/mobile_detect/psr/cache/CHANGELOG.md create mode 100644 tools/mobile_detect/psr/cache/LICENSE.txt create mode 100644 tools/mobile_detect/psr/cache/README.md create mode 100644 tools/mobile_detect/psr/cache/composer.json create mode 100644 tools/mobile_detect/psr/cache/src/CacheException.php create mode 100644 tools/mobile_detect/psr/cache/src/CacheItemInterface.php create mode 100644 tools/mobile_detect/psr/cache/src/CacheItemPoolInterface.php create mode 100644 tools/mobile_detect/psr/cache/src/InvalidArgumentException.php create mode 100644 tools/mobile_detect/psr/simple-cache/.editorconfig create mode 100644 tools/mobile_detect/psr/simple-cache/LICENSE.md create mode 100644 tools/mobile_detect/psr/simple-cache/README.md create mode 100644 tools/mobile_detect/psr/simple-cache/composer.json create mode 100644 tools/mobile_detect/psr/simple-cache/src/CacheException.php create mode 100644 tools/mobile_detect/psr/simple-cache/src/CacheInterface.php create mode 100644 tools/mobile_detect/psr/simple-cache/src/InvalidArgumentException.php create mode 100644 tools/parser_sql/builders/FulltextIndexBuilder.php create mode 100644 tools/parser_sql/builders/OrderByPositionBuilder.php create mode 100644 tools/parser_sql/builders/UniqueIndexBuilder.php delete mode 100644 tools/parser_sql/builders/index.php delete mode 100644 tools/parser_sql/exceptions/index.php delete mode 100644 tools/parser_sql/index.php delete mode 100644 tools/parser_sql/lexer/index.php delete mode 100644 tools/parser_sql/positions/index.php delete mode 100644 tools/parser_sql/processors/index.php delete mode 100644 tools/parser_sql/utils/index.php create mode 100755 tools/random_compat/build-phar.sh delete mode 100644 tools/random_compat/composer.json delete mode 100644 tools/random_compat/dist/index.php delete mode 100644 tools/random_compat/index.php delete mode 100644 tools/random_compat/lib/byte_safe_strings.php delete mode 100644 tools/random_compat/lib/cast_to_int.php delete mode 100644 tools/random_compat/lib/error_polyfill.php delete mode 100644 tools/random_compat/lib/index.php delete mode 100644 tools/random_compat/lib/random_bytes_com_dotnet.php delete mode 100644 tools/random_compat/lib/random_bytes_dev_urandom.php delete mode 100644 tools/random_compat/lib/random_bytes_libsodium.php delete mode 100644 tools/random_compat/lib/random_bytes_libsodium_legacy.php delete mode 100644 tools/random_compat/lib/random_bytes_mcrypt.php delete mode 100644 tools/random_compat/lib/random_int.php create mode 100644 tools/random_compat/other/build_phar.php create mode 100644 tools/random_compat/psalm-autoload.php create mode 100644 tools/random_compat/psalm.xml delete mode 100644 tools/smarty/.htaccess delete mode 100644 tools/smarty/CHANGELOG.md delete mode 100644 tools/smarty/LICENSE delete mode 100644 tools/smarty/README.md delete mode 100644 tools/smarty/SmartyBC.class.php create mode 100644 tools/smarty/functions.php delete mode 100644 tools/smarty/index.php delete mode 100644 tools/smarty/plugins/index.php create mode 100644 tools/smarty/plugins/modifier.count.php create mode 100644 tools/smarty/plugins/modifier.explode.php create mode 100644 tools/smarty/plugins/modifier.implode.php create mode 100644 tools/smarty/plugins/modifier.number_format.php create mode 100644 tools/smarty/plugins/modifiercompiler.json_encode.php create mode 100644 tools/smarty/plugins/modifiercompiler.nl2br.php create mode 100644 tools/smarty/plugins/modifiercompiler.round.php create mode 100644 tools/smarty/plugins/modifiercompiler.str_repeat.php create mode 100644 tools/smarty/plugins/modifiercompiler.strlen.php create mode 100644 tools/smarty/plugins/modifiercompiler.substr.php delete mode 100644 tools/smarty/sysplugins/index.php delete mode 100644 tools/smarty/sysplugins/smarty_internal_compile_include_php.php delete mode 100644 tools/smarty/sysplugins/smarty_internal_compile_private_php.php delete mode 100644 tools/smarty/sysplugins/smarty_internal_resource_registered.php delete mode 100644 tools/swift/.htaccess delete mode 100644 tools/swift/CHANGES delete mode 100644 tools/swift/README delete mode 100644 tools/swift/VERSION delete mode 100644 tools/swift/classes/Swift.php delete mode 100644 tools/swift/classes/Swift/Attachment.php delete mode 100644 tools/swift/classes/Swift/ByteStream/AbstractFilterableInputStream.php delete mode 100644 tools/swift/classes/Swift/ByteStream/ArrayByteStream.php delete mode 100644 tools/swift/classes/Swift/ByteStream/FileByteStream.php delete mode 100644 tools/swift/classes/Swift/ByteStream/TemporaryFileByteStream.php delete mode 100644 tools/swift/classes/Swift/CharacterReader.php delete mode 100644 tools/swift/classes/Swift/CharacterReader/GenericFixedWidthReader.php delete mode 100644 tools/swift/classes/Swift/CharacterReader/UsAsciiReader.php delete mode 100644 tools/swift/classes/Swift/CharacterReader/Utf8Reader.php delete mode 100644 tools/swift/classes/Swift/CharacterReaderFactory.php delete mode 100644 tools/swift/classes/Swift/CharacterReaderFactory/SimpleCharacterReaderFactory.php delete mode 100644 tools/swift/classes/Swift/CharacterStream.php delete mode 100644 tools/swift/classes/Swift/CharacterStream/ArrayCharacterStream.php delete mode 100644 tools/swift/classes/Swift/CharacterStream/NgCharacterStream.php delete mode 100644 tools/swift/classes/Swift/ConfigurableSpool.php delete mode 100644 tools/swift/classes/Swift/DependencyContainer.php delete mode 100644 tools/swift/classes/Swift/DependencyException.php delete mode 100644 tools/swift/classes/Swift/EmbeddedFile.php delete mode 100644 tools/swift/classes/Swift/Encoder.php delete mode 100644 tools/swift/classes/Swift/Encoder/Base64Encoder.php delete mode 100644 tools/swift/classes/Swift/Encoder/Rfc2231Encoder.php delete mode 100644 tools/swift/classes/Swift/Encoding.php delete mode 100644 tools/swift/classes/Swift/Events/CommandEvent.php delete mode 100644 tools/swift/classes/Swift/Events/CommandListener.php delete mode 100644 tools/swift/classes/Swift/Events/Event.php delete mode 100644 tools/swift/classes/Swift/Events/EventDispatcher.php delete mode 100644 tools/swift/classes/Swift/Events/EventListener.php delete mode 100644 tools/swift/classes/Swift/Events/EventObject.php delete mode 100644 tools/swift/classes/Swift/Events/ResponseEvent.php delete mode 100644 tools/swift/classes/Swift/Events/ResponseListener.php delete mode 100644 tools/swift/classes/Swift/Events/SendEvent.php delete mode 100644 tools/swift/classes/Swift/Events/SendListener.php delete mode 100644 tools/swift/classes/Swift/Events/SimpleEventDispatcher.php delete mode 100644 tools/swift/classes/Swift/Events/TransportChangeEvent.php delete mode 100644 tools/swift/classes/Swift/Events/TransportChangeListener.php delete mode 100644 tools/swift/classes/Swift/Events/TransportExceptionEvent.php delete mode 100644 tools/swift/classes/Swift/Events/TransportExceptionListener.php delete mode 100644 tools/swift/classes/Swift/FailoverTransport.php delete mode 100644 tools/swift/classes/Swift/FileSpool.php delete mode 100644 tools/swift/classes/Swift/FileStream.php delete mode 100644 tools/swift/classes/Swift/Filterable.php delete mode 100644 tools/swift/classes/Swift/Image.php delete mode 100644 tools/swift/classes/Swift/InputByteStream.php delete mode 100644 tools/swift/classes/Swift/IoException.php delete mode 100644 tools/swift/classes/Swift/KeyCache.php delete mode 100644 tools/swift/classes/Swift/KeyCache/ArrayKeyCache.php delete mode 100644 tools/swift/classes/Swift/KeyCache/DiskKeyCache.php delete mode 100644 tools/swift/classes/Swift/KeyCache/KeyCacheInputStream.php delete mode 100644 tools/swift/classes/Swift/KeyCache/NullKeyCache.php delete mode 100644 tools/swift/classes/Swift/KeyCache/SimpleKeyCacheInputStream.php delete mode 100644 tools/swift/classes/Swift/LoadBalancedTransport.php delete mode 100644 tools/swift/classes/Swift/MailTransport.php delete mode 100644 tools/swift/classes/Swift/Mailer.php delete mode 100644 tools/swift/classes/Swift/Mailer/ArrayRecipientIterator.php delete mode 100644 tools/swift/classes/Swift/Mailer/RecipientIterator.php delete mode 100644 tools/swift/classes/Swift/MemorySpool.php delete mode 100644 tools/swift/classes/Swift/Message.php delete mode 100644 tools/swift/classes/Swift/Mime/Attachment.php delete mode 100644 tools/swift/classes/Swift/Mime/CharsetObserver.php delete mode 100644 tools/swift/classes/Swift/Mime/ContentEncoder.php delete mode 100644 tools/swift/classes/Swift/Mime/ContentEncoder/Base64ContentEncoder.php delete mode 100644 tools/swift/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php delete mode 100644 tools/swift/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php delete mode 100644 tools/swift/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php delete mode 100644 tools/swift/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php delete mode 100644 tools/swift/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php delete mode 100644 tools/swift/classes/Swift/Mime/EmbeddedFile.php delete mode 100644 tools/swift/classes/Swift/Mime/EncodingObserver.php delete mode 100644 tools/swift/classes/Swift/Mime/Grammar.php delete mode 100644 tools/swift/classes/Swift/Mime/Header.php delete mode 100644 tools/swift/classes/Swift/Mime/HeaderEncoder/Base64HeaderEncoder.php delete mode 100644 tools/swift/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php delete mode 100644 tools/swift/classes/Swift/Mime/HeaderFactory.php delete mode 100644 tools/swift/classes/Swift/Mime/HeaderSet.php delete mode 100644 tools/swift/classes/Swift/Mime/Headers/AbstractHeader.php delete mode 100644 tools/swift/classes/Swift/Mime/Headers/DateHeader.php delete mode 100644 tools/swift/classes/Swift/Mime/Headers/IdentificationHeader.php delete mode 100644 tools/swift/classes/Swift/Mime/Headers/MailboxHeader.php delete mode 100644 tools/swift/classes/Swift/Mime/Headers/OpenDKIMHeader.php delete mode 100644 tools/swift/classes/Swift/Mime/Headers/ParameterizedHeader.php delete mode 100644 tools/swift/classes/Swift/Mime/Headers/PathHeader.php delete mode 100644 tools/swift/classes/Swift/Mime/Headers/UnstructuredHeader.php delete mode 100644 tools/swift/classes/Swift/Mime/Message.php delete mode 100644 tools/swift/classes/Swift/Mime/MimeEntity.php delete mode 100644 tools/swift/classes/Swift/Mime/MimePart.php delete mode 100644 tools/swift/classes/Swift/Mime/ParameterizedHeader.php delete mode 100644 tools/swift/classes/Swift/Mime/SimpleHeaderFactory.php delete mode 100644 tools/swift/classes/Swift/Mime/SimpleHeaderSet.php delete mode 100644 tools/swift/classes/Swift/Mime/SimpleMessage.php delete mode 100644 tools/swift/classes/Swift/Mime/SimpleMimeEntity.php delete mode 100644 tools/swift/classes/Swift/MimePart.php delete mode 100644 tools/swift/classes/Swift/NullTransport.php delete mode 100644 tools/swift/classes/Swift/OutputByteStream.php delete mode 100644 tools/swift/classes/Swift/Plugins/AntiFloodPlugin.php delete mode 100644 tools/swift/classes/Swift/Plugins/BandwidthMonitorPlugin.php delete mode 100644 tools/swift/classes/Swift/Plugins/Decorator/Replacements.php delete mode 100644 tools/swift/classes/Swift/Plugins/DecoratorPlugin.php delete mode 100644 tools/swift/classes/Swift/Plugins/ImpersonatePlugin.php delete mode 100644 tools/swift/classes/Swift/Plugins/Logger.php delete mode 100644 tools/swift/classes/Swift/Plugins/LoggerPlugin.php delete mode 100644 tools/swift/classes/Swift/Plugins/Loggers/ArrayLogger.php delete mode 100644 tools/swift/classes/Swift/Plugins/Loggers/EchoLogger.php delete mode 100644 tools/swift/classes/Swift/Plugins/MessageLogger.php delete mode 100644 tools/swift/classes/Swift/Plugins/Pop/Pop3Connection.php delete mode 100644 tools/swift/classes/Swift/Plugins/Pop/Pop3Exception.php delete mode 100644 tools/swift/classes/Swift/Plugins/PopBeforeSmtpPlugin.php delete mode 100644 tools/swift/classes/Swift/Plugins/RedirectingPlugin.php delete mode 100644 tools/swift/classes/Swift/Plugins/Reporter.php delete mode 100644 tools/swift/classes/Swift/Plugins/ReporterPlugin.php delete mode 100644 tools/swift/classes/Swift/Plugins/Reporters/HitReporter.php delete mode 100644 tools/swift/classes/Swift/Plugins/Reporters/HtmlReporter.php delete mode 100644 tools/swift/classes/Swift/Plugins/Sleeper.php delete mode 100644 tools/swift/classes/Swift/Plugins/ThrottlerPlugin.php delete mode 100644 tools/swift/classes/Swift/Plugins/Timer.php delete mode 100644 tools/swift/classes/Swift/Preferences.php delete mode 100644 tools/swift/classes/Swift/ReplacementFilterFactory.php delete mode 100644 tools/swift/classes/Swift/RfcComplianceException.php delete mode 100644 tools/swift/classes/Swift/SendmailTransport.php delete mode 100644 tools/swift/classes/Swift/SignedMessage.php delete mode 100644 tools/swift/classes/Swift/Signer.php delete mode 100644 tools/swift/classes/Swift/Signers/BodySigner.php delete mode 100644 tools/swift/classes/Swift/Signers/DKIMSigner.php delete mode 100644 tools/swift/classes/Swift/Signers/DomainKeySigner.php delete mode 100644 tools/swift/classes/Swift/Signers/HeaderSigner.php delete mode 100644 tools/swift/classes/Swift/Signers/OpenDKIMSigner.php delete mode 100644 tools/swift/classes/Swift/Signers/SMimeSigner.php delete mode 100644 tools/swift/classes/Swift/SmtpTransport.php delete mode 100644 tools/swift/classes/Swift/Spool.php delete mode 100644 tools/swift/classes/Swift/SpoolTransport.php delete mode 100644 tools/swift/classes/Swift/StreamFilter.php delete mode 100644 tools/swift/classes/Swift/StreamFilters/ByteArrayReplacementFilter.php delete mode 100644 tools/swift/classes/Swift/StreamFilters/StringReplacementFilter.php delete mode 100644 tools/swift/classes/Swift/StreamFilters/StringReplacementFilterFactory.php delete mode 100644 tools/swift/classes/Swift/SwiftException.php delete mode 100644 tools/swift/classes/Swift/Transport.php delete mode 100644 tools/swift/classes/Swift/Transport/AbstractSmtpTransport.php delete mode 100644 tools/swift/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php delete mode 100644 tools/swift/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php delete mode 100644 tools/swift/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php delete mode 100644 tools/swift/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php delete mode 100644 tools/swift/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php delete mode 100644 tools/swift/classes/Swift/Transport/Esmtp/AuthHandler.php delete mode 100644 tools/swift/classes/Swift/Transport/Esmtp/Authenticator.php delete mode 100644 tools/swift/classes/Swift/Transport/EsmtpHandler.php delete mode 100644 tools/swift/classes/Swift/Transport/EsmtpTransport.php delete mode 100644 tools/swift/classes/Swift/Transport/FailoverTransport.php delete mode 100644 tools/swift/classes/Swift/Transport/IoBuffer.php delete mode 100644 tools/swift/classes/Swift/Transport/LoadBalancedTransport.php delete mode 100644 tools/swift/classes/Swift/Transport/MailInvoker.php delete mode 100644 tools/swift/classes/Swift/Transport/MailTransport.php delete mode 100644 tools/swift/classes/Swift/Transport/NullTransport.php delete mode 100644 tools/swift/classes/Swift/Transport/SendmailTransport.php delete mode 100644 tools/swift/classes/Swift/Transport/SimpleMailInvoker.php delete mode 100644 tools/swift/classes/Swift/Transport/SmtpAgent.php delete mode 100644 tools/swift/classes/Swift/Transport/SpoolTransport.php delete mode 100644 tools/swift/classes/Swift/Transport/StreamBuffer.php delete mode 100644 tools/swift/classes/Swift/TransportException.php delete mode 100644 tools/swift/classes/Swift/Validate.php delete mode 100644 tools/swift/dependency_maps/cache_deps.php delete mode 100644 tools/swift/dependency_maps/message_deps.php delete mode 100644 tools/swift/dependency_maps/mime_deps.php delete mode 100644 tools/swift/dependency_maps/transport_deps.php delete mode 100644 tools/swift/index.php delete mode 100644 tools/swift/mime_types.php delete mode 100644 tools/swift/preferences.php delete mode 100644 tools/swift/swift_init.php delete mode 100644 tools/swift/swift_required.php delete mode 100644 tools/swift/swift_required_pear.php delete mode 100755 tools/swift/swiftmailer_generate_mimes_config.php delete mode 100644 tools/tcpdf/config/index.php create mode 100644 tools/tcpdf/examples/barcodes/example_1d_html.php create mode 100644 tools/tcpdf/examples/barcodes/example_1d_png.php create mode 100644 tools/tcpdf/examples/barcodes/example_1d_svg.php create mode 100644 tools/tcpdf/examples/barcodes/example_1d_svgi.php create mode 100644 tools/tcpdf/examples/barcodes/example_2d_datamatrix_html.php create mode 100644 tools/tcpdf/examples/barcodes/example_2d_datamatrix_png.php create mode 100644 tools/tcpdf/examples/barcodes/example_2d_datamatrix_svg.php create mode 100644 tools/tcpdf/examples/barcodes/example_2d_datamatrix_svgi.php create mode 100644 tools/tcpdf/examples/barcodes/example_2d_pdf417_html.php create mode 100644 tools/tcpdf/examples/barcodes/example_2d_pdf417_png.php create mode 100644 tools/tcpdf/examples/barcodes/example_2d_pdf417_svg.php create mode 100644 tools/tcpdf/examples/barcodes/example_2d_pdf417_svgi.php create mode 100644 tools/tcpdf/examples/barcodes/example_2d_qrcode_html.php create mode 100644 tools/tcpdf/examples/barcodes/example_2d_qrcode_png.php create mode 100644 tools/tcpdf/examples/barcodes/example_2d_qrcode_svg.php create mode 100644 tools/tcpdf/examples/barcodes/example_2d_qrcode_svgi.php create mode 100644 tools/tcpdf/examples/barcodes/tcpdf_barcodes_1d_include.php create mode 100644 tools/tcpdf/examples/barcodes/tcpdf_barcodes_2d_include.php create mode 100644 tools/tcpdf/examples/config/tcpdf_config_alt.php create mode 100644 tools/tcpdf/examples/data/cert/tcpdf.crt create mode 100644 tools/tcpdf/examples/data/cert/tcpdf.fdf create mode 100644 tools/tcpdf/examples/data/cert/tcpdf.p12 create mode 100644 tools/tcpdf/examples/data/chapter_demo_1.txt create mode 100644 tools/tcpdf/examples/data/chapter_demo_2.txt create mode 100644 tools/tcpdf/examples/data/table_data_demo.txt create mode 100644 tools/tcpdf/examples/data/utf8test.txt create mode 100644 tools/tcpdf/examples/example_001.php create mode 100644 tools/tcpdf/examples/example_002.php create mode 100644 tools/tcpdf/examples/example_003.php create mode 100644 tools/tcpdf/examples/example_004.php create mode 100644 tools/tcpdf/examples/example_005.php create mode 100644 tools/tcpdf/examples/example_006.php create mode 100644 tools/tcpdf/examples/example_007.php create mode 100644 tools/tcpdf/examples/example_008.php create mode 100644 tools/tcpdf/examples/example_009.php create mode 100644 tools/tcpdf/examples/example_010.php create mode 100644 tools/tcpdf/examples/example_011.php create mode 100644 tools/tcpdf/examples/example_012.pdf create mode 100644 tools/tcpdf/examples/example_012.php create mode 100644 tools/tcpdf/examples/example_013.php create mode 100644 tools/tcpdf/examples/example_014.php create mode 100644 tools/tcpdf/examples/example_015.php create mode 100644 tools/tcpdf/examples/example_016.php create mode 100644 tools/tcpdf/examples/example_017.php create mode 100644 tools/tcpdf/examples/example_018.php create mode 100644 tools/tcpdf/examples/example_019.php create mode 100644 tools/tcpdf/examples/example_020.php create mode 100644 tools/tcpdf/examples/example_021.php create mode 100644 tools/tcpdf/examples/example_022.php create mode 100644 tools/tcpdf/examples/example_023.php create mode 100644 tools/tcpdf/examples/example_024.php create mode 100644 tools/tcpdf/examples/example_025.php create mode 100644 tools/tcpdf/examples/example_026.php create mode 100644 tools/tcpdf/examples/example_027.php create mode 100644 tools/tcpdf/examples/example_028.php create mode 100644 tools/tcpdf/examples/example_029.php create mode 100644 tools/tcpdf/examples/example_030.php create mode 100644 tools/tcpdf/examples/example_031.php create mode 100644 tools/tcpdf/examples/example_032.php create mode 100644 tools/tcpdf/examples/example_033.php create mode 100644 tools/tcpdf/examples/example_034.php create mode 100644 tools/tcpdf/examples/example_035.php create mode 100644 tools/tcpdf/examples/example_036.php create mode 100644 tools/tcpdf/examples/example_037.php create mode 100644 tools/tcpdf/examples/example_038.php create mode 100644 tools/tcpdf/examples/example_039.php create mode 100644 tools/tcpdf/examples/example_040.php create mode 100644 tools/tcpdf/examples/example_041.php create mode 100644 tools/tcpdf/examples/example_042.php create mode 100644 tools/tcpdf/examples/example_043.php create mode 100644 tools/tcpdf/examples/example_044.php create mode 100644 tools/tcpdf/examples/example_045.php create mode 100644 tools/tcpdf/examples/example_046.php create mode 100644 tools/tcpdf/examples/example_047.php create mode 100644 tools/tcpdf/examples/example_048.php create mode 100644 tools/tcpdf/examples/example_049.php create mode 100644 tools/tcpdf/examples/example_050.php create mode 100644 tools/tcpdf/examples/example_051.php create mode 100644 tools/tcpdf/examples/example_052.php create mode 100644 tools/tcpdf/examples/example_053.php create mode 100644 tools/tcpdf/examples/example_054.php create mode 100644 tools/tcpdf/examples/example_055.php create mode 100644 tools/tcpdf/examples/example_056.php create mode 100644 tools/tcpdf/examples/example_057.php create mode 100644 tools/tcpdf/examples/example_058.php create mode 100644 tools/tcpdf/examples/example_059.php create mode 100644 tools/tcpdf/examples/example_060.php create mode 100644 tools/tcpdf/examples/example_061.php create mode 100644 tools/tcpdf/examples/example_062.php create mode 100644 tools/tcpdf/examples/example_063.php create mode 100644 tools/tcpdf/examples/example_064.php create mode 100644 tools/tcpdf/examples/example_065.php create mode 100644 tools/tcpdf/examples/example_066.php create mode 100644 tools/tcpdf/examples/example_067.php create mode 100644 tools/tcpdf/examples/images/_blank.png create mode 100644 tools/tcpdf/examples/images/alpha.png create mode 100644 tools/tcpdf/examples/images/image_demo.jpg create mode 100644 tools/tcpdf/examples/images/image_with_alpha.png create mode 100644 tools/tcpdf/examples/images/img.png create mode 100644 tools/tcpdf/examples/images/logo_example.gif create mode 100644 tools/tcpdf/examples/images/logo_example.jpg create mode 100644 tools/tcpdf/examples/images/logo_example.png create mode 100644 tools/tcpdf/examples/images/tcpdf_box.ai create mode 100644 tools/tcpdf/examples/images/tcpdf_box.svg create mode 100644 tools/tcpdf/examples/images/tcpdf_cell.png create mode 100644 tools/tcpdf/examples/images/tcpdf_logo.jpg create mode 100644 tools/tcpdf/examples/images/tcpdf_signature.png create mode 100644 tools/tcpdf/examples/images/testsvg.svg create mode 100644 tools/tcpdf/examples/images/tux.svg create mode 100644 tools/tcpdf/examples/index.php create mode 100644 tools/tcpdf/examples/lang/afr.php create mode 100644 tools/tcpdf/examples/lang/ara.php create mode 100644 tools/tcpdf/examples/lang/aze.php create mode 100644 tools/tcpdf/examples/lang/bel.php create mode 100644 tools/tcpdf/examples/lang/bra.php create mode 100644 tools/tcpdf/examples/lang/bul.php create mode 100644 tools/tcpdf/examples/lang/cat.php create mode 100644 tools/tcpdf/examples/lang/ces.php create mode 100644 tools/tcpdf/examples/lang/chi.php create mode 100644 tools/tcpdf/examples/lang/cym.php create mode 100644 tools/tcpdf/examples/lang/dan.php create mode 100644 tools/tcpdf/examples/lang/eng.php create mode 100644 tools/tcpdf/examples/lang/est.php create mode 100644 tools/tcpdf/examples/lang/eus.php create mode 100644 tools/tcpdf/examples/lang/far.php create mode 100644 tools/tcpdf/examples/lang/fra.php create mode 100644 tools/tcpdf/examples/lang/ger.php create mode 100644 tools/tcpdf/examples/lang/gle.php create mode 100644 tools/tcpdf/examples/lang/glg.php create mode 100644 tools/tcpdf/examples/lang/hat.php create mode 100644 tools/tcpdf/examples/lang/heb.php create mode 100644 tools/tcpdf/examples/lang/hrv.php create mode 100644 tools/tcpdf/examples/lang/hun.php create mode 100644 tools/tcpdf/examples/lang/hye.php create mode 100644 tools/tcpdf/examples/lang/ind.php create mode 100644 tools/tcpdf/examples/lang/ita.php create mode 100644 tools/tcpdf/examples/lang/jpn.php create mode 100644 tools/tcpdf/examples/lang/kat.php create mode 100644 tools/tcpdf/examples/lang/kor.php create mode 100644 tools/tcpdf/examples/lang/mkd.php create mode 100644 tools/tcpdf/examples/lang/mlt.php create mode 100644 tools/tcpdf/examples/lang/msa.php create mode 100644 tools/tcpdf/examples/lang/nld.php create mode 100644 tools/tcpdf/examples/lang/nob.php create mode 100644 tools/tcpdf/examples/lang/pol.php create mode 100644 tools/tcpdf/examples/lang/por.php create mode 100644 tools/tcpdf/examples/lang/ron.php create mode 100644 tools/tcpdf/examples/lang/rus.php create mode 100644 tools/tcpdf/examples/lang/slv.php create mode 100644 tools/tcpdf/examples/lang/spa.php create mode 100644 tools/tcpdf/examples/lang/sqi.php create mode 100644 tools/tcpdf/examples/lang/srp.php create mode 100644 tools/tcpdf/examples/lang/swa.php create mode 100644 tools/tcpdf/examples/lang/swe.php create mode 100644 tools/tcpdf/examples/lang/ukr.php create mode 100644 tools/tcpdf/examples/lang/urd.php create mode 100644 tools/tcpdf/examples/lang/yid.php create mode 100644 tools/tcpdf/examples/lang/zho.php create mode 100644 tools/tcpdf/examples/tcpdf_include.php delete mode 100644 tools/tcpdf/fonts/ae_fonts_2.0/index.php delete mode 100644 tools/tcpdf/fonts/dejavu-fonts-ttf-2.33/index.php delete mode 100644 tools/tcpdf/fonts/dejavu-fonts-ttf-2.33/status.txt delete mode 100644 tools/tcpdf/fonts/dejavu-fonts-ttf-2.34/index.php delete mode 100644 tools/tcpdf/fonts/dejavu-fonts-ttf-2.34/status.txt delete mode 100644 tools/tcpdf/fonts/freefont-20100919/index.php delete mode 100644 tools/tcpdf/fonts/freefont-20120503/index.php delete mode 100644 tools/tcpdf/fonts/index.php delete mode 100644 tools/tcpdf/include/barcodes/index.php delete mode 100644 tools/tcpdf/include/index.php delete mode 100644 tools/tcpdf/index.php delete mode 100644 tools/tcpdf/tools/index.php diff --git a/.travis.yml b/.travis.yml index 6f81f0d74..b1400e89e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,10 @@ sudo: required dist: trusty php: - - 5.6 - - 7.2 + - 8.1 + - 8.2 + - 8.3 + - 8.4 before_script: - sudo cp -f tests/travis-ci-apache-vhost /etc/apache2/sites-available/default diff --git a/Adapter/Adapter_ProductPriceCalculator.php b/Adapter/Adapter_ProductPriceCalculator.php index 91e9b370f..ed3e04a30 100644 --- a/Adapter/Adapter_ProductPriceCalculator.php +++ b/Adapter/Adapter_ProductPriceCalculator.php @@ -42,7 +42,7 @@ class Adapter_ProductPriceCalculator &$specific_price_output = null, $with_ecotax = true, $use_group_reduction = true, - Context $context = null, + ?Context $context = null, $use_customer_price = true, $id_roomtype = false ) { diff --git a/classes/Cart.php b/classes/Cart.php index bc233be1e..aebd18936 100644 --- a/classes/Cart.php +++ b/classes/Cart.php @@ -1056,7 +1056,7 @@ class CartCore extends ObjectModel /* If we have a product combination, the minimal quantity is set with the one of this combination */ if (!empty($id_product_attribute)) { - $minimal_quantity = (int)Attribute::getAttributeMinimalQty($id_product_attribute); + $minimal_quantity = (int)ProductAttribute::getAttributeMinimalQty($id_product_attribute); } else { $minimal_quantity = (int)$product->minimal_quantity; } diff --git a/classes/Context.php b/classes/Context.php index d616ff8d1..69c1204b5 100644 --- a/classes/Context.php +++ b/classes/Context.php @@ -124,8 +124,8 @@ class ContextCore public function getMobileDetect() { if ($this->mobile_detect === null) { - require_once(_PS_TOOL_DIR_.'mobile_Detect/Mobile_Detect.php'); - $this->mobile_detect = new Mobile_Detect(); + require_once(_PS_TOOL_DIR_.'mobile_detect/autoload.php'); + $this->mobile_detect = new Detection\MobileDetect(); } return $this->mobile_detect; } diff --git a/classes/Attribute.php b/classes/ProductAttribute.php similarity index 98% rename from classes/Attribute.php rename to classes/ProductAttribute.php index 2afe1f29d..7c2a69ba2 100644 --- a/classes/Attribute.php +++ b/classes/ProductAttribute.php @@ -24,7 +24,7 @@ * International Registered Trademark & Property of PrestaShop SA */ -class AttributeCore extends ObjectModel +class ProductAttributeCore extends ObjectModel { /** @var int Group id which attribute belongs */ public $id_attribute_group; @@ -125,7 +125,7 @@ class AttributeCore extends ObjectModel public function add($autodate = true, $null_values = false) { if ($this->position <= 0) { - $this->position = Attribute::getHigherPosition($this->id_attribute_group) + 1; + $this->position = ProductAttribute::getHigherPosition($this->id_attribute_group) + 1; } $return = parent::add($autodate, $null_values); @@ -198,7 +198,7 @@ class AttributeCore extends ObjectModel * @param int $qty Quantity needed * @return bool Quantity is available or not */ - public static function checkAttributeQty($id_product_attribute, $qty, Shop $shop = null) + public static function checkAttributeQty($id_product_attribute, $qty, ?Shop $shop = null) { if (!$shop) { $shop = Context::getContext()->shop; @@ -231,7 +231,7 @@ class AttributeCore extends ObjectModel Tools::displayAsDeprecated(); $id_product = (int)$arr['id_product']; - $qty = Attribute::getAttributeQty($id_product); + $qty = ProductAttribute::getAttributeQty($id_product); if ($qty !== false) { $arr['quantity'] = (int)$qty; diff --git a/classes/Smarty/SmartyCustom.php b/classes/Smarty/SmartyCustom.php index 4bbb55557..d719e9da0 100644 --- a/classes/Smarty/SmartyCustom.php +++ b/classes/Smarty/SmartyCustom.php @@ -26,6 +26,8 @@ class SmartyCustomCore extends Smarty { + public $template_class = null; + public function __construct() { parent::__construct(); diff --git a/classes/controller/Controller.php b/classes/controller/Controller.php index 8908d6159..31e93ec73 100644 --- a/classes/controller/Controller.php +++ b/classes/controller/Controller.php @@ -597,7 +597,12 @@ abstract class ControllerCore */ public static function myErrorHandler($errno, $errstr, $errfile, $errline) { - if (error_reporting() === 0) { + /** + * Before PHP 8.0.0, the $errno was always if expression prepended by the @ error-control operator. + * @see https://www.php.net/manual/fr/function.set-error-handler.php + * @see https://www.php.net/manual/en/language.operators.errorcontrol.php + */ + if (!(error_reporting() & $errno)) { return false; } diff --git a/classes/controller/FrontController.php b/classes/controller/FrontController.php index 0352b29a1..974571a6c 100644 --- a/classes/controller/FrontController.php +++ b/classes/controller/FrontController.php @@ -790,7 +790,11 @@ class FrontControllerCore extends Controller Context::getContext()->cookie->write(); if ($this->maintenance == true || !(int)Configuration::get('PS_SHOP_ENABLE')) { $this->maintenance = true; - if (!in_array(Tools::getRemoteAddr(), explode(',', Configuration::get('PS_MAINTENANCE_IP')))) { + $allowedIps = array(); + if (Configuration::get('PS_MAINTENANCE_IP')) { + $allowedIps = explode(',', Configuration::get('PS_MAINTENANCE_IP')); + } + if (!$allowedIps || !in_array(Tools::getRemoteAddr(), $allowedIps)) { header('HTTP/1.1 503 temporarily overloaded'); $this->context->smarty->assign($this->initLogoAndFavicon()); @@ -1032,48 +1036,63 @@ class FrontControllerCore extends Controller if (!in_array($_SERVER['SERVER_NAME'], array('localhost', '127.0.0.1'))) { /* Check if Maxmind Database exists */ if (@filemtime(_PS_GEOIP_DIR_._PS_GEOIP_CITY_FILE_)) { - if (!isset($this->context->cookie->iso_code_country) || (isset($this->context->cookie->iso_code_country) && !in_array(strtoupper($this->context->cookie->iso_code_country), explode(';', Configuration::get('PS_ALLOWED_COUNTRIES'))))) { - include_once(_PS_GEOIP_DIR_.'geoipcity.inc'); + if (!isset($this->context->cookie->iso_code_country) || (isset($this->context->cookie->iso_code_country) + && !in_array(strtoupper($this->context->cookie->iso_code_country), explode(';', Configuration::get('PS_ALLOWED_COUNTRIES')))) + ) { + include_once(_PS_GEOIP_DIR_.'autoload.php'); - $gi = geoip_open(realpath(_PS_GEOIP_DIR_._PS_GEOIP_CITY_FILE_), GEOIP_STANDARD); - $record = geoip_record_by_addr($gi, Tools::getRemoteAddr()); + $reader = new GeoIp2\Database\Reader(_PS_GEOIP_DIR_ . _PS_GEOIP_CITY_FILE_); + try { + $record = $reader->city(Tools::getRemoteAddr()); + } catch (GeoIp2\Exception\AddressNotFoundException $e) { + $record = null; + } if (is_object($record)) { - if (!in_array(strtoupper($record->country_code), explode(';', Configuration::get('PS_ALLOWED_COUNTRIES'))) && !FrontController::isInWhitelistForGeolocation()) { + if (!in_array(strtoupper($record->country->isoCode), explode(';', Configuration::get('PS_ALLOWED_COUNTRIES'))) + && !FrontController::isInWhitelistForGeolocation() + ) { if (Configuration::get('PS_GEOLOCATION_BEHAVIOR') == _PS_GEOLOCATION_NO_CATALOG_) { $this->restrictedCountry = true; } elseif (Configuration::get('PS_GEOLOCATION_BEHAVIOR') == _PS_GEOLOCATION_NO_ORDER_) { $this->context->smarty->assign(array( 'restricted_country_mode' => true, - 'geolocation_country' => $record->country_name + 'geolocation_country' => $record->country->name )); } } else { $has_been_set = !isset($this->context->cookie->iso_code_country); - $this->context->cookie->iso_code_country = strtoupper($record->country_code); + $this->context->cookie->iso_code_country = strtoupper($record->country->isoCode); } } } - if (isset($this->context->cookie->iso_code_country) && $this->context->cookie->iso_code_country && !Validate::isLanguageIsoCode($this->context->cookie->iso_code_country)) { + if (isset($this->context->cookie->iso_code_country) + && $this->context->cookie->iso_code_country + && !Validate::isLanguageIsoCode($this->context->cookie->iso_code_country) + ) { $this->context->cookie->iso_code_country = Country::getIsoById(Configuration::get('PS_COUNTRY_DEFAULT')); } - if (isset($this->context->cookie->iso_code_country) && ($id_country = (int)Country::getByIso(strtoupper($this->context->cookie->iso_code_country)))) { + if (isset($this->context->cookie->iso_code_country) + && ($id_country = (int)Country::getByIso(strtoupper($this->context->cookie->iso_code_country))) + ) { /* Update defaultCountry */ if ($default_country->iso_code != $this->context->cookie->iso_code_country) { $default_country = new Country($id_country); } + if (isset($has_been_set) && $has_been_set) { $this->context->cookie->id_currency = (int)($default_country->id_currency ? (int)$default_country->id_currency : (int)Configuration::get('PS_CURRENCY_DEFAULT')); } + return $default_country; } elseif (Configuration::get('PS_GEOLOCATION_NA_BEHAVIOR') == _PS_GEOLOCATION_NO_CATALOG_ && !FrontController::isInWhitelistForGeolocation()) { $this->restrictedCountry = true; } elseif (Configuration::get('PS_GEOLOCATION_NA_BEHAVIOR') == _PS_GEOLOCATION_NO_ORDER_ && !FrontController::isInWhitelistForGeolocation()) { $this->context->smarty->assign(array( 'restricted_country_mode' => true, - 'geolocation_country' => isset($record->country_name) && $record->country_name ? $record->country_name : 'Undefined' + 'geolocation_country' => isset($record->country->name) && $record->country->name ? $record->country->name : 'Undefined' )); } } diff --git a/config/smarty.config.inc.php b/config/smarty.config.inc.php index e350e1780..e66e38348 100644 --- a/config/smarty.config.inc.php +++ b/config/smarty.config.inc.php @@ -62,7 +62,7 @@ if (defined('_PS_ADMIN_DIR_')) { } else { require_once(dirname(__FILE__).'/smartyfront.config.inc.php'); } -require_once SMARTY_PLUGINS_DIR.'modifier.truncate.php'; +require_once SMARTY_PLUGINS_DIR . 'modifier.truncate.php'; // This escape modifier is required for invoice PDF generation function smartyEscape($string, $esc_type = 'html', $char_set = null, $double_encode = true) diff --git a/controllers/admin/AdminAttributeGeneratorController.php b/controllers/admin/AdminAttributeGeneratorController.php index 8eac6b357..6135c8ccf 100644 --- a/controllers/admin/AdminAttributeGeneratorController.php +++ b/controllers/admin/AdminAttributeGeneratorController.php @@ -239,7 +239,7 @@ class AdminAttributeGeneratorControllerCore extends AdminController $this->initPageHeaderToolbar(); $this->initGroupTable(); - $attributes = Attribute::getAttributes(Context::getContext()->language->id, true); + $attributes = ProductAttribute::getAttributes(Context::getContext()->language->id, true); $attribute_js = array(); foreach ($attributes as $k => $attribute) { diff --git a/controllers/admin/AdminAttributesGroupsController.php b/controllers/admin/AdminAttributesGroupsController.php index c47cb31e3..00965cb1b 100644 --- a/controllers/admin/AdminAttributesGroupsController.php +++ b/controllers/admin/AdminAttributesGroupsController.php @@ -102,7 +102,7 @@ class AdminAttributesGroupsControllerCore extends AdminController { if (($id = Tools::getValue('id_attribute_group'))) { $this->table = 'attribute'; - $this->className = 'Attribute'; + $this->className = 'ProductAttribute'; $this->identifier = 'id_attribute'; $this->position_identifier = 'id_attribute'; $this->position_group_identifier = 'id_attribute_group'; @@ -345,13 +345,13 @@ class AdminAttributesGroupsControllerCore extends AdminController // Override var of Controller $this->table = 'attribute'; - $this->className = 'Attribute'; + $this->className = 'ProductAttribute'; $this->identifier = 'id_attribute'; $this->lang = true; $this->tpl_folder = 'attributes/'; // Create object Attribute - if (!$obj = new Attribute((int)Tools::getValue($this->identifier))) { + if (!$obj = new ProductAttribute((int)Tools::getValue($this->identifier))) { return; } @@ -480,7 +480,7 @@ class AdminAttributesGroupsControllerCore extends AdminController } $this->content .= $this->renderForm(); } elseif ($this->display == 'editAttributes') { - if (!$this->object = new Attribute((int)Tools::getValue('id_attribute'))) { + if (!$this->object = new ProductAttribute((int)Tools::getValue('id_attribute'))) { return; } @@ -614,7 +614,7 @@ class AdminAttributesGroupsControllerCore extends AdminController if (Validate::isLoadedObject($obj = new AttributeGroup((int)$id))) { $bread_extended[] = ''.$obj->name[$this->context->employee->id_lang].''; } - if (Validate::isLoadedObject($obj = new Attribute((int)$this->id_attribute))) { + if (Validate::isLoadedObject($obj = new ProductAttribute((int)$this->id_attribute))) { $bread_extended[] = sprintf($this->l('Edit: %s'), $obj->name[$this->context->employee->id_lang]); } } else { @@ -659,7 +659,7 @@ class AdminAttributesGroupsControllerCore extends AdminController { if (Tools::isSubmit('updateattribute') || Tools::isSubmit('deleteattribute') || Tools::isSubmit('submitAddattribute') || Tools::isSubmit('submitBulkdeleteattribute')) { $this->table = 'attribute'; - $this->className = 'Attribute'; + $this->className = 'ProductAttribute'; $this->identifier = 'id_attribute'; if ($this->display == 'edit') { @@ -671,7 +671,7 @@ class AdminAttributesGroupsControllerCore extends AdminController public function processPosition() { if (Tools::getIsset('viewattribute_group')) { - $object = new Attribute((int)Tools::getValue('id_attribute')); + $object = new ProductAttribute((int)Tools::getValue('id_attribute')); self::$currentIndex = self::$currentIndex.'&viewattribute_group'; } else { $object = new AttributeGroup((int)Tools::getValue('id_attribute_group')); @@ -717,7 +717,7 @@ class AdminAttributesGroupsControllerCore extends AdminController if (!Tools::getValue($this->identifier) && Tools::getValue('id_attribute') && !Tools::getValue('attributeOrderby')) { // Override var of Controller $this->table = 'attribute'; - $this->className = 'Attribute'; + $this->className = 'ProductAttribute'; $this->identifier = 'id_attribute'; } @@ -725,7 +725,7 @@ class AdminAttributesGroupsControllerCore extends AdminController if (Tools::getValue('updateattribute') || Tools::isSubmit('deleteattribute') || Tools::isSubmit('submitAddattribute')) { if ($this->tabAccess['edit'] !== '1') { $this->errors[] = Tools::displayError('You do not have permission to edit this.'); - } elseif (!$object = new Attribute((int)Tools::getValue($this->identifier))) { + } elseif (!$object = new ProductAttribute((int)Tools::getValue($this->identifier))) { $this->errors[] = Tools::displayError('An error occurred while updating the status for an object.').' '.$this->table.' '.Tools::displayError('(cannot load object)'); } @@ -864,7 +864,7 @@ class AdminAttributesGroupsControllerCore extends AdminController { // If we are deleting attributes instead of attribute_groups if (Tools::getIsset('attributeBox')) { - $this->className = 'Attribute'; + $this->className = 'ProductAttribute'; $this->table = 'attribute'; $this->boxes = Tools::getValue($this->table.'Box'); } @@ -923,7 +923,7 @@ class AdminAttributesGroupsControllerCore extends AdminController $pos = explode('_', $value); if ((isset($pos[1]) && isset($pos[2])) && (int)$pos[2] === $id_attribute) { - if ($attribute = new Attribute((int)$pos[2])) { + if ($attribute = new ProductAttribute((int)$pos[2])) { if (isset($position) && $attribute->updatePosition($way, $position)) { echo 'ok position '.(int)$position.' for attribute '.(int)$pos[2].'\r\n'; } else { diff --git a/controllers/admin/AdminCartsController.php b/controllers/admin/AdminCartsController.php index 551ea5ce9..137758897 100644 --- a/controllers/admin/AdminCartsController.php +++ b/controllers/admin/AdminCartsController.php @@ -533,7 +533,7 @@ class AdminCartsControllerCore extends AdminController // Don't try to use a product if not instanciated before due to errors if (isset($product) && $product->id) { if (($id_product_attribute = Tools::getValue('id_product_attribute')) != 0) { - if (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !Attribute::checkAttributeQty((int)$id_product_attribute, (int)$qty)) { + if (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !ProductAttribute::checkAttributeQty((int)$id_product_attribute, (int)$qty)) { $errors[] = Tools::displayError('There is not enough product in stock.'); } } elseif (!$product->checkQty((int)$qty)) { @@ -558,7 +558,7 @@ class AdminCartsControllerCore extends AdminController if (!($qty_upd = $this->context->cart->updateQty($qty, $id_product, (int)$id_product_attribute, (int)$id_customization, $operator))) { $errors[] = Tools::displayError('You already have the maximum quantity available for this product.'); } elseif ($qty_upd < 0) { - $minimal_qty = $id_product_attribute ? Attribute::getAttributeMinimalQty((int)$id_product_attribute) : $product->minimal_quantity; + $minimal_qty = $id_product_attribute ? ProductAttribute::getAttributeMinimalQty((int)$id_product_attribute) : $product->minimal_quantity; $errors[] = sprintf(Tools::displayError('You must add a minimum quantity of %d', false), $minimal_qty); } } diff --git a/controllers/admin/AdminGeolocationController.php b/controllers/admin/AdminGeolocationController.php index 4c960a331..dfdfd2792 100644 --- a/controllers/admin/AdminGeolocationController.php +++ b/controllers/admin/AdminGeolocationController.php @@ -139,9 +139,9 @@ class AdminGeolocationControllerCore extends AdminController { $this->display = 'options'; if (!$this->isGeoLiteCityAvailable()) { - $this->displayWarning($this->l('In order to use Geolocation, please download the file').' - GeoLiteCity.dat '. - $this->l('from GitHub and copy into the /tools/geoip/ directory.')); + $this->displayWarning($this->l('Since December 30, 2019, you need to register for a '). + ''.' '.$this->l('MaxMind account').''.' '. + $this->l('to get a license key to be able to download the geolocation data. Once downloaded, extract the GeoLite2 City(.mmdb) data using Winrar or Gzip into the /tools/geoip/ directory')); Configuration::updateValue('PS_GEOLOCATION_ENABLED', 0); } @@ -150,7 +150,7 @@ class AdminGeolocationControllerCore extends AdminController protected function isGeoLiteCityAvailable() { - if (@filemtime(_PS_GEOIP_DIR_._PS_GEOIP_CITY_FILE_)) { + if (file_exists(_PS_GEOIP_DIR_._PS_GEOIP_CITY_FILE_) && @filemtime(_PS_GEOIP_DIR_._PS_GEOIP_CITY_FILE_)) { return true; } diff --git a/controllers/admin/AdminOrdersController.php b/controllers/admin/AdminOrdersController.php index 9f7d1a8eb..41bbb4a50 100644 --- a/controllers/admin/AdminOrdersController.php +++ b/controllers/admin/AdminOrdersController.php @@ -4274,7 +4274,7 @@ class AdminOrdersControllerCore extends AdminController if ($update_quantity < 0) { // If product has attribute, minimal quantity is set with minimal quantity of attribute - $minimal_quantity = ($product_informations['product_attribute_id']) ? Attribute::getAttributeMinimalQty($product_informations['product_attribute_id']) : $product->minimal_quantity; + $minimal_quantity = ($product_informations['product_attribute_id']) ? ProductAttribute::getAttributeMinimalQty($product_informations['product_attribute_id']) : $product->minimal_quantity; die(Tools::jsonEncode(array('error' => sprintf(Tools::displayError('You must add %d minimum quantity', false), $minimal_quantity)))); } elseif (!$update_quantity) { die(Tools::jsonEncode(array('error' => Tools::displayError('You already have the maximum quantity available for this product.', false)))); @@ -4845,7 +4845,7 @@ class AdminOrdersControllerCore extends AdminController if ($update_quantity < 0) { // If product has attribute, minimal quantity is set with minimal quantity of attribute - $minimal_quantity = ($product_informations['product_attribute_id']) ? Attribute::getAttributeMinimalQty($product_informations['product_attribute_id']) : $product->minimal_quantity; + $minimal_quantity = ($product_informations['product_attribute_id']) ? ProductAttribute::getAttributeMinimalQty($product_informations['product_attribute_id']) : $product->minimal_quantity; die(json_encode(array('error' => sprintf(Tools::displayError('You must add %d minimum quantity', false), $minimal_quantity)))); } elseif (!$update_quantity) { die(json_encode(array('error' => Tools::displayError('You already have the maximum quantity available for this product.', false)))); diff --git a/controllers/admin/AdminSpecificPriceRuleController.php b/controllers/admin/AdminSpecificPriceRuleController.php index 783aced1d..c3b87a9de 100644 --- a/controllers/admin/AdminSpecificPriceRuleController.php +++ b/controllers/admin/AdminSpecificPriceRuleController.php @@ -317,7 +317,7 @@ class AdminSpecificPriceRuleControllerCore extends AdminController ); $attribute_groups = array(); - $attributes = Attribute::getAttributes((int)$this->context->language->id); + $attributes = ProductAttribute::getAttributes((int)$this->context->language->id); foreach ($attributes as $attribute) { if (!isset($attribute_groups[$attribute['id_attribute_group']])) { $attribute_groups[$attribute['id_attribute_group']] = array( diff --git a/controllers/front/CartController.php b/controllers/front/CartController.php index bd34ca09b..ba9e1a7ea 100644 --- a/controllers/front/CartController.php +++ b/controllers/front/CartController.php @@ -130,7 +130,7 @@ class CartControllerCore extends FrontController $product = new Product((int)$this->id_product); if (count($customization_product)) { if ($this->id_product_attribute > 0) { - $minimal_quantity = (int)Attribute::getAttributeMinimalQty($this->id_product_attribute); + $minimal_quantity = (int)ProductAttribute::getAttributeMinimalQty($this->id_product_attribute); } else { $minimal_quantity = (int)$product->minimal_quantity; } @@ -561,7 +561,7 @@ class CartControllerCore extends FrontController // Check product quantity availability if ($this->id_product_attribute) { - if (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !Attribute::checkAttributeQty($this->id_product_attribute, $qty_to_check)) { + if (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !ProductAttribute::checkAttributeQty($this->id_product_attribute, $qty_to_check)) { $this->errors[] = Tools::displayError('There isn\'t enough product in stock.', !Tools::getValue('ajax')); } } elseif ($product->hasAttributes()) { @@ -570,7 +570,7 @@ class CartControllerCore extends FrontController // @todo do something better than a redirect admin !! if (!$this->id_product_attribute) { Tools::redirectAdmin($this->context->link->getProductLink($product)); - } elseif (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !Attribute::checkAttributeQty($this->id_product_attribute, $qty_to_check)) { + } elseif (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !ProductAttribute::checkAttributeQty($this->id_product_attribute, $qty_to_check)) { $this->errors[] = Tools::displayError('There isn\'t enough product in stock.', !Tools::getValue('ajax')); } } elseif (!$product->checkQty($qty_to_check)) { @@ -680,7 +680,7 @@ class CartControllerCore extends FrontController if ($update_quantity < 0) { // If product has attribute, minimal quantity is set with minimal quantity of attribute - $minimal_quantity = ($this->id_product_attribute) ? Attribute::getAttributeMinimalQty($this->id_product_attribute) : $product->minimal_quantity; + $minimal_quantity = ($this->id_product_attribute) ? ProductAttribute::getAttributeMinimalQty($this->id_product_attribute) : $product->minimal_quantity; $this->errors[] = sprintf(Tools::displayError('You must add %d minimum quantity', !Tools::getValue('ajax')), $minimal_quantity); } elseif (!$update_quantity) { $this->errors[] = Tools::displayError('You already have the maximum quantity available for this product.', !Tools::getValue('ajax')); diff --git a/tools/defuse/php-encryption/LICENSE b/tools/defuse/php-encryption/LICENSE index f3e7c8e60..aaf2fe94e 100644 --- a/tools/defuse/php-encryption/LICENSE +++ b/tools/defuse/php-encryption/LICENSE @@ -1,7 +1,7 @@ The MIT License (MIT) -Copyright (c) 2016 Taylor Hornby and Paragon Initiative -Enterprises . +Copyright (c) 2016 Taylor Hornby +Copyright (c) 2016 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 diff --git a/tools/defuse/php-encryption/README.md b/tools/defuse/php-encryption/README.md index cd101a2cd..1394d31cb 100644 --- a/tools/defuse/php-encryption/README.md +++ b/tools/defuse/php-encryption/README.md @@ -1,12 +1,26 @@ php-encryption =============== -[![Build Status](https://travis-ci.org/defuse/php-encryption.svg?branch=master)](https://travis-ci.org/defuse/php-encryption) +![Build Status](https://app.travis-ci.com/defuse/php-encryption.svg?branch=master) +[![codecov](https://codecov.io/gh/defuse/php-encryption/branch/master/graph/badge.svg)](https://codecov.io/gh/defuse/php-encryption) +[![Latest Stable Version](https://poser.pugx.org/defuse/php-encryption/v/stable)](https://packagist.org/packages/defuse/php-encryption) +[![License](https://poser.pugx.org/defuse/php-encryption/license)](https://packagist.org/packages/defuse/php-encryption) +[![Downloads](https://img.shields.io/packagist/dt/defuse/php-encryption.svg)](https://packagist.org/packages/defuse/php-encryption) + +```terminal +composer require defuse/php-encryption +``` This is a library for encrypting data with a key or password in PHP. **It -requires PHP 5.4 or newer.** The current version is v2.0.0, which is expected to +requires PHP 5.6 or newer and OpenSSL 1.0.1 or newer.** We recommend using a +version of PHP that [still has security +support](https://www.php.net/supported-versions.php), which at the time of +writing means PHP 8.0 or later. Using this library with an unsupported +version of PHP could lead to security vulnerabilities. + +The current version of `php-encryption` is v2.4.0. This library is expected to remain stable and supported by its authors with security and bugfixes until at -least January 1st, 2019. +least January 1st, 2024. The library is a joint effort between [Taylor Hornby](https://defuse.ca/) and [Scott Arciszewski](https://paragonie.com/blog/author/scott-arcizewski) as well @@ -19,14 +33,15 @@ ecosystem. Secondly, this library is "difficult to misuse." Like [libsodium](https://github.com/jedisct1/libsodium), its API is designed to be easy to use in a secure way and hard to use in an insecure way. + Dependencies ------------ -This library requres no special dependencies except for PHP 5.4 or newer with -the OpenSSL extensions enabled (this is the default). It uses -[random\_compat](https://github.com/paragonie/random_compat), which is bundled -in with this library so that your users will not need to follow any special -installation steps. +This library requires no special dependencies except for PHP 5.6 or newer with +the OpenSSL extensions (version 1.0.1 or later) enabled (this is the default). +It uses [random\_compat](https://github.com/paragonie/random_compat), which is +bundled in with this library so that your users will not need to follow any +special installation steps. Getting Started ---------------- @@ -53,6 +68,14 @@ documentation. If you're interested in contributing to this library, see the [Internal Developer Documentation](docs/InternalDeveloperDocs.md). +Other Language Support +---------------------- + +This library is intended for server-side PHP software that needs to encrypt data at rest. +If you are building software that needs to encrypt client-side, or building a system that +requires cross-platform encryption/decryption support, we strongly recommend using +[libsodium](https://download.libsodium.org/doc/bindings_for_other_languages) instead. + Examples --------- @@ -60,6 +83,7 @@ If the documentation is not enough for you to understand how to use this library, then you can look at an example project that uses this library: - [encutil](https://github.com/defuse/encutil) +- [fileencrypt](https://github.com/tsusanka/fileencrypt) Security Audit Status --------------------- @@ -75,13 +99,23 @@ a formal audit, please [contact Taylor Hornby](https://defuse.ca/contact.htm). Public Keys ------------ -The GnuPG public key used to sign releases is available in +The GnuPG public key used to sign current and older releases is available in [dist/signingkey.asc](https://github.com/defuse/php-encryption/raw/master/dist/signingkey.asc). Its fingerprint is: ``` 2FA6 1D8D 99B9 2658 6BAC 3D53 385E E055 A129 1538 ``` -You can verify it against the Taylor Hornby's [contact +You can verify it against Taylor Hornby's [contact page](https://defuse.ca/contact.htm) and [twitter](https://twitter.com/DefuseSec/status/723741424253059074). + +Due to the old key expiring, new releases will be signed with a new public key +available in [dist/signingkey-new.asc](https://github.com/defuse/php-encryption/raw/master/dist/signingkey-new.asc). Its fingerprint is: + +``` +6DD6 E677 0281 5846 FC85 25A3 DD2E 507F 7BDB 1669 +``` + +A signature of this new key by the old key is available in +[dist/signingkey-new.asc.sig](https://github.com/defuse/php-encryption/raw/master/dist/signingkey-new.asc.sig). diff --git a/tools/defuse/php-encryption/bin/generate-defuse-key b/tools/defuse/php-encryption/bin/generate-defuse-key new file mode 100755 index 000000000..24e31b5e0 --- /dev/null +++ b/tools/defuse/php-encryption/bin/generate-defuse-key @@ -0,0 +1,14 @@ +#!/usr/bin/env php +saveToAsciiSafeString(), "\n"; diff --git a/tools/defuse/php-encryption/defuse-crypto.phar b/tools/defuse/php-encryption/defuse-crypto.phar index 74c1b849242c28201ac5378e3bf796d29fe18520..cd0354f6fdc6a2ec59d221dcdbe2be9f28a0dabf 100644 GIT binary patch delta 9065 zcmdT~3vg7`8P4WmUD%_&{6j*gA;RnQEoe|D5~C=0RK> zVcIx)cF#Hg|9|Iyo&Wsn5AV!4`AWt;r?bvxrKQc-^`SerXmVQGvX5h%=s5Kr_w)o1 zTgiAjQ<9yQ*7ST)djdAtNbdA8`aU`q)%79`?!bZP?LvMpy4?!cX)zhAXF0VV0hY(~PFB4Pe32?(dxv6)+N zW^Cdoc?tMcx|hvdk2AOLJ9jn#pQM+wnLeDUTX5?k1N(@a}c>ADc*V14Fu0>We8+iuGRwIxQXldF|m3&7J0%mPRFZrk~E#_t7!4Xu;=r zri=x-=Vs`$bSx7^`&rbl%~30w!ivF^z_BX2bqRS5huB{mmlEiA4C&T3(Wc zs3=q7jfUgUasA#yQ%qo}xnai=Oa_#&Ctb%xM|b$#_Y&~4tZSImkC3$BsWCef;LEz2 z&CJ7@2ku)iE&+ebnmsKU?;p}VUzj3c-&IWzykdQZ-EP-jyyD*(aLi8NJv-PO(3+nI zJI4Vm%r1siIi=7)u@HWqqe8*>nXtWXRz_Jd0ky8e9O32hv$Xfe=h(C}6FfFJGhwdQ zFe%pt?@Z2zB~!DsXs&3}-kIEN(_B->*)koQ`97F5Wt!HSXV29-=J)2PLYTP1==y$s zs~{_~%OQxdxI%+Lng%~*4}&o!*lt*DjW3gFN6p8FNF{G7g55@hq`T7#w4Ma zQ+VRg)9x}ss-=e(ACAGh4}Vl{tm-+HI3&Ic0~kXjv?|JlF!PZ*!buX>=fV@(WAQ*l z2!eM`ewoD$H;C~_#BJYZcPQP0TvDIBG$0kq9-Rh%OmyThcK%*266a+&lekh_@yMx6 zxZ$z+FzJa*xaPp`w2~*L*kJa-D`DS353D|r4>um1r|mnqH?szl2!cam$t8$_zl&E~ zPA(SoV44YFs&=}I$@1n^?M*)a+J;rl%Np97{EaOwtC||tK+B;wR6EU66fL1iWhh*l zOC(;2OCs|Uy4Mkt_!wSSbV=qT;hLIJG&GbSsjJszxXD$7QmZ48qb$NlWF95NMHvrt zAvqmG`ENv%q`n#LG=_1Yo?3W#!}SBoD7=6&z5$+oWKJHN273YPus2}M@U@E(S#-MQi6xe;lsXcRKf-RePh_kcP3As;B zhsO`v;nOEi!Lg@y!nIGA!i`Vw)UtllV#A3!pggk~-h1W^*P=y>7keufFAh{!S5^e@ zOGR*DCH@5$a$cUR<`;P@%fr>7h499+2cW!k2JCsR34G5@%^O~-IBV_j?x6yB;%I*A zY>SU_vpPe9M6-g+`r!AY?>71UZa3U{baCq3{(AH^SpVF3`0exGNtsA1KX%flI?y~A zg@a<8x_zOmb!Dr6ZIiF9xn+&Nc^Rp%Ba6KF=ca*RP<3oXI_LUmTp~-2QjUaJwD4k3 zK&}#hLtKz}!V%;~di64j6j5Ftug6>DQ3+CGdf|x_7eztrB2F}Al4xpJ4{8{5Hj73b zF2%r5cJnMn`DMJ&T@0E&<8rQSZ*MIv^OTWFua`87m@`B!LfUu(Lr;u#K{DJF&q z+=jZ6cGHW9<&z6&h!1v0O++dxV+f>F5y^_=$J7|%g1n3Rz+fvf=!W}v(1NG~{CC(X zO#eeY>t;_n2Q_-XU6F*YE=>5$ATD|pkF3ezu$e2F5}gFan>s7DH~Ft?!z-dG+vjWX z;nfYF9dArIa-jXh+ue>JmK5@8E@p-fNdni|IqdD=q<4YezpUBk_fw}X^cycxtBXPVlA$qhxtz{og*XV5Hdoap7jb~dc zC*d2DmOS*2;lqS5ktqsJtbSCl@#k>1#m6nr zbHT%wQngKWbyY=q1z%ZFy)dW-DuU&FC>W?Nt6CfiRD}b9vhvDmK3rW@$>}&z_n4!H zx?7MFSMbVO))|q9FI(Q&*r)F?y^@vXx^L6s9L|?cQL(PFJiL_)ZsxjpnblQ}nDH%{ z8appM7wjfR-I+}6auZI*ylI9DyZlWa?E2ShdF%(UC%+z5La1ZFxoC|_UtIJyDr47Y zXD}Ma>)OJ?E?J}EvnD&d8yTH3pCm^A7>)=rS0_w-WZnc5kK0W}(KnbX$kzESIcsPi z0^|H5k4tguHSB;Il8@J6LZSrlnZwR7DabCa0%z`$|VVw`hy>3;;4wf9oBFQx< zO%dcq(-mG;#<3_{{1&87P>B;ng}t)|zM>@!nv!}(%O0z2Cz@nnAL<74eY95yVf9hh zJqnTjqCht=koh=~`cE<-s%i5~7T1#c9!|jy-XO7X;@H zh`L4W4v8HqISek&&>fiflXIX`H@(4^g@)xX>Y#WS>@dUmP>-QlESEQ12u?E}(MraQ z$ggolhDRMJ@cli!)Wy3Dn5i-9umtO|JTf?=77VdEYcM*MHcy=!2Opf-WQZBQ89Gby zh2W{!k3@6nzCQxKOA8O{14FWr3XPODP@3XPf}+x0Qcsskw-nt%M1BkDY>6u^;YLiE zA-QR5kY_iz%h{?Ya#BRA$mGzZg;WtfFIaO*cat%!F+y|WYp#N%U>qFMmplyhC{&Zf zkh;=E1hVDqMzk54r2QNkHC9F%Ejl7yJj>Kcycq4bs_~%;Z)Lf{$bpwx?IUEri&p!H zxh_TRj~M+Ur#)=se~WH!7{O+_z0WMEFS7-xT_s>OJVBk4m)EIh+k+SQndcH7R zKZ)C=bN+#%R0tAy$2Dm!)&V|zKpDA9uSl&}#k<(5Jeti5gjKhOqa|H>-i;kj_7tN< zBAhLqGoP~Nwk+cmZiEJ+C1ZCWA4K2u)%2a~a)fX(XZrT)ZBf^n^p3rTTAJ*pD;ym0Zv; z6e9^?9V)ZvUrPHJdaJ*tW+WN-22klEAgQU3U2VNnKsnK~>b2NVJ(}9;7@#$(BnvMq zl)jcu6(nkCtE(l*e)?mgYk;pOsgYtaXAKm+&amcE6NvIqlV|)7l6D+a)@B)0Zqt6m zW$Us`8}_@v|4_%lnPSHQzIf>@2AtuduYBX9${(kLR7M`|fG` an+@s5q6zsFf0uk}G5$XdX)796H~tsC_T6Iu delta 1936 zcma)6drVVT81L;1T3Vo5KwfewE#n~wf*lW01a+uWbTaWdxU>a2gm!HenL{TKRHmYQ zC_3XCA0Y$O<1UKx!E{Ryk*UcR=bSSd$=qC6oXZk7-FI#!+x}v0^8LQ^JHPLB&dKfT zm2BD~*>+!+DietUwm*v2q>K`YuJHLwDNcDF8^#06#HlG0=OGeJzo5(GVF|-(f;`kNXN~OTp;(+DFtx}iT3h^hI3Z3Dm_^8JJn-~a9-fGk1f~j^ zjF|e9m`4(<(RsV;QS7SNW#?hBL{~sNU4R`n=1+b++$jo#PO}|Vc9)IzDjn;NrTF#b z%#vZ{@J!h@hcJ^h*sY_OKKNui&LoM^tRLfMDb`GVVCKPBria{zo|+OoZrTCGw_kM3 z=V6;PUQ;J_vlJ86A2c8<3x))#BGj~kb2`g8JMGDgUD8;JOAa2*p;_H0(TvQH;nYeV z=E#h~N&KV9mroKH18Vl|j`89_DbEy`L1aR^Jh9pV`B)9T1Dc(psk;g9e?Wf3gH;ND zQt9zrqGRzPG8BisKk+qY4mjIhHm7K|}lr*ghfJUbWnK!MUl6Byp z8VmN>GIAs5AtNmA&MKow?6X6p=om;x?lUR8SQ$vV^K@dtdAjhn5<9=f6`+kRa-!WQ zSd9sNQfG={Bsec=H(LY;+RYKfSUeeopw|Otw1#H< zM!>q}067-3Im)q`mUK3UGCsmvz}JMYg#KwHdA8#n#(SCBQf#fTn4|O+T)74MZ$?6A z%Xqlg62L^m{YC?>m-E0WTo?`t zj{*)EDc5^A9PQ)7*=XZhb>ywq5=M-@3>>i|Gv(+YG#?)YXOAs~8^^T7c>FpYzOXG4 z5{@chYr7}pb_PI4n-6g9Etvd|_Gp?lyz^bb#)It>HN -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../'); -exit; diff --git a/tools/defuse/php-encryption/dist/phar-testing-autoload.php b/tools/defuse/php-encryption/dist/phar-testing-autoload.php new file mode 100644 index 000000000..433395a79 --- /dev/null +++ b/tools/defuse/php-encryption/dist/phar-testing-autoload.php @@ -0,0 +1,4 @@ + diff --git a/tools/defuse/php-encryption/dist/signingkey-new.asc b/tools/defuse/php-encryption/dist/signingkey-new.asc new file mode 100644 index 000000000..7e3a4a1f3 --- /dev/null +++ b/tools/defuse/php-encryption/dist/signingkey-new.asc @@ -0,0 +1,53 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBF5V4TABEAC4G2BkHDaqbip3gj1oOqKh3V6LQa9QAd/f/hyhmR5hXpciPxf3 +NNHAxzoGAuB51f1YPJTNO59mGKHDuCFfr0pI94HDGoW4WgxqnUyqHBj2+/JhQPqO +lgDT0QDcfxmUd0wfZl/Ur+8SsaBYvfFWNmPaXHp9m4MMRtw9uZNIW6LlZ24JqmGy +/YUELUSH7P+uJ4HQEdixaqQ0VgIomRDI+5IwdJMtq4TSNazQm3nNmH9Em37cdi6J +NDfFRy2QxJDmuqlg8mkpS5TvrrNy/UJwIeXO9PuGaBODr8GAKWvhkpfGlxN+hWMY +01bOFnuEnOcuXw8BjPAKHqwOuGvinNmQ7lX1Rj3ssd31sTUimop0oNjOTZztpJBR +m6wO2/YGMjt+eL02NgBBDIsV837PeWuJmymTJDGQuBjZ3JWUfyT3AnkA8OU5vKjs +pM8AjIiuU7C8zQhUSHDnukTKWpBmMdOXeWNb5Ye6n60wJWzWFGlm+cYalPs+q3H8 +bxHxHEdFT0rUpxB05bc9zsZ3gGkc2NTNW/00a6gvTyX1UsBAeNgvVSHBHQGfow6o +ZKG+LnVxd+cl97ay6kP29eLypXffbXQ3hMXe9tUNBjAeiok9tssU70Epr9wTh/Fm +/iEbGc8VhS4TSk3c+3eS16rvlQ51FmAlmG6kAnN/ah+BiM4syPrWcJHIDQARAQAB +tG1kZWZ1c2UvcGhwLWVuY3J5cHRpb24gbWFpbnRhaW5lcnMgKGRlZnVzZS9waHAt +ZW5jcnlwdGlvbiByZWxlYXNlIHNpZ25pbmcga2V5KSA8cGhwLWVuY3J5cHRpb25A +ZGVmdXNlLmludmFsaWQ+iQJUBBMBCAA+FiEEbdbmdwKBWEb8hSWj3S5Qf3vbFmkF +Al5V4TACGwMFCQlmAYAFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQ3S5Qf3vb +FmnQ4Q//bHAwDI7CcTlDDktdRCP0YCRtb5zMa6vSqnZLi5aTqzmL1yQCAp1/JTwf +nlHn5xt60eKwfjIKj7Kj0n8WDFYnlOu30H5fNtFHis0xeS7GkH60tIE/pQUZILlB +Wcnx/ZPnlxccjtfSbnpelSPdvIoHVRNhh1ZYG/49kuuv8TMbMIi2FBAzGEatPoLN +f4wntoOKGvl8R2rPc2geapXTz++X+HJkddHCISR61obDRl9P0t9x+0M7gGSVMGfC +GC4wh3JB6/ha8l+DI+l88/64IKRG+M33bBwLGQ0RIhotHIy442gLJTm6TeoH8iUz +xCBwPYW+Ta1wZi17PIjHdTkNGBeEj/Hr5tTVV3oxrQVgHCymzasnz9IwcCCMwpKK +ZOMFl0+PT3TSBKLnUByvOB64YOjxU7t+sRf53Biz3yKzto5VdHGW64OG2vGFy/Xz +vI5RqU34wjtEHxWfz8y2GBnhD2TzEFCIIWPAX3TDG64NBSEBjhUraOmoVoaYJlP6 +rqxIQo4yhC+f5rnr2ZA48Hnrg0jEdVvN07FegoOnQQPpYBBkOrkTDWChn8oiXMfg +9bjv19zDOBVXl9EU+P8AhwTHz/pBKmhb97N9nYp/pbmejA+I0Kw1vZo7gaMxL938 +oQkdtWT70ZzcpcZfeKVXoZa/ddAmuxzNknZA8ZnjQ9Qhv7aNX2O5Ag0EXlXhMAEQ +AM8od4/85i7ZPmM6C1M4n4XcXeKsuZKHLvLLcRHFGkjVdXRSaxpbk2yDJiLnB9hX +GSJG2gUCT+yrimjQ71bJ4q9K2+mkVHVjdtCrCtoOYEIpMLzsRtqyAWotcVmdv8Zv +4IIjxfdxpTkj9gZmUfDIe6tbN2iBCAo1HArXq1qSdof3ui8SqdWeinkd7lZMesFm +dGQaAcHbmEakO5mRzljme8IBs3UY9j/zxEG1JbsHx9ua7CVwJ7lxi2SgSW6nF9k5 +CX5zbrDqlqSJNtDs+KbjCbI2eK+qe4qZWHPiw4bNBn6EWf97/4Os8w7Vrrpyd2eO +1JENwjlG6WG9mbJdIWWwakZ0CeH5LnJo6dV47KZbbbB6ncavaL+VpfbTCgdOGsCc +GcYUVl90/v5pPm2owx4Dg9hSfcp8fesQuq4b79NAcjF7meu5wgNdvFlfuXony+UC +W2wNi0mi9lzLD0n0j0GDzWyd3r7yXmPTL4LhrQu/pIcWIljKI3GUAQZqIYbGAO3G +7hEFT8rDWg2vKRtMag4iy5FvZFqR+7TwWJAcWnHJBZ95F9NzeYIFhp9a3hxbKXqD +xEnyGgzAszUycq29BApT4/4rDZQuXuOBd4lJp8tSzctLjvo7D3la+MWD6AlDkYT4 +bGKN9NfRCzYr2Zq3jOByAV3d5hGgyzdJlZSqXAGtbHHdABEBAAGJAjwEGAEIACYW +IQRt1uZ3AoFYRvyFJaPdLlB/e9sWaQUCXlXhMAIbDAUJCWYBgAAKCRDdLlB/e9sW +aSGfD/wPeq6lGu8ocHIkO74VPioJRKRXDVLsY02xKP64p0RHUGFTOqqB3A3UV0ue +tkizoUdfF5xkgJ18gbxXo8lotBq+Ita5hoYAfqJnTnucAPGovREJ+X1HfdK4pJqW +KNJElBz+fC4chqksiUAuH7IMImmy0/lA+LqZagzkQJU10MvmiFZ6kn+X5Mb4izRl +vAHo16eI4psApdT8Bs7mwAjgCHxS9Re46uOElB4Bx3iFPd/PEwHWnfr8x9TJZYKW +fsShG31+vfBRCfGtfKGxiAkp3EEM11lzbbfMcC3lai5iJQ/FmHgoIDeIG2Ebuk4w +/PYakSrpvkEYoMP31pVHDhzopVeURS2lpvQJ4CvTP5CVQtKrbuygow6GF8N/drCE +hdEx22pzW02ADS9fgzrlDztIOlOvC9a+epISIaEjfrc9dWhrw6chZEoWIil2MVQR +Sj0jZ8w/H7P88oHTOcFVel73ZEPg9eRUkqMnIn3DWUuqLI2SX/AtVnhdYHWTiOkq +knsGofWxUSu3RZR2ZElK9hjNKdVbGDzHGAYeJihieTKIOXpCf6Ix5B32tmFpfmBV +Q9YP3JLsRTxIMbXsJImand/r6fSjdmTpk2PovYPtE1HTJKaVHeagQdsrWw5LaJv0 +ZWuwJm0y0WJXcAEjwOHhBs0nvq2CXuZi2ZTPtY+DbsSFWhaN7g== +=Ysgx +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tools/defuse/php-encryption/dist/signingkey-new.asc.sig b/tools/defuse/php-encryption/dist/signingkey-new.asc.sig new file mode 100644 index 0000000000000000000000000000000000000000..56e1f3a0d8cf0c0387b4eb06fc034b95a8c7c353 GIT binary patch literal 566 zcmV-60?GY}0y6{v0SEvc79j*LrX7u$xh7a^tUXgWUf@-sDHS*c0$vN@000UJ5IA1o zRiP;rIO!4(|5tQbjui!J*!qyZSo6G!W2zavNU5a=22-kcA5)A4EQibr8oA`DtTuwH`rZ@PSD=v@r;Djzx?Ww@kN0BVtkj8Ij`j`#jK@YN^w2LErU~_+0 zLV!9Fif+Akxuc(xyi+q zl>P!TulL1uhr?9Ep*&_^ikxn*v@!9<%|VWUR393zN!mxpnJ)w&U{@Dc^ou80hRFrL E`21%Ku>b%7 literal 0 HcmV?d00001 diff --git a/tools/defuse/php-encryption/docs/CryptoDetails.md b/tools/defuse/php-encryption/docs/CryptoDetails.md new file mode 100644 index 000000000..43abd72ab --- /dev/null +++ b/tools/defuse/php-encryption/docs/CryptoDetails.md @@ -0,0 +1,64 @@ +Cryptography Details +===================== + +Here is a high-level description of how this library works. Any discrepancy +between this documentation and the actual implementation will be considered +a security bug. + +Let's start with the following definitions: + +- HKDF-SHA256(*k*, *n*, *info*, *s*) is the key derivation function specified in + RFC 5869 (using the SHA256 hash function). The parameters are: + - *k*: The initial keying material. + - *n*: The number of output bytes. + - *info*: The info string. + - *s*: The salt. +- AES-256-CTR(*m*, *k*, *iv*) is AES-256 encryption in CTR mode. The parameters + are: + - *m*: An arbitrary-length (possibly zero-length) message. + - *k*: A 32-byte key. + - *iv*: A 16-byte initialization vector (nonce). +- PBKDF2-SHA256(*p*, *s*, *i*, *n*) is the password-based key derivation + function defined in RFC 2898 (using the SHA256 hash function). The parameters + are: + - *p*: The password string. + - *s*: The salt string. + - *i*: The iteration count. + - *n*: The output length in bytes. +- VERSION is the string `"\xDE\xF5\x02\x00"`. +- AUTHINFO is the string `"DefusePHP|V2|KeyForAuthentication"`. +- ENCRINFO is the string `"DefusePHP|V2|KeyForEncryption"`. + +To encrypt a message *m* using a 32-byte key *k*, the following steps are taken: + +1. Generate a random 32-byte string *salt*. +2. Derive the 32-byte authentication key *akey* = HKDF-SHA256(*k*, 32, AUTHINFO, *salt*). +3. Derive the 32-byte encryption key *ekey* = HKDF-SHA256(*k*, 32, ENCRINFO, *salt*). +4. Generate a random 16-byte initialization vector *iv*. +5. Compute *c* = AES-256-CTR(*m*, *ekey*, *iv*). +6. Combine *ctxt* = VERSION || *salt* || *iv* || *c*. +7. Compute *h* = HMAC-SHA256(*ctxt*, *akey*). +8. Output *ctxt* || *h*. + +Decryption is roughly the reverse process (see the code for details, since the +security of the decryption routine is highly implementation-dependent). + +For encryption using a password *p*, steps 1-3 above are replaced by: + +1. Generate a random 32-byte string *salt*. +2. Compute *k* = PBKDF2-SHA256(SHA256(*p*), *salt*, 100000, 32). +3. Derive the 32-byte authentication key *akey* = HKDF-SHA256(*k*, 32, AUTHINFO, *salt*) +4. Derive the 32-byte encryption key *ekey* = HKDF-SHA256(*k*, 32, ENCRINFO, *salt*) + +The remainder of the process is the same. Notice the reuse of the same *salt* +for PBKDF2-SHA256 and HKDF-SHA256. The prehashing of the password in step 2 is +done to prevent a [DoS attack using long +passwords](https://github.com/defuse/php-encryption/issues/230). + +For `KeyProtectedByPassword`, the serialized key is encrypted according to the +password encryption defined above. However, the actual password used for +encryption is the SHA256 hash of the password the user provided. This is done in +order to provide domain separation between the message encryption in the user's +application and the internal key encryption done by this library. It fixes +a [key replacement chosen-protocol +attack](https://github.com/defuse/php-encryption/issues/240). diff --git a/tools/defuse/php-encryption/docs/FAQ.md b/tools/defuse/php-encryption/docs/FAQ.md new file mode 100644 index 000000000..9f7739251 --- /dev/null +++ b/tools/defuse/php-encryption/docs/FAQ.md @@ -0,0 +1,51 @@ +Frequently Asked Questions +=========================== + +How do I use this library to encrypt passwords? +------------------------------------------------ + +Passwords should not be encrypted, they should be hashed with a *slow* password +hashing function that's designed to slow down password guessing attacks. See +[How to Safely Store Your Users' Passwords in +2016](https://paragonie.com/blog/2016/02/how-safely-store-password-in-2016). + +How do I give it the same key every time instead of a new random key? +---------------------------------------------------------------------- + +A `Key` object can be saved to a string by calling its `saveToAsciiSafeString()` +method. You will have to save that string somewhere safe, and then load it back +into a `Key` object using `Key`'s `loadFromAsciiSafeString` static method. + +Where you store the string depends on your application. For example if you are +using `KeyProtectedByPassword` to encrypt files with a user's login password, +then you should not store the `Key` at all. If you are protecting sensitive data +on a server that may be compromised, then you should store it in a hardware +security module. When in doubt, consult a security expert. + +Why is an EnvironmentIsBrokenException getting thrown? +------------------------------------------------------- + +Either you've encountered a bug in this library, or your system doesn't support +the use of this library. For example, if your system does not have a secure +random number generator, this library will refuse to run, by throwing that +exception, instead of falling back to an insecure random number generator. + +Why am I getting a BadFormatException when loading a Key from a string? +------------------------------------------------------------------------ + +If you're getting this exception, then the string you're giving to +`loadFromAsciiSafeString()` is *not* the same as the string you got from +`saveToAsciiSafeString()`. Perhaps your database column isn't wide enough and +it's truncating the string as you insert it? + +Does encrypting hide the length of the plaintext? +-------------------------------------------------- + +Encryption does not, and is not intended to, hide the length of the data being +encrypted. For example, it is not safe to encrypt a field in which only a small +number of different-length values are possible (e.g. "male" or "female") since +it would be possible to tell what the plaintext is by looking at the length of +the ciphertext. In order to do this safely, it is your responsibility to, before +encrypting, pad the data out to the length of the longest string that will ever +be encrypted. This way, all plaintexts are the same length, and no information +about the plaintext can be gleaned from the length of the ciphertext. diff --git a/tools/defuse/php-encryption/docs/InstallingAndVerifying.md b/tools/defuse/php-encryption/docs/InstallingAndVerifying.md new file mode 100644 index 000000000..12b5fee43 --- /dev/null +++ b/tools/defuse/php-encryption/docs/InstallingAndVerifying.md @@ -0,0 +1,53 @@ +Getting The Code +================= + +There are two ways to use this library in your applications. You can either: + +1. Use [Composer](https://getcomposer.org/), or +2. `require_once` a single `.phar` file in your application. + +If you are not using either option (for example, because you're using Git submodules), you may need to write your own autoloader ([example](https://gist.github.com/paragonie-scott/949daee819bb7f19c50e5e103170b400)). + +Option 1: Using Composer +------------------------- + +Run this inside the directory of your composer-enabled project: + +```sh +composer require defuse/php-encryption +``` + +Unfortunately, composer doesn't provide a way for you to verify that the code +you're getting was signed by this library's authors. If you want a more secure +option, use the `.phar` method described below. + +Option 2: Including a PHAR +---------------------------- + +The `.phar` option lets you include this library into your project simply by +calling `require_once` on a single file. Download `defuse-crypto.phar` and +`defuse-crypto.phar.sig` from this project's +[releases](https://github.com/defuse/php-encryption/releases) page. + +You should verify the integrity of the `.phar`. The `defuse-crypto.phar.sig` +contains the signature of `defuse-crypto.phar`. It is signed with Taylor +Hornby's PGP key. You can find Taylor's public key in `dist/signingkey.asc`. You +can verify the public key's fingerprint against the Taylor Hornby's [contact +page](https://defuse.ca/contact.htm) and +[twitter](https://twitter.com/DefuseSec/status/723741424253059074). + +Once you have verified the signature, it is safe to use the `.phar`. Place it +somewhere in your file system, e.g. `/var/www/lib/defuse-crypto.phar`, and then +pass that path to `require_once`. + +```php + Whenever there is a conflict between security and some other property, + > security will be favored. For example, the library has runtime tests, + > which make it slower, but will hopefully stop it from encrypting stuff + > if the platform it's running on is broken. + +- Rule #2: It should be difficult to misuse the library. + + > We assume the developers using this library have no experience with + > cryptography. We only assume that they know that the "key" is something + > you need to encrypt and decrypt the messages, and that it must be kept + > secret. Whenever possible, the library should refuse to encrypt or decrypt + > messages when it is not being used correctly. + +- Rule #3: The library aims only to be compatible with itself. + + > Other PHP encryption libraries try to support every possible type of + > encryption, even the insecure ones (e.g. ECB mode). Because there are so + > many options, inexperienced developers must decide whether to use "CBC + > mode" or "ECB mode" when both are meaningless terms to them. This + > inevitably leads to vulnerabilities. + + > This library will only support one secure mode. A developer using this + > library will call "encrypt" and "decrypt" methods without worrying about + > how they are implemented. + +- Rule #4: The library should require no special installation. + + > Some PHP encryption libraries, like libsodium-php, are not straightforward + > to install and cannot packaged with "just download and extract" + > applications. This library will always be just a handful of PHP files that + > you can copy to your source tree and require(). + +Publishing Releases +-------------------- + +To make a release, you will need to install [composer](https://getcomposer.org/) +and [box](https://github.com/box-project/box2) on your system. They will need to +be available in your `$PATH` so that running the commands `composer` and `box` +in your terminal run them, respectively. You will also need the private key for +signing (ID: 7B4B2D98) available. + +Once you have those tools installed and the key available follow these steps: + +**Remember to set the version number in `composer.json`!** + +Make a fresh clone of the repository: + +``` +git clone +``` + +Check out the branch you want to release: + +``` +git checkout +``` + +Check that the version number in composer.json is correct (or not specified so that it gets picked up from the git tag): + +``` +cat composer.json +``` + +Check that the version number and support lifetime in README.md are correct: + +``` +cat README.md +``` + +Run the tests: + +``` +composer install +./test.sh +``` + +Generate the `.phar`: + +``` +cd dist +make build-phar +``` + +Test the `.phar`: + +``` +cd ../ +./test.sh dist/phar-testing-autoload.php +``` + +Sign the `.phar`: + +``` +cd dist +make sign-phar +``` + +Tag the release: + +``` +git -c user.signingkey=DD2E507F7BDB1669 tag -s "" -m "" +``` + +`` should be in the format `v2.0.0` and `` should look +like "Release of v2.0.0." + +Push the tag to github, then use the +[releases](https://github.com/defuse/php-encryption/releases) page to draft +a new release for that tag. Upload the `.phar` and the `.phar.sig` file to be +included as part of that release. diff --git a/tools/defuse/php-encryption/docs/Tutorial.md b/tools/defuse/php-encryption/docs/Tutorial.md new file mode 100644 index 000000000..a40cac376 --- /dev/null +++ b/tools/defuse/php-encryption/docs/Tutorial.md @@ -0,0 +1,314 @@ +Tutorial +========= + +Hello! If you're reading this file, it's because you want to add encryption to +one of your PHP projects. My job, as the person writing this documentation, is +to help you make sure you're doing the right thing and then show you how to use +this library to do it. To help me help you, please read the documentation +*carefully* and *deliberately*. + +A Word of Caution +------------------ + +Encryption is not magic dust you can sprinkle on a system to make it more +secure. The way encryption is integrated into a system's design needs to be +carefully thought out. Sometimes, encryption is the wrong thing to use. Other +times, encryption needs to be used in a very specific way in order for it to +work as intended. Even if you are sure of what you are doing, we strongly +recommend seeking advice from an expert. + +The first step is to think about your application's threat model. Ask yourself +the following questions. Who will want to attack my application, and what will +they get out of it? Are they trying to steal some information? Trying to alter +or destroy some information? Or just trying to make the system go down so people +can't access it? Then ask yourself how encryption can help combat those threats. +If you're going to add encryption to your application, you should have a very +clear idea of exactly which kinds of attacks it's helping to secure your +application against. Once you have your threat model, think about what kinds of +attacks it *does not* cover, and whether or not you should improve your threat +model to include those attacks. + +**This isn't for storing user login passwords:** The most common use of +cryptography in web applications is to protect the users' login passwords. If +you're trying to use this library to "encrypt" your users' passwords, you're in +the wrong place. Passwords shouldn't be *encrypted*, they should be *hashed* +with a slow computation-heavy function that makes password guessing attacks more +expensive. See [How to Safely Store Your Users' Passwords in +2016](https://paragonie.com/blog/2016/02/how-safely-store-password-in-2016). + +**This isn't for encrypting network communication:** Likewise, if you're trying +to encrypt messages sent between two parties over the Internet, you don't want +to be using this library. For that, set up a TLS connection between the two +points, or, if it's a chat app, use the [Signal +Protocol](https://whispersystems.org/blog/advanced-ratcheting/). + +What this library provides is symmetric encryption for "data at rest." This +means it is not suitable for use in building protocols where "data is in motion" +(i.e. moving over a network) except in limited set of cases. + +Please note that **encryption does not, and is not intended to, hide the +*length* of the data being encrypted.** For example, it is not safe to encrypt +a field in which only a small number of different-length values are possible +(e.g. "male" or "female") since it would be possible to tell what the plaintext +is by looking at the length of the ciphertext. In order to do this safely, it is +your responsibility to, before encrypting, pad the data out to the length of the +longest string that will ever be encrypted. This way, all plaintexts are the +same length, and no information about the plaintext can be gleaned from the +length of the ciphertext. + +Getting the Code +----------------- + +There are several different ways to obtain this library's code and to add it to +your project. Even if you've already cloned the code from GitHub, you should +take steps to verify the cryptographic signatures to make sure the code you got +was not intercepted and modified by an attacker. + +Please head over to the [**Installing and +Verifying**](InstallingAndVerifying.md) documentation to get the code, and then +come back here to continue the tutorial. + +Using the Library +------------------ + +I'm going to assume you know what symmetric encryption is, and the difference +between symmetric and asymmetric encryption. If you don't, I recommend taking +[Dan Boneh's Cryptography I course](https://www.coursera.org/learn/crypto/) on +Coursera. + +To give you a quick introduction to the library, I'm going to explain how it +would be used in two sterotypical scenarios. Hopefully, one of these sterotypes +is close enough to what you want to do that you'll be able to figure out what +needs to be different on your own. + +### Formal Documentation + +While this tutorial should get you up and running fast, it's important to +understand how this library behaves. Please make sure to read the formal +documentation of all of the functions you're using, since there are some +important security warnings there. + +The following classes are available for you to use: + +- [Crypto](classes/Crypto.md): Encrypting and decrypting strings. +- [File](classes/File.md): Encrypting and decrypting files. +- [Key](classes/Key.md): Represents a secret encryption key. +- [KeyProtectedByPassword](classes/KeyProtectedByPassword.md): Represents + a secret encryption key that needs to be "unlocked" by a password before it + can be used. + +### Scenario #1: Keep data secret from the database administrator + +In this scenario, our threat model is as follows. Alice is a server +administrator responsible for managing a trusted web server. Eve is a database +administrator responsible for managing a database server. Dave is a web +developer working on code that will eventually run on the trusted web server. + +Let's say Alice and Dave trust each other, and Alice is going to host Dave's +application on her server. But both Alice and Dave don't trust Eve. They know +Eve is a good database administrator, but she might have incentive to steal the +data from the database. They want to keep some of the web application's data +secret from Eve. + +In order to do that, Alice will use the included `generate-defuse-key` script +which generates a random encryption key and prints it to standard output: + +```sh +$ composer require defuse/php-encryption +$ vendor/bin/generate-defuse-key +``` + +Alice will run this script once and save the output to a configuration file, say +in `/etc/daveapp-secret-key.txt` and set the file permissions so that only the +user that the website PHP scripts run as can access it. + +Dave will write his code to load the key from the configuration file: + +```php +saveToAsciiSafeString(); + // ... save $protected_key_encoded into the user's account record +} +``` + +**WARNING:** Because of the way `KeyProtectedByPassword` is implemented, knowing +`SHA256($password)` is enough to decrypt a `KeyProtectedByPassword`. To be +secure, your application MUST NOT EVER compute `SHA256($password)` and use or +store it for any reason. You must also make sure that other libraries your +application is using don't compute it either. + +Then, when the user logs in, Dave's code will load the protected key from the +user's account record, unlock it to get a `Key` object, and save the `Key` +object somewhere safe (like temporary memory-backed session storage or +a cookie). Note that wherever Dave's code saves the key, it must be destroyed +once the user logs out, or else the attacker might be able to find users' keys +even if they were never logged in during the attack. + +```php +unlockKey($password); +$user_key_encoded = $user_key->saveToAsciiSafeString(); +// ... save $user_key_encoded in a cookie +``` + +```php + -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../'); -exit; diff --git a/tools/defuse/php-encryption/src/Core.php b/tools/defuse/php-encryption/src/Core.php index c489f3903..3fc20abce 100644 --- a/tools/defuse/php-encryption/src/Core.php +++ b/tools/defuse/php-encryption/src/Core.php @@ -45,32 +45,31 @@ final class Core * @throws Ex\EnvironmentIsBrokenException * * @return string + * + * @psalm-suppress RedundantCondition - It's valid to use is_int to check for overflow. */ public static function incrementCounter($ctr, $inc) { - if (Core::ourStrlen($ctr) !== Core::BLOCK_BYTE_SIZE) { - throw new Ex\EnvironmentIsBrokenException( - 'Trying to increment a nonce of the wrong size.' - ); - } + Core::ensureTrue( + Core::ourStrlen($ctr) === Core::BLOCK_BYTE_SIZE, + 'Trying to increment a nonce of the wrong size.' + ); - if (! \is_int($inc)) { - throw new Ex\EnvironmentIsBrokenException( - 'Trying to increment nonce by a non-integer.' - ); - } + Core::ensureTrue( + \is_int($inc), + 'Trying to increment nonce by a non-integer.' + ); - if ($inc < 0) { - throw new Ex\EnvironmentIsBrokenException( - 'Trying to increment nonce by a negative amount.' - ); - } + // The caller is probably re-using CTR-mode keystream if they increment by 0. + Core::ensureTrue( + $inc > 0, + 'Trying to increment a nonce by a nonpositive amount' + ); - if ($inc > PHP_INT_MAX - 255) { - throw new Ex\EnvironmentIsBrokenException( - 'Integer overflow may occur.' - ); - } + Core::ensureTrue( + $inc <= PHP_INT_MAX - 255, + 'Integer overflow may occur' + ); /* * We start at the rightmost byte (big-endian) @@ -80,11 +79,7 @@ final class Core $sum = \ord($ctr[$i]) + $inc; /* Detect integer overflow and fail. */ - if (! \is_int($sum)) { - throw new Ex\EnvironmentIsBrokenException( - 'Integer overflow in CTR mode nonce increment.' - ); - } + Core::ensureTrue(\is_int($sum), 'Integer overflow in CTR mode nonce increment'); $ctr[$i] = \pack('C', $sum & 0xFF); $inc = $sum >> 8; @@ -103,9 +98,14 @@ final class Core */ public static function secureRandom($octets) { + if ($octets <= 0) { + throw new Ex\CryptoException( + 'A zero or negative amount of random bytes was requested.' + ); + } self::ensureFunctionExists('random_bytes'); try { - return \random_bytes($octets); + return \random_bytes(max(1, $octets)); } catch (\Exception $ex) { throw new Ex\EnvironmentIsBrokenException( 'Your system does not have a secure random number generator.' @@ -124,20 +124,30 @@ final class Core * @param string $salt * * @throws Ex\EnvironmentIsBrokenException + * @psalm-suppress UndefinedFunction - We're checking if the function exists first. * * @return string */ public static function HKDF($hash, $ikm, $length, $info = '', $salt = null) { + static $nativeHKDF = null; + if ($nativeHKDF === null) { + $nativeHKDF = \is_callable('\\hash_hkdf'); + } + if ($nativeHKDF) { + if (\is_null($salt)) { + $salt = ''; + } + return \hash_hkdf($hash, $ikm, $length, $info, $salt); + } + $digest_length = Core::ourStrlen(\hash_hmac($hash, '', '', true)); // Sanity-check the desired output length. - if (empty($length) || ! \is_int($length) || - $length < 0 || $length > 255 * $digest_length) { - throw new Ex\EnvironmentIsBrokenException( - 'Bad output length requested of HKDF.' - ); - } + Core::ensureTrue( + !empty($length) && \is_int($length) && $length >= 0 && $length <= 255 * $digest_length, + 'Bad output length requested of HDKF.' + ); // "if [salt] not provided, is set to a string of HashLen zeroes." if (\is_null($salt)) { @@ -152,9 +162,7 @@ final class Core // HKDF-Expand: // This check is useless, but it serves as a reminder to the spec. - if (Core::ourStrlen($prk) < $digest_length) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(Core::ourStrlen($prk) >= $digest_length); // T(0) = '' $t = ''; @@ -172,10 +180,9 @@ final class Core } // ORM = first L octets of T + /** @var string $orm */ $orm = Core::ourSubstr($t, 0, $length); - if ($orm === false) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\is_string($orm)); return $orm; } @@ -209,9 +216,7 @@ final class Core // We're not attempting to make variable-length string comparison // secure, as that's very difficult. Make sure the strings are the same // length. - if (Core::ourStrlen($expected) !== Core::ourStrlen($given)) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(Core::ourStrlen($expected) === Core::ourStrlen($given)); $blind = Core::secureRandom(32); $message_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $given, $blind); @@ -222,27 +227,47 @@ final class Core * Throws an exception if the constant doesn't exist. * * @param string $name + * @return void * * @throws Ex\EnvironmentIsBrokenException */ public static function ensureConstantExists($name) { - if (! \defined($name)) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue( + \defined($name), + 'Constant '.$name.' does not exists' + ); } /** * Throws an exception if the function doesn't exist. * * @param string $name + * @return void * * @throws Ex\EnvironmentIsBrokenException */ public static function ensureFunctionExists($name) { - if (! \function_exists($name)) { - throw new Ex\EnvironmentIsBrokenException(); + Core::ensureTrue( + \function_exists($name), + 'function '.$name.' does not exists' + ); + } + + /** + * Throws an exception if the condition is false. + * + * @param bool $condition + * @param string $message + * @return void + * + * @throws Ex\EnvironmentIsBrokenException + */ + public static function ensureTrue($condition, $message = '') + { + if (!$condition) { + throw new Ex\EnvironmentIsBrokenException($message); } } @@ -265,13 +290,11 @@ final class Core { static $exists = null; if ($exists === null) { - $exists = \function_exists('mb_strlen'); + $exists = \extension_loaded('mbstring') && \function_exists('mb_strlen'); } if ($exists) { $length = \mb_strlen($str, '8bit'); - if ($length === false) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue($length !== false); return $length; } else { return \strlen($str); @@ -287,39 +310,52 @@ final class Core * * @throws Ex\EnvironmentIsBrokenException * - * @return string + * @return string|bool */ public static function ourSubstr($str, $start, $length = null) { static $exists = null; if ($exists === null) { - $exists = \function_exists('mb_substr'); + $exists = \extension_loaded('mbstring') && \function_exists('mb_substr'); + } + + // This is required to make mb_substr behavior identical to substr. + // Without this, mb_substr() would return false, contra to what the + // PHP documentation says (it doesn't say it can return false.) + $input_len = Core::ourStrlen($str); + if ($start === $input_len && !$length) { + return ''; + } + + if ($start > $input_len) { + return false; + } + + // mb_substr($str, 0, NULL, '8bit') returns an empty string on PHP 5.3, + // so we have to find the length ourselves. Also, substr() doesn't + // accept null for the length. + if (! isset($length)) { + if ($start >= 0) { + $length = $input_len - $start; + } else { + $length = -$start; + } + } + + if ($length < 0) { + throw new \InvalidArgumentException( + "Negative lengths are not supported with ourSubstr." + ); } if ($exists) { - // mb_substr($str, 0, NULL, '8bit') returns an empty string on PHP - // 5.3, so we have to find the length ourselves. - if (! isset($length)) { - if ($start >= 0) { - $length = Core::ourStrlen($str) - $start; - } else { - $length = -$start; - } - } - - // This is required to make mb_substr behavior identical to substr. - // Without this, mb_substr() would return false, contra to what the - // PHP documentation says (it doesn't say it can return false.) - if ($start === Core::ourStrlen($str) && $length === 0) { - return ''; - } - - if ($start > Core::ourStrlen($str)) { - return false; - } - $substr = \mb_substr($str, $start, $length, '8bit'); - if (Core::ourStrlen($substr) !== $length) { + // At this point there are two cases where mb_substr can + // legitimately return an empty string. Either $length is 0, or + // $start is equal to the length of the string (both mb_substr and + // substr return an empty string when this happens). It should never + // ever return a string that's longer than $length. + if (Core::ourStrlen($substr) > $length || (Core::ourStrlen($substr) === 0 && $length !== 0 && $start !== $input_len)) { throw new Ex\EnvironmentIsBrokenException( 'Your version of PHP has bug #66797. Its implementation of mb_substr() is incorrect. See the details here: @@ -329,12 +365,7 @@ final class Core return $substr; } - // Unlike mb_substr(), substr() doesn't accept NULL for length - if (isset($length)) { - return \substr($str, $start, $length); - } else { - return \substr($str, $start); - } + return \substr($str, $start, $length); } /** @@ -355,7 +386,15 @@ final class Core * * @return string A $key_length-byte key derived from the password and salt. */ - public static function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false) + public static function pbkdf2( + $algorithm, + #[\SensitiveParameter] + $password, + $salt, + $count, + $key_length, + $raw_output = false + ) { // Type checks: if (! \is_string($algorithm)) { @@ -378,28 +417,22 @@ final class Core $key_length += 0; $algorithm = \strtolower($algorithm); - if (! \in_array($algorithm, \hash_algos(), true)) { - throw new Ex\EnvironmentIsBrokenException( - 'Invalid or unsupported hash algorithm.' - ); - } + Core::ensureTrue( + \in_array($algorithm, \hash_algos(), true), + 'Invalid or unsupported hash algorithm.' + ); // Whitelist, or we could end up with people using CRC32. $ok_algorithms = [ 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'ripemd160', 'ripemd256', 'ripemd320', 'whirlpool', ]; - if (! \in_array($algorithm, $ok_algorithms, true)) { - throw new Ex\EnvironmentIsBrokenException( - 'Algorithm is not a secure cryptographic hash function.' - ); - } + Core::ensureTrue( + \in_array($algorithm, $ok_algorithms, true), + 'Algorithm is not a secure cryptographic hash function.' + ); - if ($count <= 0 || $key_length <= 0) { - throw new Ex\EnvironmentIsBrokenException( - 'Invalid PBKDF2 parameters.' - ); - } + Core::ensureTrue($count > 0 && $key_length > 0, 'Invalid PBKDF2 parameters.'); if (\function_exists('hash_pbkdf2')) { // The output length is in NIBBLES (4-bits) if $raw_output is false! @@ -420,15 +453,18 @@ final class Core $last = $xorsum = \hash_hmac($algorithm, $last, $password, true); // perform the other $count - 1 iterations for ($j = 1; $j < $count; $j++) { + /** + * @psalm-suppress InvalidOperand + */ $xorsum ^= ($last = \hash_hmac($algorithm, $last, $password, true)); } $output .= $xorsum; } if ($raw_output) { - return Core::ourSubstr($output, 0, $key_length); + return (string) Core::ourSubstr($output, 0, $key_length); } else { - return Encoding::binToHex(Core::ourSubstr($output, 0, $key_length)); + return Encoding::binToHex((string) Core::ourSubstr($output, 0, $key_length)); } } } diff --git a/tools/defuse/php-encryption/src/Crypto.php b/tools/defuse/php-encryption/src/Crypto.php index 3acd6112a..f148db465 100644 --- a/tools/defuse/php-encryption/src/Crypto.php +++ b/tools/defuse/php-encryption/src/Crypto.php @@ -14,11 +14,27 @@ class Crypto * @param bool $raw_binary * * @throws Ex\EnvironmentIsBrokenException + * @throws \TypeError * * @return string */ - public static function encrypt($plaintext, Key $key, $raw_binary = false) + public static function encrypt($plaintext, $key, $raw_binary = false) { + if (!\is_string($plaintext)) { + throw new \TypeError( + 'String expected for argument 1. ' . \ucfirst(\gettype($plaintext)) . ' given instead.' + ); + } + if (!($key instanceof Key)) { + throw new \TypeError( + 'Key expected for argument 2. ' . \ucfirst(\gettype($key)) . ' given instead.' + ); + } + if (!\is_bool($raw_binary)) { + throw new \TypeError( + 'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.' + ); + } return self::encryptInternal( $plaintext, KeyOrPassword::createFromKey($key), @@ -35,11 +51,32 @@ class Crypto * @param bool $raw_binary * * @throws Ex\EnvironmentIsBrokenException + * @throws \TypeError * * @return string */ - public static function encryptWithPassword($plaintext, $password, $raw_binary = false) + public static function encryptWithPassword( + $plaintext, + #[\SensitiveParameter] + $password, + $raw_binary = false + ) { + if (!\is_string($plaintext)) { + throw new \TypeError( + 'String expected for argument 1. ' . \ucfirst(\gettype($plaintext)) . ' given instead.' + ); + } + if (!\is_string($password)) { + throw new \TypeError( + 'String expected for argument 2. ' . \ucfirst(\gettype($password)) . ' given instead.' + ); + } + if (!\is_bool($raw_binary)) { + throw new \TypeError( + 'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.' + ); + } return self::encryptInternal( $plaintext, KeyOrPassword::createFromPassword($password), @@ -54,13 +91,29 @@ class Crypto * @param Key $key * @param bool $raw_binary * + * @throws \TypeError * @throws Ex\EnvironmentIsBrokenException * @throws Ex\WrongKeyOrModifiedCiphertextException * * @return string */ - public static function decrypt($ciphertext, Key $key, $raw_binary = false) + public static function decrypt($ciphertext, $key, $raw_binary = false) { + if (!\is_string($ciphertext)) { + throw new \TypeError( + 'String expected for argument 1. ' . \ucfirst(\gettype($ciphertext)) . ' given instead.' + ); + } + if (!($key instanceof Key)) { + throw new \TypeError( + 'Key expected for argument 2. ' . \ucfirst(\gettype($key)) . ' given instead.' + ); + } + if (!\is_bool($raw_binary)) { + throw new \TypeError( + 'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.' + ); + } return self::decryptInternal( $ciphertext, KeyOrPassword::createFromKey($key), @@ -78,11 +131,32 @@ class Crypto * * @throws Ex\EnvironmentIsBrokenException * @throws Ex\WrongKeyOrModifiedCiphertextException + * @throws \TypeError * * @return string */ - public static function decryptWithPassword($ciphertext, $password, $raw_binary = false) + public static function decryptWithPassword( + $ciphertext, + #[\SensitiveParameter] + $password, + $raw_binary = false + ) { + if (!\is_string($ciphertext)) { + throw new \TypeError( + 'String expected for argument 1. ' . \ucfirst(\gettype($ciphertext)) . ' given instead.' + ); + } + if (!\is_string($password)) { + throw new \TypeError( + 'String expected for argument 2. ' . \ucfirst(\gettype($password)) . ' given instead.' + ); + } + if (!\is_bool($raw_binary)) { + throw new \TypeError( + 'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.' + ); + } return self::decryptInternal( $ciphertext, KeyOrPassword::createFromPassword($password), @@ -98,11 +172,27 @@ class Crypto * * @throws Ex\EnvironmentIsBrokenException * @throws Ex\WrongKeyOrModifiedCiphertextException + * @throws \TypeError * * @return string */ - public static function legacyDecrypt($ciphertext, $key) + public static function legacyDecrypt( + $ciphertext, + #[\SensitiveParameter] + $key + ) { + if (!\is_string($ciphertext)) { + throw new \TypeError( + 'String expected for argument 1. ' . \ucfirst(\gettype($ciphertext)) . ' given instead.' + ); + } + if (!\is_string($key)) { + throw new \TypeError( + 'String expected for argument 2. ' . \ucfirst(\gettype($key)) . ' given instead.' + ); + } + RuntimeTests::runtimeTest(); // Extract the HMAC from the front of the ciphertext. @@ -111,14 +201,16 @@ class Crypto 'Ciphertext is too short.' ); } + /** + * @var string + */ $hmac = Core::ourSubstr($ciphertext, 0, Core::LEGACY_MAC_BYTE_SIZE); - if ($hmac === false) { - throw new Ex\EnvironmentIsBrokenException(); - } - $ciphertext = Core::ourSubstr($ciphertext, Core::LEGACY_MAC_BYTE_SIZE); - if ($ciphertext === false) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\is_string($hmac)); + /** + * @var string + */ + $messageCiphertext = Core::ourSubstr($ciphertext, Core::LEGACY_MAC_BYTE_SIZE); + Core::ensureTrue(\is_string($messageCiphertext)); // Regenerate the same authentication sub-key. $akey = Core::HKDF( @@ -129,7 +221,7 @@ class Crypto null ); - if (self::verifyHMAC($hmac, $ciphertext, $akey)) { + if (self::verifyHMAC($hmac, $messageCiphertext, $akey)) { // Regenerate the same encryption sub-key. $ekey = Core::HKDF( Core::LEGACY_HASH_FUNCTION_NAME, @@ -140,22 +232,25 @@ class Crypto ); // Extract the IV from the ciphertext. - if (Core::ourStrlen($ciphertext) <= Core::LEGACY_BLOCK_BYTE_SIZE) { + if (Core::ourStrlen($messageCiphertext) <= Core::LEGACY_BLOCK_BYTE_SIZE) { throw new Ex\WrongKeyOrModifiedCiphertextException( 'Ciphertext is too short.' ); } - $iv = Core::ourSubstr($ciphertext, 0, Core::LEGACY_BLOCK_BYTE_SIZE); - if ($iv === false) { - throw new Ex\EnvironmentIsBrokenException(); - } - $ciphertext = Core::ourSubstr($ciphertext, Core::LEGACY_BLOCK_BYTE_SIZE); - if ($ciphertext === false) { - throw new Ex\EnvironmentIsBrokenException(); - } + /** + * @var string + */ + $iv = Core::ourSubstr($messageCiphertext, 0, Core::LEGACY_BLOCK_BYTE_SIZE); + Core::ensureTrue(\is_string($iv)); + + /** + * @var string + */ + $actualCiphertext = Core::ourSubstr($messageCiphertext, Core::LEGACY_BLOCK_BYTE_SIZE); + Core::ensureTrue(\is_string($actualCiphertext)); // Do the decryption. - $plaintext = self::plainDecrypt($ciphertext, $ekey, $iv, Core::LEGACY_CIPHER_METHOD); + $plaintext = self::plainDecrypt($actualCiphertext, $ekey, $iv, Core::LEGACY_CIPHER_METHOD); return $plaintext; } else { throw new Ex\WrongKeyOrModifiedCiphertextException( @@ -226,6 +321,7 @@ class Crypto } // Get and check the version header. + /** @var string $header */ $header = Core::ourSubstr($ciphertext, 0, Core::HEADER_VERSION_SIZE); if ($header !== Core::CURRENT_VERSION) { throw new Ex\WrongKeyOrModifiedCiphertextException( @@ -234,36 +330,34 @@ class Crypto } // Get the salt. + /** @var string $salt */ $salt = Core::ourSubstr( $ciphertext, Core::HEADER_VERSION_SIZE, Core::SALT_BYTE_SIZE ); - if ($salt === false) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\is_string($salt)); // Get the IV. + /** @var string $iv */ $iv = Core::ourSubstr( $ciphertext, Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE, Core::BLOCK_BYTE_SIZE ); - if ($iv === false) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\is_string($iv)); // Get the HMAC. + /** @var string $hmac */ $hmac = Core::ourSubstr( $ciphertext, Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE, Core::MAC_BYTE_SIZE ); - if ($hmac === false) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\is_string($hmac)); // Get the actual encrypted ciphertext. + /** @var string $encrypted */ $encrypted = Core::ourSubstr( $ciphertext, Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + @@ -271,9 +365,7 @@ class Crypto Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE - Core::SALT_BYTE_SIZE - Core::BLOCK_BYTE_SIZE - Core::HEADER_VERSION_SIZE ); - if ($encrypted === false) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\is_string($encrypted)); // Derive the separate encryption and authentication keys from the key // or password, whichever it is. @@ -300,10 +392,17 @@ class Crypto * * @return string */ - protected static function plainEncrypt($plaintext, $key, $iv) + protected static function plainEncrypt( + $plaintext, + #[\SensitiveParameter] + $key, + #[\SensitiveParameter] + $iv + ) { Core::ensureConstantExists('OPENSSL_RAW_DATA'); Core::ensureFunctionExists('openssl_encrypt'); + /** @var string $ciphertext */ $ciphertext = \openssl_encrypt( $plaintext, Core::CIPHER_METHOD, @@ -312,11 +411,7 @@ class Crypto $iv ); - if ($ciphertext === false) { - throw new Ex\EnvironmentIsBrokenException( - 'openssl_encrypt() failed.' - ); - } + Core::ensureTrue(\is_string($ciphertext), 'openssl_encrypt() failed'); return $ciphertext; } @@ -333,10 +428,19 @@ class Crypto * * @return string */ - protected static function plainDecrypt($ciphertext, $key, $iv, $cipherMethod) + protected static function plainDecrypt( + $ciphertext, + #[\SensitiveParameter] + $key, + #[\SensitiveParameter] + $iv, + $cipherMethod + ) { Core::ensureConstantExists('OPENSSL_RAW_DATA'); Core::ensureFunctionExists('openssl_decrypt'); + + /** @var string $plaintext */ $plaintext = \openssl_decrypt( $ciphertext, $cipherMethod, @@ -344,11 +448,7 @@ class Crypto OPENSSL_RAW_DATA, $iv ); - if ($plaintext === false) { - throw new Ex\EnvironmentIsBrokenException( - 'openssl_decrypt() failed.' - ); - } + Core::ensureTrue(\is_string($plaintext), 'openssl_decrypt() failed.'); return $plaintext; } @@ -356,7 +456,7 @@ class Crypto /** * Verifies an HMAC without leaking information through side-channels. * - * @param string $correct_hmac + * @param string $expected_hmac * @param string $message * @param string $key * @@ -364,9 +464,14 @@ class Crypto * * @return bool */ - protected static function verifyHMAC($correct_hmac, $message, $key) + protected static function verifyHMAC( + $expected_hmac, + $message, + #[\SensitiveParameter] + $key + ) { $message_hmac = \hash_hmac(Core::HASH_FUNCTION_NAME, $message, $key, true); - return Core::hashEquals($correct_hmac, $message_hmac); + return Core::hashEquals($message_hmac, $expected_hmac); } } diff --git a/tools/defuse/php-encryption/src/DerivedKeys.php b/tools/defuse/php-encryption/src/DerivedKeys.php index fcfc04307..86a48e5ea 100644 --- a/tools/defuse/php-encryption/src/DerivedKeys.php +++ b/tools/defuse/php-encryption/src/DerivedKeys.php @@ -2,13 +2,25 @@ namespace Defuse\Crypto; +/** + * Class DerivedKeys + * @package Defuse\Crypto + */ final class DerivedKeys { - private $akey = null; - private $ekey = null; + /** + * @var string + */ + private $akey = ''; + + /** + * @var string + */ + private $ekey = ''; /** * Returns the authentication key. + * @return string */ public function getAuthenticationKey() { @@ -17,6 +29,7 @@ final class DerivedKeys /** * Returns the encryption key. + * @return string */ public function getEncryptionKey() { diff --git a/tools/defuse/php-encryption/src/Encoding.php b/tools/defuse/php-encryption/src/Encoding.php index 6e022d779..b14044f64 100644 --- a/tools/defuse/php-encryption/src/Encoding.php +++ b/tools/defuse/php-encryption/src/Encoding.php @@ -46,6 +46,7 @@ final class Encoding * @throws Ex\EnvironmentIsBrokenException * * @return string + * @psalm-suppress TypeDoesNotContainType */ public static function hexToBin($hex_string) { @@ -77,6 +78,62 @@ final class Encoding } return $bin; } + + /** + * Remove trialing whitespace without table look-ups or branches. + * + * Calling this function may leak the length of the string as well as the + * number of trailing whitespace characters through side-channels. + * + * @param string $string + * @return string + */ + public static function trimTrailingWhitespace($string = '') + { + $length = Core::ourStrlen($string); + if ($length < 1) { + return ''; + } + do { + $prevLength = $length; + $last = $length - 1; + $chr = \ord($string[$last]); + + /* Null Byte (0x00), a.k.a. \0 */ + // if ($chr === 0x00) $length -= 1; + $sub = (($chr - 1) >> 8 ) & 1; + $length -= $sub; + $last -= $sub; + + /* Horizontal Tab (0x09) a.k.a. \t */ + $chr = \ord($string[$last]); + // if ($chr === 0x09) $length -= 1; + $sub = (((0x08 - $chr) & ($chr - 0x0a)) >> 8) & 1; + $length -= $sub; + $last -= $sub; + + /* New Line (0x0a), a.k.a. \n */ + $chr = \ord($string[$last]); + // if ($chr === 0x0a) $length -= 1; + $sub = (((0x09 - $chr) & ($chr - 0x0b)) >> 8) & 1; + $length -= $sub; + $last -= $sub; + + /* Carriage Return (0x0D), a.k.a. \r */ + $chr = \ord($string[$last]); + // if ($chr === 0x0d) $length -= 1; + $sub = (((0x0c - $chr) & ($chr - 0x0e)) >> 8) & 1; + $length -= $sub; + $last -= $sub; + + /* Space */ + $chr = \ord($string[$last]); + // if ($chr === 0x20) $length -= 1; + $sub = (((0x1f - $chr) & ($chr - 0x21)) >> 8) & 1; + $length -= $sub; + } while ($prevLength !== $length && $length > 0); + return (string) Core::ourSubstr($string, 0, $length); + } /* * SECURITY NOTE ON APPLYING CHECKSUMS TO SECRETS: @@ -118,15 +175,18 @@ final class Encoding * * @return string */ - public static function saveBytesToChecksummedAsciiSafeString($header, $bytes) + public static function saveBytesToChecksummedAsciiSafeString( + $header, + #[\SensitiveParameter] + $bytes + ) { // Headers must be a constant length to prevent one type's header from // being a prefix of another type's header, leading to ambiguity. - if (Core::ourStrlen($header) !== self::SERIALIZE_HEADER_BYTES) { - throw new Ex\EnvironmentIsBrokenException( - 'Header must be ' . self::SERIALIZE_HEADER_BYTES . ' bytes.' - ); - } + Core::ensureTrue( + Core::ourStrlen($header) === self::SERIALIZE_HEADER_BYTES, + 'Header must be ' . self::SERIALIZE_HEADER_BYTES . ' bytes.' + ); return Encoding::binToHex( $header . @@ -151,16 +211,21 @@ final class Encoding * * @return string */ - public static function loadBytesFromChecksummedAsciiSafeString($expected_header, $string) + public static function loadBytesFromChecksummedAsciiSafeString( + $expected_header, + #[\SensitiveParameter] + $string + ) { // Headers must be a constant length to prevent one type's header from // being a prefix of another type's header, leading to ambiguity. - if (Core::ourStrlen($expected_header) !== self::SERIALIZE_HEADER_BYTES) { - throw new Ex\EnvironmentIsBrokenException( - 'Header must be 4 bytes.' - ); - } + Core::ensureTrue( + Core::ourStrlen($expected_header) === self::SERIALIZE_HEADER_BYTES, + 'Header must be 4 bytes.' + ); + /* If you get an exception here when attempting to load from a file, first pass your + key to Encoding::trimTrailingWhitespace() to remove newline characters, etc. */ $bytes = Encoding::hexToBin($string); /* Make sure we have enough bytes to get the version header and checksum. */ @@ -171,7 +236,7 @@ final class Encoding } /* Grab the version header. */ - $actual_header = Core::ourSubstr($bytes, 0, self::SERIALIZE_HEADER_BYTES); + $actual_header = (string) Core::ourSubstr($bytes, 0, self::SERIALIZE_HEADER_BYTES); if ($actual_header !== $expected_header) { throw new Ex\BadFormatException( @@ -180,14 +245,14 @@ final class Encoding } /* Grab the bytes that are part of the checksum. */ - $checked_bytes = Core::ourSubstr( + $checked_bytes = (string) Core::ourSubstr( $bytes, 0, Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE ); /* Grab the included checksum. */ - $checksum_a = Core::ourSubstr( + $checksum_a = (string) Core::ourSubstr( $bytes, Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE, self::CHECKSUM_BYTE_SIZE @@ -203,7 +268,7 @@ final class Encoding ); } - return Core::ourSubstr( + return (string) Core::ourSubstr( $bytes, self::SERIALIZE_HEADER_BYTES, Core::ourStrlen($bytes) - self::SERIALIZE_HEADER_BYTES - self::CHECKSUM_BYTE_SIZE diff --git a/tools/defuse/php-encryption/src/Exception/index.php b/tools/defuse/php-encryption/src/Exception/index.php deleted file mode 100644 index d9925ba54..000000000 --- a/tools/defuse/php-encryption/src/Exception/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../'); -exit; diff --git a/tools/defuse/php-encryption/src/File.php b/tools/defuse/php-encryption/src/File.php index d73907775..caf32ee48 100644 --- a/tools/defuse/php-encryption/src/File.php +++ b/tools/defuse/php-encryption/src/File.php @@ -12,6 +12,7 @@ final class File * @param string $inputFilename * @param string $outputFilename * @param Key $key + * @return void * * @throws Ex\EnvironmentIsBrokenException * @throws Ex\IOException @@ -32,11 +33,17 @@ final class File * @param string $inputFilename * @param string $outputFilename * @param string $password + * @return void * * @throws Ex\EnvironmentIsBrokenException * @throws Ex\IOException */ - public static function encryptFileWithPassword($inputFilename, $outputFilename, $password) + public static function encryptFileWithPassword( + $inputFilename, + $outputFilename, + #[\SensitiveParameter] + $password + ) { self::encryptFileInternal( $inputFilename, @@ -51,6 +58,7 @@ final class File * @param string $inputFilename * @param string $outputFilename * @param Key $key + * @return void * * @throws Ex\EnvironmentIsBrokenException * @throws Ex\IOException @@ -72,12 +80,18 @@ final class File * @param string $inputFilename * @param string $outputFilename * @param string $password + * @return void * * @throws Ex\EnvironmentIsBrokenException * @throws Ex\IOException * @throws Ex\WrongKeyOrModifiedCiphertextException */ - public static function decryptFileWithPassword($inputFilename, $outputFilename, $password) + public static function decryptFileWithPassword( + $inputFilename, + $outputFilename, + #[\SensitiveParameter] + $password + ) { self::decryptFileInternal( $inputFilename, @@ -93,6 +107,7 @@ final class File * @param resource $inputHandle * @param resource $outputHandle * @param Key $key + * @return void * * @throws Ex\EnvironmentIsBrokenException * @throws Ex\WrongKeyOrModifiedCiphertextException @@ -114,12 +129,18 @@ final class File * @param resource $inputHandle * @param resource $outputHandle * @param string $password + * @return void * * @throws Ex\EnvironmentIsBrokenException * @throws Ex\IOException * @throws Ex\WrongKeyOrModifiedCiphertextException */ - public static function encryptResourceWithPassword($inputHandle, $outputHandle, $password) + public static function encryptResourceWithPassword( + $inputHandle, + $outputHandle, + #[\SensitiveParameter] + $password + ) { self::encryptResourceInternal( $inputHandle, @@ -135,6 +156,7 @@ final class File * @param resource $inputHandle * @param resource $outputHandle * @param Key $key + * @return void * * @throws Ex\EnvironmentIsBrokenException * @throws Ex\IOException @@ -156,12 +178,18 @@ final class File * @param resource $inputHandle * @param resource $outputHandle * @param string $password + * @return void * * @throws Ex\EnvironmentIsBrokenException * @throws Ex\IOException * @throws Ex\WrongKeyOrModifiedCiphertextException */ - public static function decryptResourceWithPassword($inputHandle, $outputHandle, $password) + public static function decryptResourceWithPassword( + $inputHandle, + $outputHandle, + #[\SensitiveParameter] + $password + ) { self::decryptResourceInternal( $inputHandle, @@ -176,14 +204,21 @@ final class File * @param string $inputFilename * @param string $outputFilename * @param KeyOrPassword $secret + * @return void * * @throws Ex\CryptoException * @throws Ex\IOException */ private static function encryptFileInternal($inputFilename, $outputFilename, KeyOrPassword $secret) { + if (file_exists($inputFilename) && file_exists($outputFilename) && realpath($inputFilename) === realpath($outputFilename)) { + throw new Ex\IOException('Input and output filenames must be different.'); + } + /* Open the input file. */ + self::removePHPUnitErrorHandler(); $if = @\fopen($inputFilename, 'rb'); + self::restorePHPUnitErrorHandler(); if ($if === false) { throw new Ex\IOException( 'Cannot open input file for encrypting: ' . @@ -196,7 +231,9 @@ final class File } /* Open the output file. */ + self::removePHPUnitErrorHandler(); $of = @\fopen($outputFilename, 'wb'); + self::restorePHPUnitErrorHandler(); if ($of === false) { \fclose($if); throw new Ex\IOException( @@ -240,28 +277,37 @@ final class File * @param string $inputFilename * @param string $outputFilename * @param KeyOrPassword $secret + * @return void * * @throws Ex\CryptoException * @throws Ex\IOException */ private static function decryptFileInternal($inputFilename, $outputFilename, KeyOrPassword $secret) { + if (file_exists($inputFilename) && file_exists($outputFilename) && realpath($inputFilename) === realpath($outputFilename)) { + throw new Ex\IOException('Input and output filenames must be different.'); + } + /* Open the input file. */ + self::removePHPUnitErrorHandler(); $if = @\fopen($inputFilename, 'rb'); + self::restorePHPUnitErrorHandler(); if ($if === false) { throw new Ex\IOException( 'Cannot open input file for decrypting: ' . self::getLastErrorMessage() ); } - + if (\is_callable('\\stream_set_read_buffer')) { /* This call can fail, but the only consequence is performance. */ \stream_set_read_buffer($if, 0); } /* Open the output file. */ + self::removePHPUnitErrorHandler(); $of = @\fopen($outputFilename, 'wb'); + self::restorePHPUnitErrorHandler(); if ($of === false) { \fclose($if); throw new Ex\IOException( @@ -269,7 +315,7 @@ final class File self::getLastErrorMessage() ); } - + if (\is_callable('\\stream_set_write_buffer')) { /* This call can fail, but the only consequence is performance. */ \stream_set_write_buffer($of, 0); @@ -306,9 +352,13 @@ final class File * @param resource $inputHandle * @param resource $outputHandle * @param KeyOrPassword $secret + * @return void * * @throws Ex\EnvironmentIsBrokenException * @throws Ex\IOException + * @psalm-suppress PossiblyInvalidArgument + * Fixes erroneous errors caused by PHP 7.2 switching the return value + * of hash_init from a resource to a HashContext. */ private static function encryptResourceInternal($inputHandle, $outputHandle, KeyOrPassword $secret) { @@ -335,12 +385,12 @@ final class File $iv = Core::secureRandom($ivsize); /* Initialize a streaming HMAC state. */ + /** @var mixed $hmac */ $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey); - if ($hmac === false) { - throw new Ex\EnvironmentIsBrokenException( - 'Cannot initialize a hash context' - ); - } + Core::ensureTrue( + \is_resource($hmac) || \is_object($hmac), + 'Cannot initialize a hash context' + ); /* Write the header, salt, and IV. */ self::writeBytes( @@ -358,14 +408,18 @@ final class File $thisIv = $iv; /* How many blocks do we encrypt at a time? We increment by this value. */ - $inc = Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE; + /** + * @psalm-suppress RedundantCast + */ + $inc = (int) (Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE); /* Loop until we reach the end of the input file. */ $at_file_end = false; while (! (\feof($inputHandle) || $at_file_end)) { /* Find out if we can read a full buffer, or only a partial one. */ + /** @var int */ $pos = \ftell($inputHandle); - if ($pos === false) { + if (!\is_int($pos)) { throw new Ex\IOException( 'Could not get current position in input file during encryption' ); @@ -385,6 +439,7 @@ final class File } /* Encrypt this buffer. */ + /** @var string */ $encrypted = \openssl_encrypt( $read, Core::CIPHER_METHOD, @@ -393,11 +448,7 @@ final class File $thisIv ); - if ($encrypted === false) { - throw new Ex\EnvironmentIsBrokenException( - 'OpenSSL encryption error' - ); - } + Core::ensureTrue(\is_string($encrypted), 'OpenSSL encryption error'); /* Write this buffer's ciphertext. */ self::writeBytes($outputHandle, $encrypted, Core::ourStrlen($encrypted)); @@ -422,10 +473,14 @@ final class File * @param resource $inputHandle * @param resource $outputHandle * @param KeyOrPassword $secret + * @return void * * @throws Ex\EnvironmentIsBrokenException * @throws Ex\IOException * @throws Ex\WrongKeyOrModifiedCiphertextException + * @psalm-suppress PossiblyInvalidArgument + * Fixes erroneous errors caused by PHP 7.2 switching the return value + * of hash_init from a resource to a HashContext. */ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyOrPassword $secret) { @@ -476,18 +531,22 @@ final class File $thisIv = $iv; /* How many blocks do we encrypt at a time? We increment by this value. */ - $inc = Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE; + /** + * @psalm-suppress RedundantCast + */ + $inc = (int) (Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE); /* Get the HMAC. */ - if (\fseek($inputHandle, (-1 * Core::MAC_BYTE_SIZE), SEEK_END) === false) { + if (\fseek($inputHandle, (-1 * Core::MAC_BYTE_SIZE), SEEK_END) === -1) { throw new Ex\IOException( 'Cannot seek to beginning of MAC within input file' ); } /* Get the position of the last byte in the actual ciphertext. */ + /** @var int $cipher_end */ $cipher_end = \ftell($inputHandle); - if ($cipher_end === false) { + if (!\is_int($cipher_end)) { throw new Ex\IOException( 'Cannot read input file' ); @@ -496,25 +555,23 @@ final class File --$cipher_end; /* Read the HMAC. */ + /** @var string $stored_mac */ $stored_mac = self::readBytes($inputHandle, Core::MAC_BYTE_SIZE); /* Initialize a streaming HMAC state. */ + /** @var mixed $hmac */ $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey); - if ($hmac === false) { - throw new Ex\EnvironmentIsBrokenException( - 'Cannot initialize a hash context' - ); - } + Core::ensureTrue(\is_resource($hmac) || \is_object($hmac), 'Cannot initialize a hash context'); /* Reset file pointer to the beginning of the file after the header */ - if (\fseek($inputHandle, Core::HEADER_VERSION_SIZE, SEEK_SET) === false) { + if (\fseek($inputHandle, Core::HEADER_VERSION_SIZE, SEEK_SET) === -1) { throw new Ex\IOException( 'Cannot read seek within input file' ); } /* Seek to the start of the actual ciphertext. */ - if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize, SEEK_CUR) === false) { + if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize, SEEK_CUR) === -1) { throw new Ex\IOException( 'Cannot seek input file to beginning of ciphertext' ); @@ -525,12 +582,14 @@ final class File \hash_update($hmac, $header); \hash_update($hmac, $file_salt); \hash_update($hmac, $iv); + /** @var mixed $hmac2 */ $hmac2 = \hash_copy($hmac); $break = false; while (! $break) { + /** @var int $pos */ $pos = \ftell($inputHandle); - if ($pos === false) { + if (!\is_int($pos)) { throw new Ex\IOException( 'Could not get current position in input file during decryption' ); @@ -554,16 +613,14 @@ final class File \hash_update($hmac, $read); /* Remember this buffer-sized chunk's HMAC. */ + /** @var mixed $chunk_mac */ $chunk_mac = \hash_copy($hmac); - if ($chunk_mac === false) { - throw new Ex\EnvironmentIsBrokenException( - 'Cannot duplicate a hash context' - ); - } + Core::ensureTrue(\is_resource($chunk_mac) || \is_object($chunk_mac), 'Cannot duplicate a hash context'); $macs []= \hash_final($chunk_mac); } /* Get the final HMAC, which should match the stored one. */ + /** @var string $final_mac */ $final_mac = \hash_final($hmac, true); /* Verify the HMAC. */ @@ -576,7 +633,7 @@ final class File /* PASS #2: Decrypt and write output. */ /* Rewind to the start of the actual ciphertext. */ - if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize + Core::HEADER_VERSION_SIZE, SEEK_SET) === false) { + if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize + Core::HEADER_VERSION_SIZE, SEEK_SET) === -1) { throw new Ex\IOException( 'Could not move the input file pointer during decryption' ); @@ -584,8 +641,9 @@ final class File $at_file_end = false; while (! $at_file_end) { + /** @var int $pos */ $pos = \ftell($inputHandle); - if ($pos === false) { + if (!\is_int($pos)) { throw new Ex\IOException( 'Could not get current position in input file during decryption' ); @@ -609,12 +667,9 @@ final class File * remembered from pass #1 to ensure attackers didn't change the * ciphertext after MAC verification. */ \hash_update($hmac2, $read); + /** @var mixed $calc_mac */ $calc_mac = \hash_copy($hmac2); - if ($calc_mac === false) { - throw new Ex\EnvironmentIsBrokenException( - 'Cannot duplicate a hash context' - ); - } + Core::ensureTrue(\is_resource($calc_mac) || \is_object($calc_mac), 'Cannot duplicate a hash context'); $calc = \hash_final($calc_mac); if (empty($macs)) { @@ -628,6 +683,7 @@ final class File } /* Decrypt this buffer-sized chunk. */ + /** @var string $decrypted */ $decrypted = \openssl_decrypt( $read, Core::CIPHER_METHOD, @@ -635,11 +691,7 @@ final class File OPENSSL_RAW_DATA, $thisIv ); - if ($decrypted === false) { - throw new Ex\EnvironmentIsBrokenException( - 'OpenSSL decryption error' - ); - } + Core::ensureTrue(\is_string($decrypted), 'OpenSSL decryption error'); /* Write the plaintext to the output file. */ self::writeBytes( @@ -649,6 +701,7 @@ final class File ); /* Increment the IV by the amount of blocks in a buffer. */ + /** @var string $thisIv */ $thisIv = Core::incrementCounter($thisIv, $inc); /* WARNING: Usually, unless the file is a multiple of the buffer * size, $thisIv will contain an incorrect value here on the last @@ -661,27 +714,25 @@ final class File * * @param resource $stream * @param int $num_bytes + * @return string * * @throws Ex\IOException * @throws Ex\EnvironmentIsBrokenException - * - * @return string */ public static function readBytes($stream, $num_bytes) { - if ($num_bytes < 0) { - throw new Ex\EnvironmentIsBrokenException( - 'Tried to read less than 0 bytes' - ); - } elseif ($num_bytes === 0) { + Core::ensureTrue($num_bytes >= 0, 'Tried to read less than 0 bytes'); + + if ($num_bytes === 0) { return ''; } + $buf = ''; $remaining = $num_bytes; while ($remaining > 0 && ! \feof($stream)) { + /** @var string $read */ $read = \fread($stream, $remaining); - - if ($read === false) { + if (!\is_string($read)) { throw new Ex\IOException( 'Could not read from the file' ); @@ -703,10 +754,9 @@ final class File * @param resource $stream * @param string $buf * @param int $num_bytes + * @return int * * @throws Ex\IOException - * - * @return string */ public static function writeBytes($stream, $buf, $num_bytes = null) { @@ -726,13 +776,14 @@ final class File } $remaining = $num_bytes; while ($remaining > 0) { + /** @var int $written */ $written = \fwrite($stream, $buf, $remaining); - if ($written === false) { + if (!\is_int($written)) { throw new Ex\IOException( 'Could not write to the file' ); } - $buf = Core::ourSubstr($buf, $written, null); + $buf = (string) Core::ourSubstr($buf, $written, null); $remaining -= $written; } return $num_bytes; @@ -747,9 +798,38 @@ final class File { $error = error_get_last(); if ($error === null) { - return '[no PHP error]'; + return '[no PHP error, or you have a custom error handler set]'; } else { return $error['message']; } } + + /** + * PHPUnit sets an error handler, which prevents getLastErrorMessage() from working, + * because error_get_last does not work when custom handlers are set. + * + * This is a workaround, which should be a no-op in production deployments, to make + * getLastErrorMessage() return the error messages that the PHPUnit tests expect. + * + * If, in a production deployment, a custom error handler is set, the exception + * handling will still work as usual, but the error messages will be confusing. + * + * @return void + */ + private static function removePHPUnitErrorHandler() { + if (defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__')) { + set_error_handler(null); + } + } + + /** + * Undoes what removePHPUnitErrorHandler did. + * + * @return void + */ + private static function restorePHPUnitErrorHandler() { + if (defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__')) { + restore_error_handler(); + } + } } diff --git a/tools/defuse/php-encryption/src/Key.php b/tools/defuse/php-encryption/src/Key.php index ca7b9b2ee..1767d1f33 100644 --- a/tools/defuse/php-encryption/src/Key.php +++ b/tools/defuse/php-encryption/src/Key.php @@ -9,7 +9,10 @@ final class Key const KEY_CURRENT_VERSION = "\xDE\xF0\x00\x00"; const KEY_BYTE_SIZE = 32; - private $key_bytes = null; + /** + * @var string + */ + private $key_bytes; /** * Creates new random key. @@ -26,15 +29,27 @@ final class Key /** * Loads a Key from its encoded form. * + * By default, this function will call Encoding::trimTrailingWhitespace() + * to remove trailing CR, LF, NUL, TAB, and SPACE characters, which are + * commonly appended to files when working with text editors. + * * @param string $saved_key_string + * @param bool $do_not_trim (default: false) * * @throws Ex\BadFormatException * @throws Ex\EnvironmentIsBrokenException * * @return Key */ - public static function loadFromAsciiSafeString($saved_key_string) + public static function loadFromAsciiSafeString( + #[\SensitiveParameter] + $saved_key_string, + $do_not_trim = false + ) { + if (!$do_not_trim) { + $saved_key_string = Encoding::trimTrailingWhitespace($saved_key_string); + } $key_bytes = Encoding::loadBytesFromChecksummedAsciiSafeString(self::KEY_CURRENT_VERSION, $saved_key_string); return new Key($key_bytes); } @@ -71,13 +86,15 @@ final class Key * * @throws Ex\EnvironmentIsBrokenException */ - private function __construct($bytes) + private function __construct( + #[\SensitiveParameter] + $bytes + ) { - if (Core::ourStrlen($bytes) !== self::KEY_BYTE_SIZE) { - throw new Ex\EnvironmentIsBrokenException( - 'Bad key length.' - ); - } + Core::ensureTrue( + Core::ourStrlen($bytes) === self::KEY_BYTE_SIZE, + 'Bad key length.' + ); $this->key_bytes = $bytes; } diff --git a/tools/defuse/php-encryption/src/KeyOrPassword.php b/tools/defuse/php-encryption/src/KeyOrPassword.php index 2a46b711a..385065530 100644 --- a/tools/defuse/php-encryption/src/KeyOrPassword.php +++ b/tools/defuse/php-encryption/src/KeyOrPassword.php @@ -10,8 +10,15 @@ final class KeyOrPassword const SECRET_TYPE_KEY = 1; const SECRET_TYPE_PASSWORD = 2; - private $secret_type = null; - private $secret = null; + /** + * @var int + */ + private $secret_type = 0; + + /** + * @var Key|string + */ + private $secret; /** * Initializes an instance of KeyOrPassword from a key. @@ -32,7 +39,10 @@ final class KeyOrPassword * * @return KeyOrPassword */ - public static function createFromPassword($password) + public static function createFromPassword( + #[\SensitiveParameter] + $password + ) { return new KeyOrPassword(self::SECRET_TYPE_PASSWORD, $password); } @@ -43,17 +53,23 @@ final class KeyOrPassword * * @param string $salt * + * @throws Ex\CryptoException * @throws Ex\EnvironmentIsBrokenException * * @return DerivedKeys */ public function deriveKeys($salt) { - if (Core::ourStrlen($salt) !== Core::SALT_BYTE_SIZE) { - throw new Ex\EnvironmentIsBrokenException('Bad salt.'); - } + Core::ensureTrue( + Core::ourStrlen($salt) === Core::SALT_BYTE_SIZE, + 'Bad salt.' + ); if ($this->secret_type === self::SECRET_TYPE_KEY) { + Core::ensureTrue($this->secret instanceof Key); + /** + * @psalm-suppress PossiblyInvalidMethodCall + */ $akey = Core::HKDF( Core::HASH_FUNCTION_NAME, $this->secret->getRawBytes(), @@ -61,6 +77,9 @@ final class KeyOrPassword Core::AUTHENTICATION_INFO_STRING, $salt ); + /** + * @psalm-suppress PossiblyInvalidMethodCall + */ $ekey = Core::HKDF( Core::HASH_FUNCTION_NAME, $this->secret->getRawBytes(), @@ -70,12 +89,18 @@ final class KeyOrPassword ); return new DerivedKeys($akey, $ekey); } elseif ($this->secret_type === self::SECRET_TYPE_PASSWORD) { + Core::ensureTrue(\is_string($this->secret)); /* Our PBKDF2 polyfill is vulnerable to a DoS attack documented in * GitHub issue #230. The fix is to pre-hash the password to ensure * it is short. We do the prehashing here instead of in pbkdf2() so * that pbkdf2() still computes the function as defined by the * standard. */ + + /** + * @psalm-suppress PossiblyInvalidArgument + */ $prehash = \hash(Core::HASH_FUNCTION_NAME, $this->secret, true); + $prekey = Core::pbkdf2( Core::HASH_FUNCTION_NAME, $prehash, @@ -111,8 +136,20 @@ final class KeyOrPassword * @param int $secret_type * @param mixed $secret (either a Key or a password string) */ - private function __construct($secret_type, $secret) + private function __construct( + $secret_type, + #[\SensitiveParameter] + $secret + ) { + // The constructor is private, so these should never throw. + if ($secret_type === self::SECRET_TYPE_KEY) { + Core::ensureTrue($secret instanceof Key); + } elseif ($secret_type === self::SECRET_TYPE_PASSWORD) { + Core::ensureTrue(\is_string($secret)); + } else { + throw new Ex\EnvironmentIsBrokenException('Bad secret type.'); + } $this->secret_type = $secret_type; $this->secret = $secret; } diff --git a/tools/defuse/php-encryption/src/KeyProtectedByPassword.php b/tools/defuse/php-encryption/src/KeyProtectedByPassword.php index b9a40f157..7d90ed1fe 100644 --- a/tools/defuse/php-encryption/src/KeyProtectedByPassword.php +++ b/tools/defuse/php-encryption/src/KeyProtectedByPassword.php @@ -8,7 +8,10 @@ final class KeyProtectedByPassword { const PASSWORD_KEY_CURRENT_VERSION = "\xDE\xF1\x00\x00"; - private $encrypted_key = null; + /** + * @var string + */ + private $encrypted_key = ''; /** * Creates a random key protected by the provided password. @@ -19,7 +22,10 @@ final class KeyProtectedByPassword * * @return KeyProtectedByPassword */ - public static function createRandomPasswordProtectedKey($password) + public static function createRandomPasswordProtectedKey( + #[\SensitiveParameter] + $password + ) { $inner_key = Key::createNewRandomKey(); /* The password is hashed as a form of poor-man's domain separation @@ -44,7 +50,10 @@ final class KeyProtectedByPassword * * @return KeyProtectedByPassword */ - public static function loadFromAsciiSafeString($saved_key_string) + public static function loadFromAsciiSafeString( + #[\SensitiveParameter] + $saved_key_string + ) { $encrypted_key = Encoding::loadBytesFromChecksummedAsciiSafeString( self::PASSWORD_KEY_CURRENT_VERSION, @@ -76,9 +85,13 @@ final class KeyProtectedByPassword * @throws Ex\EnvironmentIsBrokenException * @throws Ex\WrongKeyOrModifiedCiphertextException * + * @param string $password * @return Key */ - public function unlockKey($password) + public function unlockKey( + #[\SensitiveParameter] + $password + ) { try { $inner_key_encoded = Crypto::decryptWithPassword( @@ -100,6 +113,40 @@ final class KeyProtectedByPassword } } + /** + * Changes the password. + * + * @param string $current_password + * @param string $new_password + * + * @throws Ex\EnvironmentIsBrokenException + * @throws Ex\WrongKeyOrModifiedCiphertextException + * + * @return KeyProtectedByPassword + */ + public function changePassword( + #[\SensitiveParameter] + $current_password, + #[\SensitiveParameter] + $new_password + ) + { + $inner_key = $this->unlockKey($current_password); + /* The password is hashed as a form of poor-man's domain separation + * between this use of encryptWithPassword() and other uses of + * encryptWithPassword() that the user may also be using as part of the + * same protocol. */ + $encrypted_key = Crypto::encryptWithPassword( + $inner_key->saveToAsciiSafeString(), + \hash(Core::HASH_FUNCTION_NAME, $new_password, true), + true + ); + + $this->encrypted_key = $encrypted_key; + + return $this; + } + /** * Constructor for KeyProtectedByPassword. * diff --git a/tools/defuse/php-encryption/src/RuntimeTests.php b/tools/defuse/php-encryption/src/RuntimeTests.php index 9c0ba339d..65ce55d9d 100644 --- a/tools/defuse/php-encryption/src/RuntimeTests.php +++ b/tools/defuse/php-encryption/src/RuntimeTests.php @@ -17,6 +17,7 @@ class RuntimeTests extends Crypto * Runs the runtime tests. * * @throws Ex\EnvironmentIsBrokenException + * @return void */ public static function runtimeTest() { @@ -58,13 +59,9 @@ class RuntimeTests extends Crypto RuntimeTests::HKDFTestVector(); RuntimeTests::testEncryptDecrypt(); - if (Core::ourStrlen(Key::createNewRandomKey()->getRawBytes()) != Core::KEY_BYTE_SIZE) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(Core::ourStrlen(Key::createNewRandomKey()->getRawBytes()) === Core::KEY_BYTE_SIZE); - if (Core::ENCRYPTION_INFO_STRING == Core::AUTHENTICATION_INFO_STRING) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(Core::ENCRYPTION_INFO_STRING !== Core::AUTHENTICATION_INFO_STRING); } catch (Ex\EnvironmentIsBrokenException $ex) { // Do this, otherwise it will stay in the "tests are running" state. $test_state = 3; @@ -79,6 +76,7 @@ class RuntimeTests extends Crypto * High-level tests of Crypto operations. * * @throws Ex\EnvironmentIsBrokenException + * @return void */ private static function testEncryptDecrypt() { @@ -95,9 +93,7 @@ class RuntimeTests extends Crypto // the user into thinking it's just an invalid ciphertext! throw new Ex\EnvironmentIsBrokenException(); } - if ($decrypted !== $data) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue($decrypted === $data); // Modifying the ciphertext: Appending a string. try { @@ -148,6 +144,7 @@ class RuntimeTests extends Crypto * Test HKDF against test vectors. * * @throws Ex\EnvironmentIsBrokenException + * @return void */ private static function HKDFTestVector() { @@ -164,9 +161,7 @@ class RuntimeTests extends Crypto '34007208d5b887185865' ); $computed_okm = Core::HKDF('sha256', $ikm, $length, $info, $salt); - if ($computed_okm !== $okm) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue($computed_okm === $okm); // Test Case 7 $ikm = \str_repeat("\x0c", 22); @@ -177,15 +172,14 @@ class RuntimeTests extends Crypto '673a081d70cce7acfc48' ); $computed_okm = Core::HKDF('sha1', $ikm, $length, '', null); - if ($computed_okm !== $okm) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue($computed_okm === $okm); } /** * Test HMAC against test vectors. * * @throws Ex\EnvironmentIsBrokenException + * @return void */ private static function HMACTestVector() { @@ -193,15 +187,16 @@ class RuntimeTests extends Crypto $key = \str_repeat("\x0b", 20); $data = 'Hi There'; $correct = 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7'; - if (\hash_hmac(Core::HASH_FUNCTION_NAME, $data, $key) !== $correct) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue( + \hash_hmac(Core::HASH_FUNCTION_NAME, $data, $key) === $correct + ); } /** * Test AES against test vectors. * * @throws Ex\EnvironmentIsBrokenException + * @return void */ private static function AESTestVector() { @@ -225,18 +220,9 @@ class RuntimeTests extends Crypto ); $computed_ciphertext = Crypto::plainEncrypt($plaintext, $key, $iv); - if ($computed_ciphertext !== $ciphertext) { - echo \str_repeat("\n", 30); - echo \bin2hex($computed_ciphertext); - echo "\n---\n"; - echo \bin2hex($ciphertext); - echo \str_repeat("\n", 30); - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue($computed_ciphertext === $ciphertext); $computed_plaintext = Crypto::plainDecrypt($ciphertext, $key, $iv, Core::CIPHER_METHOD); - if ($computed_plaintext !== $plaintext) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue($computed_plaintext === $plaintext); } } diff --git a/tools/defuse/php-encryption/src/index.php b/tools/defuse/php-encryption/src/index.php deleted file mode 100644 index d9925ba54..000000000 --- a/tools/defuse/php-encryption/src/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../'); -exit; diff --git a/tools/geoip/LICENSE b/tools/geoip/LICENSE index 8ee68bd4d..d64569567 100644 --- a/tools/geoip/LICENSE +++ b/tools/geoip/LICENSE @@ -1,35 +1,202 @@ -geoip.inc -Copyright (C) 2007 MaxMind LLC + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -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. + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -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. + 1. Definitions. -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 + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -geoipcity.inc + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. -Copyright (C) 2004 Maxmind LLC + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. -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. + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. -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. + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. -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 + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/tools/geoip/autoload.php b/tools/geoip/autoload.php new file mode 100644 index 000000000..46835dd3a --- /dev/null +++ b/tools/geoip/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @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', 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 string[] $classMap Class to filename map + * @psalm-param array $classMap + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $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 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) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * 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 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) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * 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 string[]|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $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 string[]|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * 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') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * 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 true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + 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 + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + * @private + */ +function includeFile($file) +{ + include $file; +} diff --git a/tools/geoip/composer/InstalledVersions.php b/tools/geoip/composer/InstalledVersions.php new file mode 100644 index 000000000..d50e0c9fc --- /dev/null +++ b/tools/geoip/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/tools/geoip/composer/LICENSE b/tools/geoip/composer/LICENSE new file mode 100644 index 000000000..f27399a04 --- /dev/null +++ b/tools/geoip/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +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/tools/geoip/composer/autoload_classmap.php b/tools/geoip/composer/autoload_classmap.php new file mode 100644 index 000000000..b26f1b13b --- /dev/null +++ b/tools/geoip/composer/autoload_classmap.php @@ -0,0 +1,10 @@ + $vendorDir . '/composer/InstalledVersions.php', +); diff --git a/tools/geoip/composer/autoload_namespaces.php b/tools/geoip/composer/autoload_namespaces.php new file mode 100644 index 000000000..b7fc0125d --- /dev/null +++ b/tools/geoip/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/maxmind/web-service-common/src/WebService'), + 'MaxMind\\Exception\\' => array($vendorDir . '/maxmind/web-service-common/src/Exception'), + 'MaxMind\\Db\\' => array($vendorDir . '/maxmind-db/reader/src/MaxMind/Db'), + 'GeoIp2\\' => array($vendorDir . '/geoip2/geoip2/src'), + 'Composer\\CaBundle\\' => array($vendorDir . '/composer/ca-bundle/src'), +); diff --git a/tools/geoip/composer/autoload_real.php b/tools/geoip/composer/autoload_real.php new file mode 100644 index 000000000..9f693eea0 --- /dev/null +++ b/tools/geoip/composer/autoload_real.php @@ -0,0 +1,57 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInitd5b813279dd5262ff846bf9ff4d279c4::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + return $loader; + } +} diff --git a/tools/geoip/composer/autoload_static.php b/tools/geoip/composer/autoload_static.php new file mode 100644 index 000000000..d33289946 --- /dev/null +++ b/tools/geoip/composer/autoload_static.php @@ -0,0 +1,62 @@ + + array ( + 'MaxMind\\WebService\\' => 19, + 'MaxMind\\Exception\\' => 18, + 'MaxMind\\Db\\' => 11, + ), + 'G' => + array ( + 'GeoIp2\\' => 7, + ), + 'C' => + array ( + 'Composer\\CaBundle\\' => 18, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'MaxMind\\WebService\\' => + array ( + 0 => __DIR__ . '/..' . '/maxmind/web-service-common/src/WebService', + ), + 'MaxMind\\Exception\\' => + array ( + 0 => __DIR__ . '/..' . '/maxmind/web-service-common/src/Exception', + ), + 'MaxMind\\Db\\' => + array ( + 0 => __DIR__ . '/..' . '/maxmind-db/reader/src/MaxMind/Db', + ), + 'GeoIp2\\' => + array ( + 0 => __DIR__ . '/..' . '/geoip2/geoip2/src', + ), + 'Composer\\CaBundle\\' => + array ( + 0 => __DIR__ . '/..' . '/composer/ca-bundle/src', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInitd5b813279dd5262ff846bf9ff4d279c4::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitd5b813279dd5262ff846bf9ff4d279c4::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInitd5b813279dd5262ff846bf9ff4d279c4::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/tools/geoip/composer/ca-bundle/LICENSE b/tools/geoip/composer/ca-bundle/LICENSE new file mode 100644 index 000000000..c5b5220e8 --- /dev/null +++ b/tools/geoip/composer/ca-bundle/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2016 Composer + +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/tools/geoip/composer/ca-bundle/README.md b/tools/geoip/composer/ca-bundle/README.md new file mode 100644 index 000000000..d8205ec53 --- /dev/null +++ b/tools/geoip/composer/ca-bundle/README.md @@ -0,0 +1,85 @@ +composer/ca-bundle +================== + +Small utility library that lets you find a path to the system CA bundle, +and includes a fallback to the Mozilla CA bundle. + +Originally written as part of [composer/composer](https://github.com/composer/composer), +now extracted and made available as a stand-alone library. + + +Installation +------------ + +Install the latest version with: + +```bash +$ composer require composer/ca-bundle +``` + + +Requirements +------------ + +* PHP 5.3.2 is required but using the latest version of PHP is highly recommended. + + +Basic usage +----------- + +### `Composer\CaBundle\CaBundle` + +- `CaBundle::getSystemCaRootBundlePath()`: Returns the system CA bundle path, or a path to the bundled one as fallback +- `CaBundle::getBundledCaBundlePath()`: Returns the path to the bundled CA file +- `CaBundle::validateCaFile($filename)`: Validates a CA file using openssl_x509_parse only if it is safe to use +- `CaBundle::isOpensslParseSafe()`: Test if it is safe to use the PHP function openssl_x509_parse() +- `CaBundle::reset()`: Resets the static caches + + +#### To use with curl + +```php +$curl = curl_init("https://example.org/"); + +$caPathOrFile = \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(); +if (is_dir($caPathOrFile)) { + curl_setopt($curl, CURLOPT_CAPATH, $caPathOrFile); +} else { + curl_setopt($curl, CURLOPT_CAINFO, $caPathOrFile); +} + +$result = curl_exec($curl); +``` + +#### To use with php streams + +```php +$opts = array( + 'http' => array( + 'method' => "GET" + ) +); + +$caPathOrFile = \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(); +if (is_dir($caPathOrFile)) { + $opts['ssl']['capath'] = $caPathOrFile; +} else { + $opts['ssl']['cafile'] = $caPathOrFile; +} + +$context = stream_context_create($opts); +$result = file_get_contents('https://example.com', false, $context); +``` + +#### To use with Guzzle + +```php +$client = new \GuzzleHttp\Client([ + \GuzzleHttp\RequestOptions::VERIFY => \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath() +]); +``` + +License +------- + +composer/ca-bundle is licensed under the MIT License, see the LICENSE file for details. diff --git a/tools/geoip/composer/ca-bundle/composer.json b/tools/geoip/composer/ca-bundle/composer.json new file mode 100644 index 000000000..c2ce2bb8e --- /dev/null +++ b/tools/geoip/composer/ca-bundle/composer.json @@ -0,0 +1,54 @@ +{ + "name": "composer/ca-bundle", + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "type": "library", + "license": "MIT", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8 || ^9", + "phpstan/phpstan": "^1.10", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Composer\\CaBundle\\": "tests" + } + }, + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "scripts": { + "test": "@php phpunit", + "phpstan": "@php phpstan analyse" + } +} diff --git a/tools/geoip/composer/ca-bundle/res/cacert.pem b/tools/geoip/composer/ca-bundle/res/cacert.pem new file mode 100644 index 000000000..eb11b2fd1 --- /dev/null +++ b/tools/geoip/composer/ca-bundle/res/cacert.pem @@ -0,0 +1,3696 @@ +## +## Bundle of CA Root Certificates +## +## Certificate data from Mozilla as of: Tue Nov 26 13:58:25 2024 GMT +## +## Find updated versions here: https://curl.se/docs/caextract.html +## +## This is a bundle of X.509 certificates of public Certificate Authorities +## (CA). These were automatically extracted from Mozilla's root certificates +## file (certdata.txt). This file can be found in the mozilla source tree: +## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt +## +## It contains the certificates in PEM format and therefore +## can be directly used with curl / libcurl / php_curl, or with +## an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## +## Conversion done with mk-ca-bundle.pl version 1.29. +## SHA256: 36105b01631f9fc03b1eca779b44a30a1a5890b9bf8dc07ccb001a07301e01cf +## + + +GlobalSign Root CA +================== +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx +GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds +b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD +VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa +DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc +THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb +Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP +c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX +gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF +AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj +Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG +j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH +hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC +X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +Entrust.net Premium 2048 Secure Server CA +========================================= +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u +ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp +bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV +BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx +NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 +d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u +ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL +Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr +hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW +nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi +VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ +KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy +T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT +J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e +nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +Baltimore CyberTrust Root +========================= +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE +ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li +ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC +SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs +dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME +uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB +UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C +G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 +XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr +l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI +VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB +BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh +cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 +hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa +Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H +RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +Entrust Root Certification Authority +==================================== +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw +b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG +A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 +MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu +MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu +Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz +A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww +Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 +j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN +rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 +MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH +hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM +Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa +v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS +W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 +tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +Comodo AAA Services root +======================== +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw +MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl +c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV +BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG +C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs +i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW +Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH +Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK +Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f +BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl +cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz +LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm +7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z +8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C +12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +QuoVadis Root CA 2 +================== +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx +ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 +XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk +lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB +lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy +lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt +66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn +wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh +D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy +BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie +J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud +DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU +a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv +Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 +UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm +VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK ++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW +IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 +WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X +f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II +4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 +VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +================== +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx +OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg +DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij +KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K +DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv +BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp +p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 +nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX +MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM +Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz +uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT +BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj +YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB +BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD +VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 +ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE +AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV +qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s +hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z +POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 +Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp +8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC +bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu +g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p +vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr +qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +XRamp Global CA Root +==================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE +BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj +dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx +HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg +U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu +IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx +foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE +zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs +AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry +xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap +oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC +AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc +/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n +nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz +8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +Go Daddy Class 2 CA +=================== +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY +VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG +A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD +ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv +2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 +qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j +YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY +vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O +BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o +atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu +MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim +PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt +I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI +Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b +vZ8= +-----END CERTIFICATE----- + +Starfield Class 2 CA +==================== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc +U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo +MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG +A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG +SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY +bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ +JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm +epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN +F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF +MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f +hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo +bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs +afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM +PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD +KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 +QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +DigiCert Assured ID Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx +MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO +9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy +UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW +/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy +oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf +GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF +66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq +hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc +EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn +SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i +8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +DigiCert Global Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw +MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn +TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 +BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H +4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y +7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB +o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm +8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF +BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr +EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt +tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 +UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +DigiCert High Assurance EV Root CA +================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw +KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw +MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ +MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu +Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t +Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS +OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 +MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ +NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe +h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY +JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ +V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp +myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK +mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +====================== +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw +EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN +MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp +c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq +t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C +jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg +vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF +ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR +AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend +jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO +peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR +7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi +GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 +OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm +5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr +44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf +Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m +Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp +mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk +vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf +KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br +NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj +viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- + +SwissSign Silver CA - G2 +======================== +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT +BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X +DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 +aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 +N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm ++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH +6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu +MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h +qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 +FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs +ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc +celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X +CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB +tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P +4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F +kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L +3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx +/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa +DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP +e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu +WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ +DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub +DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +SecureTrust CA +============== +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy +dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe +BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX +OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t +DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH +GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b +01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH +ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu +SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf +mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ +nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +Secure Global CA +================ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH +bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg +MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx +YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ +bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g +8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV +HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi +0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn +oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA +MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ +OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn +CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 +3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +COMODO Certification Authority +============================== +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb +MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD +T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH ++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww +xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV +4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA +1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI +rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k +b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC +AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP +OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc +IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN ++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== +-----END CERTIFICATE----- + +COMODO ECC Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix +GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X +4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni +wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG +FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA +U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +Certigna +======== +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw +EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 +MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI +Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q +XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH +GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p +ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg +DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf +Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ +tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ +BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J +SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA +hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ +ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu +PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY +1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +ePKI Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx +MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq +MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs +IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi +lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv +qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX +12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O +WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ +ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao +lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ +vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi +Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi +MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 +1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq +KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV +xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP +NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r +GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE +xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx +gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy +sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD +BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +certSIGN ROOT CA +================ +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD +VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa +Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE +CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I +JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH +rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 +ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD +0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 +AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB +AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 +SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 +x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt +vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz +TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +NetLock Arany (Class Gold) Főtanúsítvány +======================================== +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G +A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 +dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB +cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx +MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO +ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 +c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu +0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw +/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk +H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw +fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 +neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW +qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta +YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna +NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu +dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +SecureSign RootCA11 +=================== +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi +SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS +b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw +KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 +cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL +TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO +wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq +g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP +O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA +bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX +t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh +OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r +bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ +Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 +y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 +lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER +MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv +c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE +BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt +U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA +fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG +0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA +pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm +1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC +AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf +QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE +FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o +lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX +I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 +yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi +LXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +GlobalSign Root CA - R3 +======================= +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt +iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ +0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 +rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl +OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 +xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 +lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 +EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E +bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 +YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r +kpeDMdmztcpHWD9f +-----END CERTIFICATE----- + +Izenpe.com +========== +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG +EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz +MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu +QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ +03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK +ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU ++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC +PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT +OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK +F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK +0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ +0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB +leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID +AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ +SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG +NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l +Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga +kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q +hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs +g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 +aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 +nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC +ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo +Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z +WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +Go Daddy Root Certificate Authority - G2 +======================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu +MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G +A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq +9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD ++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd +fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl +NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 +BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac +vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r +5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV +N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 +-----END CERTIFICATE----- + +Starfield Root Certificate Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw +DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg +VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB +dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv +W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs +bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk +N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf +ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU +JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol +TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx +4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw +F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ +c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +Starfield Services Root Certificate Authority - G2 +================================================== +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl +IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT +dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 +h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa +hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP +LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB +rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG +SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP +E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy +xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza +YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 +-----END CERTIFICATE----- + +AffirmTrust Commercial +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw +MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb +DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV +C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 +BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww +MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV +HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG +hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi +qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv +0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh +sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +AffirmTrust Networking +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw +MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE +Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI +dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 +/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb +h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV +HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu +UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 +12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 +WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 +/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +AffirmTrust Premium +=================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy +OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy +dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn +BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV +5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs ++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd +GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R +p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI +S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 +6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 +/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo ++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv +MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC +6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S +L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK ++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV +BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg +IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 +g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb +zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== +-----END CERTIFICATE----- + +AffirmTrust Premium ECC +======================= +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV +BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx +MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U +cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ +N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW +BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK +BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X +57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM +eQ== +-----END CERTIFICATE----- + +Certum Trusted Network CA +========================= +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK +ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy +MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU +ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC +l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J +J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 +fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 +cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB +Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw +DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj +jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 +mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj +Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +TWCA Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ +VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG +EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB +IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx +QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC +oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP +4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r +y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG +9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC +mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW +QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY +T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny +Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +Security Communication RootCA2 +============================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC +SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy +aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ ++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R +3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV +spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K +EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 +QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj +u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk +3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q +tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 +mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +Actalis Authentication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM +BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE +AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky +MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz +IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ +wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa +by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 +zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f +YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 +oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l +EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 +hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 +EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 +jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY +iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI +WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 +JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx +K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ +Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC +4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo +2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz +lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem +OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 +vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +Buypass Class 2 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X +DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 +g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn +9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b +/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU +CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff +awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI +zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn +Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX +Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs +M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI +osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S +aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd +DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD +LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 +oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC +wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS +CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN +rJgWVqA= +-----END CERTIFICATE----- + +Buypass Class 3 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X +DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH +sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR +5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh +7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ +ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH +2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV +/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ +RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA +Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq +j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G +uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG +Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 +ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 +KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz +6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug +UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe +eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi +Cp/HuZc= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 3 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx +MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK +9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU +NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF +iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W +0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr +AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb +fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT +ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h +P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe +Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE +LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD +ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA +BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv +KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z +p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC +AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ +4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y +eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw +MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G +PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw +OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm +2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV +dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph +X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 EV 2009 +================================= +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS +egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh +zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T +7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 +sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 +11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv +cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v +ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El +MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp +b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh +c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ +PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX +ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA +NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv +w9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +CA Disig Root R2 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC +w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia +xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 +A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S +GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV +g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa +5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE +koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A +Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i +Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u +Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV +sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je +dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 +1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx +mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 +utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 +sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg +UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV +7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +ACCVRAIZ1 +========= +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB +SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 +MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH +UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM +jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 +RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD +aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ +0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG +WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 +8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR +5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J +9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK +Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw +Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu +Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM +Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA +QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh +AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA +YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj +AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA +IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk +aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 +dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 +MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI +hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E +R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN +YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 +nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ +TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 +sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg +Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd +3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p +EfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +TWCA Global Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT +CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD +QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK +EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg +Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C +nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV +r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR +Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV +tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W +KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 +sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p +yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn +kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI +zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g +cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M +8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg +/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg +lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP +A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m +i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 +EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 +zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= +-----END CERTIFICATE----- + +TeliaSonera Root CA v1 +====================== +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE +CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 +MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW +VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ +6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA +3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k +B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn +Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH +oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 +F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ +oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 +gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc +TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB +AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW +DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm +zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW +pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV +G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc +c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT +JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 +qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 +Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems +WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 2 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx +MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ +SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F +vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 +2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV +WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy +YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 +r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf +vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR +3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== +-----END CERTIFICATE----- + +Atos TrustedRoot 2011 +===================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU +cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 +MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG +A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV +hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr +54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ +DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 +HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR +z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R +l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ +bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h +k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh +TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 +61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G +3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + +QuoVadis Root CA 1 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE +PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm +PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6 +Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN +ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l +g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV +7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX +9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f +iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg +t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI +hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3 +GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct +Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP ++V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh +3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa +wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6 +O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0 +FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV +hMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +QuoVadis Root CA 2 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh +ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY +NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t +oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o +MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l +V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo +L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ +sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD +6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh +lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI +hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K +pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9 +x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz +dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X +U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw +mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD +zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN +JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr +O3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +QuoVadis Root CA 3 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286 +IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL +Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe +6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3 +I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U +VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7 +5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi +Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM +dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt +rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI +hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS +t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ +TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du +DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib +Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD +hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX +0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW +dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2 +PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +DigiCert Assured ID Root G2 +=========================== +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw +MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH +35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq +bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw +VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP +YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn +lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO +w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv +0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz +d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW +hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M +jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +DigiCert Assured ID Root G3 +=========================== +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD +VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 +MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb +RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs +KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF +UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy +YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy +1vUhZscv6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +DigiCert Global Root G2 +======================= +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx +MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ +kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO +3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV +BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM +UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB +o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu +5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr +F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U +WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH +QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/ +iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +DigiCert Global Root G3 +======================= +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD +VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw +MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k +aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C +AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O +YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp +Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y +3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34 +VOKa5Vt8sycX +-----END CERTIFICATE----- + +DigiCert Trusted Root G4 +======================== +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw +HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 +MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp +pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o +k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa +vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY +QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6 +MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm +mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7 +f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH +dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8 +oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY +ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr +yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy +7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah +ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN +5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb +/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa +5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK +G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP +82Z+ +-----END CERTIFICATE----- + +COMODO RSA Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn +dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ +FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+ +5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG +x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX +2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL +OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3 +sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C +GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5 +WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt +rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+ +nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg +tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW +sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp +pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA +zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq +ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52 +7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I +LaZRfyHBNVOFBkpdn627G190 +-----END CERTIFICATE----- + +USERTrust RSA Certification Authority +===================================== +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE +BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK +ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE +BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK +ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz +0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j +Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn +RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O ++T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq +/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE +Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM +lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8 +yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+ +eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW +FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ +7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ +Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM +8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi +FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi +yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c +J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw +sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx +Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +USERTrust ECC Certification Authority +===================================== +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2 +0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez +nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV +HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB +HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu +9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R5 +=========================== +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6 +SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS +h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx +uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7 +yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +IdenTrust Commercial Root CA 1 +============================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS +b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES +MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB +IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld +hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/ +mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi +1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C +XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl +3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy +NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV +WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg +xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix +uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI +hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg +ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt +ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV +YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX +feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro +kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe +2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz +Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R +cGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +IdenTrust Public Sector Root CA 1 +================================= +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv +ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV +UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS +b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy +P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6 +Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI +rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf +qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS +mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn +ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh +LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v +iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL +4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B +Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw +DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A +mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt +GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt +m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx +NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4 +Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI +ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC +ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ +3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +Entrust Root Certification Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy +bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug +b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw +HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT +DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx +OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP +/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz +HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU +s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y +TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx +AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6 +0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z +iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi +nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+ +vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO +e4pIb4tF9g== +-----END CERTIFICATE----- + +Entrust Root Certification Authority - EC1 +========================================== +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx +FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn +YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw +FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs +LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg +dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt +IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy +AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef +9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h +vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8 +kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +CFCA EV ROOT +============ +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE +CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB +IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw +MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD +DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV +BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD +7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN +uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW +ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7 +xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f +py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K +gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol +hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ +tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf +BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q +ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua +4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG +E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX +BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn +aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy +PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX +kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C +ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GB CA +=============================== +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG +EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw +MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds +b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX +scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP +rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk +9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o +Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg +GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI +hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD +dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0 +VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui +HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +SZAFIR ROOT CA2 +=============== +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG +A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV +BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ +BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD +VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q +qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK +DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE +2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ +ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi +ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC +AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5 +O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67 +oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul +4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6 ++/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +Certum Trusted Network CA 2 +=========================== +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE +BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1 +bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y +ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ +TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB +IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9 +7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o +CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b +Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p +uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130 +GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ +9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB +Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye +hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM +BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI +hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW +Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA +L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo +clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM +pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb +w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo +J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm +ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX +is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7 +zAYspsbiDrW5viSP +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2015 +======================================================= +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT +BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0 +aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx +MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg +QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV +BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw +MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv +bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh +iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+ +6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd +FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr +i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F +GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2 +fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu +iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI +hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+ +D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM +d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y +d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn +82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb +davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F +Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt +J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa +JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q +p/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions ECC RootCA 2015 +=========================================================== +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0 +aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u +cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj +aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw +MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj +IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD +VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290 +Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP +dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK +Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA +GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn +dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +ISRG Root X1 +============ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE +BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD +EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG +EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT +DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r +Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1 +3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K +b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN +Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ +4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf +1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu +hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH +usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r +OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G +A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY +9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV +0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt +hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw +TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx +e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA +JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD +YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n +JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ +m+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM +================ +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT +AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw +MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD +TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf +qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr +btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL +j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou +08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw +WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT +tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ +47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC +ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa +i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o +dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s +D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ +j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT +Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW ++YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7 +Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d +8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm +5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG +rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- + +Amazon Root CA 1 +================ +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD +VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1 +MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv +bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH +FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ +gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t +dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce +VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3 +DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM +CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy +8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa +2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2 +xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +Amazon Root CA 2 +================ +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD +VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1 +MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv +bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4 +kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp +N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9 +AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd +fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx +kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS +btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0 +Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN +c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+ +3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw +DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA +A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE +YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW +xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ +gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW +aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV +Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3 +KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi +JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw= +-----END CERTIFICATE----- + +Amazon Root CA 3 +================ +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG +EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy +NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ +MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB +f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr +Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43 +rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc +eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +Amazon Root CA 4 +================ +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG +EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy +NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ +MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN +/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri +83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA +MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1 +AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 +============================================= +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT +D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr +IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g +TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp +ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD +VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt +c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth +bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11 +IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8 +6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc +wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0 +3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9 +WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU +ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc +lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R +e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j +q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- + +GDCA TrustAUTH R5 ROOT +====================== +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw +BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD +DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow +YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs +AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p +OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr +pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ +9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ +xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM +R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ +D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4 +oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx +9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9 +H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35 +6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd ++PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ +HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD +F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ +8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv +/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT +aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- + +SSL.com Root Certification Authority RSA +======================================== +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM +BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x +MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw +MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx +EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM +LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C +Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8 +P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge +oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp +k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z +fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ +gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2 +UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8 +1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s +bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr +dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf +ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl +u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq +erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj +MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ +vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI +Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y +wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI +WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- + +SSL.com Root Certification Authority ECC +======================================== +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv +BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy +MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO +BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+ +8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR +hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT +jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW +e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z +5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority RSA R2 +============================================== +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w +DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u +MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI +DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD +VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh +hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w +cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO +Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+ +B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh +CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim +9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto +RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm +JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48 ++qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp +qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1 +++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx +Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G +guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz +OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7 +CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq +lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR +rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1 +hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX +9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority ECC +=========================================== +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy +BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw +MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx +EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM +LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy +3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O +BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe +5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ +N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm +m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- + +GlobalSign Root CA - R6 +======================= +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX +R2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds +b2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i +YWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs +U2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss +grRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE +3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF +vuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM +PKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+ +azayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O +WgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy +CLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP +0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN +b7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE +AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV +HSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0 +lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY +BzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym +Fe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr +3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1 +0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T +uTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK +oZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t +JDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GC CA +=============================== +-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD +SDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo +MCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa +Fw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL +ExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr +VCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab +NTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E +AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk +AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE----- + +UCA Global G2 Root +================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG +EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x +NjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU +cnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT +oni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV +8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS +h6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o +LTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/ +R+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe +KW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa +4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc +OxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97 +8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo +5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A +Ds0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9 +yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX +c47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo +jhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk +bxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x +ygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn +RR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A== +-----END CERTIFICATE----- + +UCA Extended Validation Root +============================ +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG +EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u +IFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G +A1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs +iWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF +Rv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu +eUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR +59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH +0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR +el7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv +B0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth +WG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS +NwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS +3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL +BQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM +aVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4 +dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb ++7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW +F3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi +GpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc +GMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi +djzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr +dhh2n1ax +-----END CERTIFICATE----- + +Certigna Root CA +================ +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE +BhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ +MBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda +MFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz +MDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX +stmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz +KNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8 +JXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16 +XdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq +4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej +wpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ +lXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI +jzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/ +/TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy +dGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h +LmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl +cnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt +OoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP +TGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq +7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3 +4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd +8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS +6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY +tlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS +aX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde +E4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- + +emSign Root CA - G1 +=================== +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJJTjET +MBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl +ZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgx +ODMwMDBaMGcxCzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk +aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQzf2N4aLTN +LnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO8oG0x5ZOrRkVUkr+PHB1 +cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aqd7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHW +DV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhMtTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ +6DqS0hdW5TUaQBw+jSztOd9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrH +hQIDAQABo0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQDAgEG +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31xPaOfG1vR2vjTnGs2 +vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjMwiI/aTvFthUvozXGaCocV685743Q +NcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6dGNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q ++Mri/Tm3R7nrft8EI6/6nAYH6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeih +U80Bv2noWgbyRQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- + +emSign ECC Root CA - G3 +======================= +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQGEwJJTjETMBEG +A1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg +MB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4 +MTgzMDAwWjBrMQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11 +ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0WXTsuwYc +58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xySfvalY8L1X44uT6EYGQIr +MgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuBzhccLikenEhjQjAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+D +CBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7 +jHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- + +emSign Root CA - C1 +=================== +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx +EzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp +Z24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UE +BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQD +ExNlbVNpZ24gUm9vdCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+up +ufGZBczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZHdPIWoU/ +Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH3DspVpNqs8FqOp099cGX +OFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvHGPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4V +I5b2P/AgNBbeCsbEBEV5f6f9vtKppa+cxSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleooms +lMuoaJuvimUnzYnu3Yy1aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+ +XJGFehiqTbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD +ggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87/kOXSTKZEhVb3xEp +/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4kqNPEjE2NuLe/gDEo2APJ62gsIq1 +NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrGYQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9 +wC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ +BmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- + +emSign ECC Root CA - C3 +======================= +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG +A1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF +Q0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UE +BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQD +ExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd +6bciMK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4OjavtisIGJAnB9 +SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0OBBYEFPtaSNCAIEDyqOkA +B2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gA +MGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU +ZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- + +Hongkong Post Root CA 3 +======================= +-----BEGIN CERTIFICATE----- +MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG +A1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK +Ew1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25na29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2 +MDMwMjI5NDZaFw00MjA2MDMwMjI5NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv +bmcxEjAQBgNVBAcTCUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMX +SG9uZ2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz +iNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFOdem1p+/l6TWZ5Mwc50tf +jTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mIVoBc+L0sPOFMV4i707mV78vH9toxdCim +5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOe +sL4jpNrcyCse2m5FHomY2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj +0mRiikKYvLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+TtbNe/ +JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZbx39ri1UbSsUgYT2u +y1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+l2oBlKN8W4UdKjk60FSh0Tlxnf0h ++bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YKTE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsG +xVd7GYYKecsAyVKvQv83j+GjHno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwID +AQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e +i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEwDQYJKoZIhvcN +AQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG7BJ8dNVI0lkUmcDrudHr9Egw +W62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCkMpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWld +y8joRTnU+kLBEUx3XZL7av9YROXrgZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov ++BS5gLNdTaqX4fnkGMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDc +eqFS3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJmOzj/2ZQw +9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+l6mc1X5VTMbeRRAc6uk7 +nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6cJfTzPV4e0hz5sy229zdcxsshTrD3mUcY +hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB +60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq +dBb9HxEGmpv0 +-----END CERTIFICATE----- + +Entrust Root Certification Authority - G4 +========================================= +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAwgb4xCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3Qu +bmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1 +dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eSAtIEc0MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYT +AlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3D +umSXbcr3DbVZwbPLqGgZ2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV +3imz/f3ET+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j5pds +8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAMC1rlLAHGVK/XqsEQ +e9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73TDtTUXm6Hnmo9RR3RXRv06QqsYJn7 +ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNXwbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5X +xNMhIWNlUpEbsZmOeX7m640A2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV +7rtNOzK+mndmnqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwlN4y6mACXi0mW +Hv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNjc0kCAwEAAaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9n +MA0GCSqGSIb3DQEBCwUAA4ICAQAS5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4Q +jbRaZIxowLByQzTSGwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht +7LGrhFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/B7NTeLUK +YvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uIAeV8KEsD+UmDfLJ/fOPt +jqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbwH5Lk6rWS02FREAutp9lfx1/cH6NcjKF+ +m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKW +RGhXxNUzzxkvFMSUHHuk2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjA +JOgc47OlIQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk5F6G ++TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuYn/PIjhs4ViFqUZPT +kcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE----- + +Microsoft ECC Root Certificate Authority 2017 +============================================= +-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND +IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4 +MjMxNjA0WjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZRogPZnZH6 +thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYbhGBKia/teQ87zvH2RPUB +eMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIy5lycFIM ++Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlf +Xu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR +eNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE----- + +Microsoft RSA Root Certificate Authority 2017 +============================================= +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg +UlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIw +NzE4MjMwMDIzWjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u +MTYwNAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZNt9GkMml +7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0ZdDMbRnMlfl7rEqUrQ7e +S0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw7 +1VdyvD/IybLeS2v4I2wDwAW9lcfNcztmgGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+ +dkC0zVJhUXAoP8XFWvLJjEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49F +yGcohJUcaDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaGYaRS +MLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6W6IYZVcSn2i51BVr +lMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4KUGsTuqwPN1q3ErWQgR5WrlcihtnJ +0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJ +ClTUFLkqqNfs+avNJVgyeY+QW5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZCLgLNFgVZJ8og +6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OCgMNPOsduET/m4xaRhPtthH80 +dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk ++ONVFT24bcMKpBLBaYVu32TxU5nhSnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex +/2kskZGT4d9Mozd2TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDy +AmH3pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGRxpl/j8nW +ZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiAppGWSZI1b7rCoucL5mxAyE +7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKT +c0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D +5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E +-----END CERTIFICATE----- + +e-Szigno Root CA 2017 +===================== +-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw +DwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt +MjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJvb3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZa +Fw00MjA4MjIxMjA3MDZaMHExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UE +CgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3pp +Z25vIFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtvxie+RJCx +s1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+HWyx7xf58etqjYzBhMA8G +A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSHERUI0arBeAyxr87GyZDv +vzAEwDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEA +tVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO +svxyqltZ+efcMQ== +-----END CERTIFICATE----- + +certSIGN Root CA G2 +=================== +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw +EgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy +MDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJBgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lH +TiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAMDFdRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05 +N0IwvlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZuIt4Imfk +abBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhpn+Sc8CnTXPnGFiWeI8Mg +wT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKscpc/I1mbySKEwQdPzH/iV8oScLumZfNp +dWO9lfsbl83kqK/20U6o2YpxJM02PbyWxPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91Qqh +ngLjYl/rNUssuHLoPj1PrCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732 +jcZZroiFDsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fxDTvf +95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgyLcsUDFDYg2WD7rlc +z8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6CeWRgKRM+o/1Pcmqr4tTluCRVLERL +iohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud +DgQWBBSCIS1mxteg4BXrzkwJd8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOB +ywaK8SJJ6ejqkX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQlqiCA2ClV9+BB +/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0OJD7uNGzcgbJceaBxXntC6Z5 +8hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+cNywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5 +BiKDUyUM/FHE5r7iOZULJK2v0ZXkltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklW +atKcsWMy5WHgUyIOpwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tU +Sxfj03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZkPuXaTH4M +NMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N +0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc= +-----END CERTIFICATE----- + +Trustwave Global Certification Authority +======================================== +-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV +UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 +ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTAeFw0xNzA4MjMxOTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJV +UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 +ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALldUShLPDeS0YLOvR29 +zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0XznswuvCAAJWX/NKSqIk4cXGIDtiLK0thAf +LdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4Bq +stTnoApTAbqOl5F2brz81Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9o +WN0EACyW80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotPJqX+ +OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1lRtzuzWniTY+HKE40 +Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfwhI0Vcnyh78zyiGG69Gm7DIwLdVcE +uE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm ++9jaJXLE9gCxInm943xZYkqcBW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqj +ifLJS3tBEW1ntwiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1UdDwEB/wQEAwIB +BjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W0OhUKDtkLSGm+J1WE2pIPU/H +PinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfeuyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0H +ZJDmHvUqoai7PF35owgLEQzxPy0QlG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla +4gt5kNdXElE1GYhBaCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5R +vbbEsLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPTMaCm/zjd +zyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qequ5AvzSxnI9O4fKSTx+O +856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxhVicGaeVyQYHTtgGJoC86cnn+OjC/QezH +Yj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu +3R3y4G5OBVixwJAWKqQ9EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP +29FpHOTKyeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE----- + +Trustwave Global ECC P256 Certification Authority +================================================= +-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJVUzER +MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy +dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1 +NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH77bOYj +43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoNFWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqm +P62jQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt +0UrrdaVKEJmzsaGLSvcwCgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjz +RM4q3wghDDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE----- + +Trustwave Global ECC P384 Certification Authority +================================================= +-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYDVQQGEwJVUzER +MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy +dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4 +NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGvaDXU1CDFH +Ba5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJj9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr +/TklZvFe/oyujUF5nQlgziip04pt89ZF1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNV +HQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNn +ADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl +CrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw== +-----END CERTIFICATE----- + +NAVER Global Root Certification Authority +========================================= +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEMBQAwaTELMAkG +A1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRGT1JNIENvcnAuMTIwMAYDVQQD +DClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4 +NDJaFw0zNzA4MTgyMzU5NTlaMGkxCzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVT +UyBQTEFURk9STSBDb3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVAiQqrDZBb +UGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH38dq6SZeWYp34+hInDEW ++j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lEHoSTGEq0n+USZGnQJoViAbbJAh2+g1G7 +XNr4rRVqmfeSVPc0W+m/6imBEtRTkZazkVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2 +aacp+yPOiNgSnABIqKYPszuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4 +Yb8ObtoqvC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHfnZ3z +VHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaGYQ5fG8Ir4ozVu53B +A0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo0es+nPxdGoMuK8u180SdOqcXYZai +cdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3aCJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejy +YhbLgGvtPe31HzClrkvJE+2KAQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNV +HQ4EFgQU0p+I36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoNqo0hV4/GPnrK +21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatjcu3cvuzHV+YwIHHW1xDBE1UB +jCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bx +hYTeodoS76TiEJd6eN4MUZeoIUCLhr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTg +E34h5prCy8VCZLQelHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTH +D8z7p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8piKCk5XQ +A76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLRLBT/DShycpWbXgnbiUSY +qqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oG +I/hGoiLtk/bdmuYqh7GYVPEi92tF4+KOdh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmg +kpzNNIaRkPpkUZ3+/uul9XXeifdy +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM SERVIDORES SEGUROS +=================================== +-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQswCQYDVQQGEwJF +UzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgwFgYDVQRhDA9WQVRFUy1RMjgy +NjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1SQ00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4 +MTIyMDA5MzczM1oXDTQzMTIyMDA5MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQt +UkNNMQ4wDAYDVQQLDAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNB +QyBSQUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LHsbI6GA60XYyzZl2hNPk2 +LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oKUm8BA06Oi6NCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqG +SM49BAMDA2kAMGYCMQCuSuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoD +zBOQn5ICMQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJyv+c= +-----END CERTIFICATE----- + +GlobalSign Root R46 +=================== +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUAMEYxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJv +b3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAX +BgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08Es +CVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQGvGIFAha/ +r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud316HCkD7rRlr+/fKYIje +2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEt +bWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvj +K8Cd+RTyG/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD4 +12lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCNI/on +ccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzsx2sZy/N78CsHpdls +eVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9 +vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEM +BQADggIBAHx47PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti2kM3S+LGteWy +gxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIkpnnpHs6i58FZFZ8d4kuaPp92 +CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRFFRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZm +OUdkLG5NrmJ7v2B0GbhWrJKsFjLtrWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qq +JZ4d16GLuc1CLgSkZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwye +qiv5u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP4vkYxboz +nxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6N3ec592kD3ZDZopD8p/7 +DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3 +QEUxeCp6 +-----END CERTIFICATE----- + +GlobalSign Root E46 +=================== +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYxCzAJBgNVBAYT +AkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3Qg +RTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNV +BAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkB +jtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGddyXqBPCCj +QjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRL +gLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZk +vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+ +CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- + +GLOBALTRUST 2020 +================ +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx +IzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT +VCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh +BgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy +MDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi +D59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO +VPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM +CcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm +fecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA +A1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR +JitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG +DfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU +clOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ +mjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud +IwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw +4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9 +iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS +8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2 +HcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS +vTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918 +oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF +YqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl +gqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----END CERTIFICATE----- + +ANF Secure Server Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4 +NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv +bjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNVBAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3Qg +Q0EwHhcNMTkwOTA0MTAwMDM4WhcNMzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEw +MQswCQYDVQQGEwJFUzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQw +EgYDVQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9vdCBDQTCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCjcqQZAZ2cC4Ffc0m6p6zz +BE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9qyGFOtibBTI3/TO80sh9l2Ll49a2pcbnv +T1gdpd50IJeh7WhM3pIXS7yr/2WanvtH2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcv +B2VSAKduyK9o7PQUlrZXH1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXse +zx76W0OLzc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyRp1RM +VwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQzW7i1o0TJrH93PB0j +7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/SiOL9V8BY9KHcyi1Swr1+KuCLH5z +JTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJnLNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe +8TZBAQIvfXOn3kLMTOmJDVb3n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVO +Hj1tyRRM4y5Bu8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj +o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAOBgNVHQ8BAf8E +BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEATh65isagmD9uw2nAalxJ +UqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzx +j6ptBZNscsdW699QIyjlRRA96Gejrw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDt +dD+4E5UGUcjohybKpFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM +5gf0vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjqOknkJjCb +5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ/zo1PqVUSlJZS2Db7v54 +EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ92zg/LFis6ELhDtjTO0wugumDLmsx2d1H +hk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGy +g77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3 +r5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= +-----END CERTIFICATE----- + +Certum EC-384 CA +================ +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ +TDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2 +MDcyNDU0WhcNNDMwMzI2MDcyNDU0WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERh +dGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +GTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATEKI6rGFtq +vm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7TmFy8as10CW4kjPMIRBSqn +iBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68KjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFI0GZnQkdjrzife81r1HfS+8EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNo +ADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0 +QoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- + +Certum Trusted Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG +EwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0Ew +HhcNMTgwMzE2MTIxMDEzWhcNNDMwMzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMY +QXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZn0EGze2jusDbCSzBfN8p +fktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/qp1x4EaTByIVcJdPTsuclzxFUl6s1wB52 +HO8AU5853BSlLCIls3Jy/I2z5T4IHhQqNwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2 +fJmItdUDmj0VDT06qKhF8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGt +g/BKEiJ3HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGamqi4 +NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi7VdNIuJGmj8PkTQk +fVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSFytKAQd8FqKPVhJBPC/PgP5sZ0jeJ +P/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0PqafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSY +njYJdmZm/Bo/6khUHL4wvYBQv3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHK +HRzQ+8S1h9E6Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 +vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAEii1QAL +LtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4WxmB82M+w85bj/UvXgF2Ez8s +ALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvozMrnadyHncI013nR03e4qllY/p0m+jiGPp2K +h2RX5Rc64vmNueMzeMGQ2Ljdt4NR5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8 +CYyqOhNf6DR5UMEQGfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA +4kZf5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq0Uc9Nneo +WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj +6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTMqJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmT +OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck +bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb +-----END CERTIFICATE----- + +TunTrust Root CA +================ +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG +A1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj +dHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw +NDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD +ZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz +2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b +bjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7 +NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd +gjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW +VSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f +Tpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ +juXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas +DXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS +VXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI +04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 +90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl +0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd +Ao74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY +YdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp +adbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x +xBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP +jCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM +MEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z +ZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r +AZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= +-----END CERTIFICATE----- + +HARICA TLS RSA Root CA 2021 +=========================== +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG +EwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u +cyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz +OFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl +bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB +IFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN +JLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu +a2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y +Ulhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K +5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv +dmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR +0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH +GjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm +haZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ +CPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU +EapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq +QRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD +QpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR +j88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5 +vZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0 +qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6 +Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/ +PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn +kf3/W9b3raYvAwtt41dU63ZTGI0RmLo= +-----END CERTIFICATE----- + +HARICA TLS ECC Root CA 2021 +=========================== +-----BEGIN CERTIFICATE----- +MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH +UjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD +QTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX +DTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj +IGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv +b3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l +AEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b +ECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW +0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi +rcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw +CZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +========================================================= +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCRVMxQjBA +BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIw +QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB +NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD +Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P +B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY +7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH +ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI +plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX +MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX +LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK +bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU +vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1Ud +DgQWBBRlzeurNR4APn7VdMActHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4w +gZswgZgGBFUdIAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j +b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABCAG8AbgBhAG4A +bwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAwADEANzAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9miWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL +4QjbEwj4KKE1soCzC1HA01aajTNFSa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDb +LIpgD7dvlAceHabJhfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1il +I45PVf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZEEAEeiGaP +cjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV1aUsIC+nmCjuRfzxuIgA +LI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2tCsvMo2ebKHTEm9caPARYpoKdrcd7b/+A +lun4jWq9GJAd/0kakFI3ky88Al2CdgtR5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH +9IBk9W6VULgRfhVwOEqwf9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpf +NIbnYrX9ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNKGbqE +ZycPvEJdvSRUDewdcAZfpLz6IHxV +-----END CERTIFICATE----- + +vTrus ECC Root CA +================= +-----BEGIN CERTIFICATE----- +MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMwRzELMAkGA1UE +BhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBS +b290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDczMTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAa +BgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+c +ToL0v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUde4BdS49n +TPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIwV53dVvHH4+m4SVBrm2nDb+zDfSXkV5UT +QJtS0zvzQBm8JsctBp61ezaf9SXUY2sAAjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQL +YgmRWAD5Tfs0aNoJrSEGGJTO +-----END CERTIFICATE----- + +vTrus Root CA +============= +-----BEGIN CERTIFICATE----- +MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQELBQAwQzELMAkG +A1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xFjAUBgNVBAMTDXZUcnVzIFJv +b3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMxMDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoG +A1UEChMTaVRydXNDaGluYSBDby4sTHRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZots +SKYcIrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykUAyyNJJrI +ZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+GrPSbcKvdmaVayqwlHeF +XgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z98Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KA +YPxMvDVTAWqXcoKv8R1w6Jz1717CbMdHflqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70 +kLJrxLT5ZOrpGgrIDajtJ8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2 +AXPKBlim0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZNpGvu +/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQUqqzApVg+QxMaPnu +1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHWOXSuTEGC2/KmSNGzm/MzqvOmwMVO +9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMBAAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYg +scasGrz2iTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOC +AgEAKbqSSaet8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd +nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1jbhd47F18iMjr +jld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvMKar5CKXiNxTKsbhm7xqC5PD4 +8acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIivTDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJn +xDHO2zTlJQNgJXtxmOTAGytfdELSS8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554Wg +icEFOwE30z9J4nfrI8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4 +sEb9b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNBUvupLnKW +nyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1PTi07NEPhmg4NpGaXutIc +SkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929vensBxXVsFy6K2ir40zSbofitzmdHxghm+H +l3s= +-----END CERTIFICATE----- + +ISRG Root X2 +============ +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQswCQYDVQQGEwJV +UzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElT +UkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVT +MSkwJwYDVQQKEyBJbnRlcm5ldCBTZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNS +RyBSb290IFgyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0H +ttwW+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9ItgKbppb +d9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZIzj0EAwMDaAAwZQIwe3lORlCEwkSHRhtF +cP9Ymd70/aTSVaYgLXTWNLxBo1BfASdWtL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5 +U6VR5CmD1/iQMVtCnwr1/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- + +HiPKI Root CA - G1 +================== +-----BEGIN CERTIFICATE----- +MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xGzAZBgNVBAMMEkhpUEtJ +IFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRaFw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYT +AlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kg +Um9vdCBDQSAtIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0 +o9QwqNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twvVcg3Px+k +wJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6lZgRZq2XNdZ1AYDgr/SE +YYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnzQs7ZngyzsHeXZJzA9KMuH5UHsBffMNsA +GJZMoYFL3QRtU6M9/Aes1MU3guvklQgZKILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfd +hSi8MEyr48KxRURHH+CKFgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj +1jOXTyFjHluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDry+K4 +9a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ/W3c1pzAtH2lsN0/ +Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgMa/aOEmem8rJY5AIJEzypuxC00jBF +8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQD +AgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi +7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqcSE5XCV0vrPSl +tJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6FzaZsT0pPBWGTMpWmWSBUdGSquE +wx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9TcXzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07Q +JNBAsNB1CI69aO4I1258EHBGG3zgiLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv +5wiZqAxeJoBF1PhoL5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+Gpz +jLrFNe85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wrkkVbbiVg +hUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+vhV4nYWBSipX3tUZQ9rb +yltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQUYDksswBVLuT1sw5XxJFBAJw/6KXf6vb/ +yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R4 +=========================== +-----BEGIN CERTIFICATE----- +MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYDVQQLExtHbG9i +YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds +b2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgwMTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9i +YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds +b2JhbFNpZ24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkW +ymOxuYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNVHQ8BAf8E +BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/+wpu+74zyTyjhNUwCgYI +KoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147bmF0774BxL4YSFlhgjICICadVGNA3jdg +UM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm +-----END CERTIFICATE----- + +GTS Root R1 +=========== +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV +UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg +UjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE +ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM +f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7raKb0 +xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnWr4+w +B7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXW +nOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk +9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zq +kUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92wO1A +K/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om3xPX +V2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDW +cfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQAD +ggIBAJ+qQibbC5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuyh6f88/qBVRRi +ClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM47HLwEXWdyzRSjeZ2axfG34ar +J45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8JZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYci +NuaCp+0KueIHoI17eko8cdLiA6EfMgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5me +LMFrUKTX5hgUvYU/Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJF +fbdT6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ0E6yove+ +7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm2tIMPNuzjsmhDYAPexZ3 +FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bbbP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3 +gm3c +-----END CERTIFICATE----- + +GTS Root R2 +=========== +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV +UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg +UjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE +ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv +CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo7JUl +e3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWIm8Wb +a96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS ++LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7M +kogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJG +r61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RWIr9q +S34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73VululycslaVNV +J1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy5okL +dWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQAD +ggIBAB/Kzt3HvqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 +0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyCB19m3H0Q/gxh +swWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2uNmSRXbBoGOqKYcl3qJfEycel +/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMgyALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVn +jWQye+mew4K6Ki3pHrTgSAai/GevHyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y5 +9PYjJbigapordwj6xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M +7YNRTOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924SgJPFI/2R8 +0L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV7LXTWtiBmelDGDfrs7vR +WGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjW +HYbL +-----END CERTIFICATE----- + +GTS Root R3 +=========== +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi +MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMw +HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ +R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjO +PQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout +736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24CejQjBA +MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP0/Eq +Er24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azT +L818+FsuVbu/3ZL3pAzcMeGiAjEA/JdmZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV +11RZt+cRLInUue4X +-----END CERTIFICATE----- + +GTS Root R4 +=========== +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi +MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQw +HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ +R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjO +PQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu +hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqjQjBA +MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV2Py1 +PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/C +r8deVl5c1RxYIigL9zC2L7F8AjEA8GE8p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh +4rsUecrNIdSUtUlD +-----END CERTIFICATE----- + +Telia Root CA v2 +================ +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNVBAYT +AkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2 +MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQK +DBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ7 +6zBqAMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9vVYiQJ3q +9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9lRdU2HhE8Qx3FZLgmEKn +pNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTODn3WhUidhOPFZPY5Q4L15POdslv5e2QJl +tI5c0BE0312/UqeBAMN/mUWZFdUXyApT7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW +5olWK8jjfN7j/4nlNW4o6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNr +RBH0pUPCTEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6WT0E +BXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63RDolUK5X6wK0dmBR4 +M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZIpEYslOqodmJHixBTB0hXbOKSTbau +BcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGjYzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7W +xy+G2CQ5MB0GA1UdDgQWBBRyrOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ +8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi0f6X+J8wfBj5 +tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMMA8iZGok1GTzTyVR8qPAs5m4H +eW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBSSRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+C +y748fdHif64W1lZYudogsYMVoe+KTTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygC +QMez2P2ccGrGKMOF6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15 +h2Er3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMtTy3EHD70 +sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pTVmBds9hCG1xLEooc6+t9 +xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAWysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQ +raVplI/owd8k+BsHMYeB2F326CjYSlKArBPuUBQemMc= +-----END CERTIFICATE----- + +D-TRUST BR Root CA 1 2020 +========================= +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE +RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0EgMSAy +MDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNV +BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7 +dPYSzuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0QVK5buXu +QqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/VbNafAkl1bK6CKBrqx9t +MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu +bmV0L2NybC9kLXRydXN0X2JyX3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP +PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD +AwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFWwKrY7RjEsK70Pvom +AjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHVdWNbFJWcHwHP2NVypw87 +-----END CERTIFICATE----- + +D-TRUST EV Root CA 1 2020 +========================= +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE +RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0EgMSAy +MDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNV +BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8 +ZRCC/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rDwpdhQntJ +raOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3OqQo5FD4pPfsazK2/umL +MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu +bmV0L2NybC9kLXRydXN0X2V2X3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP +PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD +AwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CAy/m0sRtW9XLS/BnR +AjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJbgfM0agPnIjhQW+0ZT0MW +-----END CERTIFICATE----- + +DigiCert TLS ECC P384 Root G5 +============================= +-----BEGIN CERTIFICATE----- +MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURpZ2lDZXJ0IFRMUyBFQ0MgUDM4 +NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQg +Um9vdCBHNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1Tzvd +lHJS7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp0zVozptj +n4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICISB4CIfBFqMA4GA1UdDwEB +/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQCJao1H5+z8blUD2Wds +Jk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQLgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIx +AJSdYsiJvRmEFOml+wG4DXZDjC5Ty3zfDBeWUA== +-----END CERTIFICATE----- + +DigiCert TLS RSA4096 Root G5 +============================ +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBNMQswCQYDVQQG +EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0 +MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcNNDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2 +IFJvb3QgRzUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS8 +7IE+ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG02C+JFvuU +AT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgpwgscONyfMXdcvyej/Ces +tyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZMpG2T6T867jp8nVid9E6P/DsjyG244gXa +zOvswzH016cpVIDPRFtMbzCe88zdH5RDnU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnV +DdXifBBiqmvwPXbzP6PosMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9q +TXeXAaDxZre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cdLvvy +z6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvXKyY//SovcfXWJL5/ +MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNeXoVPzthwiHvOAbWWl9fNff2C+MIk +wcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPLtgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4E +FgQUUTMc7TZArxfTJc1paPKvTiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw +GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7HPNtQOa27PShN +lnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLFO4uJ+DQtpBflF+aZfTCIITfN +MBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQREtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/ +u4cnYiWB39yhL/btp/96j1EuMPikAdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9G +OUrYU9DzLjtxpdRv/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh +47a+p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilwMUc/dNAU +FvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WFqUITVuwhd4GTWgzqltlJ +yqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCKovfepEWFJqgejF0pW8hL2JpqA15w8oVP +bEtoL8pU9ozaMv7Da4M/OMZ+ +-----END CERTIFICATE----- + +Certainly Root R1 +================= +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE +BhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2VydGFpbmx5IFJvb3QgUjEwHhcN +MjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2Vy +dGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBANA21B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O +5MQTvqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbedaFySpvXl +8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b01C7jcvk2xusVtyWMOvwl +DbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGI +XsXwClTNSaa/ApzSRKft43jvRl5tcdF5cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkN +KPl6I7ENPT2a/Z2B7yyQwHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQ +AjeZjOVJ6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA2Cnb +rlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyHWyf5QBGenDPBt+U1 +VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMReiFPCyEQtkA6qyI6BJyLm4SGcprS +p6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBTgqj8ljZ9EXME66C6ud0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAsz +HQNTVfSVcOQrPbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d +8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi1wrykXprOQ4v +MMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrdrRT90+7iIgXr0PK3aBLXWopB +GsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9ditaY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+ +gjwN/KUD+nsa2UUeYNrEjvn8K8l7lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgH +JBu6haEaBQmAupVjyTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7 +fpYnKx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLyyCwzk5Iw +x06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5nwXARPbv0+Em34yaXOp/S +X3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6OV+KmalBWQewLK8= +-----END CERTIFICATE----- + +Certainly Root E1 +================= +-----BEGIN CERTIFICATE----- +MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQswCQYDVQQGEwJV +UzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBFMTAeFw0yMTA0 +MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlu +bHkxGjAYBgNVBAMTEUNlcnRhaW5seSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4 +fxzf7flHh4axpMCK+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9 +YBk2QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4hevIIgcwCgYIKoZIzj0E +AwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozmut6Dacpps6kFtZaSF4fC0urQe87YQVt8 +rgIwRt7qy12a7DLCZRawTDBcMPPaTnOGBtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR +-----END CERTIFICATE----- + +Security Communication RootCA3 +============================== +-----BEGIN CERTIFICATE----- +MIIFfzCCA2egAwIBAgIJAOF8N0D9G/5nMA0GCSqGSIb3DQEBDAUAMF0xCzAJBgNVBAYTAkpQMSUw +IwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScwJQYDVQQDEx5TZWN1cml0eSBD +b21tdW5pY2F0aW9uIFJvb3RDQTMwHhcNMTYwNjE2MDYxNzE2WhcNMzgwMTE4MDYxNzE2WjBdMQsw +CQYDVQQGEwJKUDElMCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UE +AxMeU2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEA48lySfcw3gl8qUCBWNO0Ot26YQ+TUG5pPDXC7ltzkBtnTCHsXzW7OT4rCmDvu20r +hvtxosis5FaU+cmvsXLUIKx00rgVrVH+hXShuRD+BYD5UpOzQD11EKzAlrenfna84xtSGc4RHwsE +NPXY9Wk8d/Nk9A2qhd7gCVAEF5aEt8iKvE1y/By7z/MGTfmfZPd+pmaGNXHIEYBMwXFAWB6+oHP2 +/D5Q4eAvJj1+XCO1eXDe+uDRpdYMQXF79+qMHIjH7Iv10S9VlkZ8WjtYO/u62C21Jdp6Ts9EriGm +npjKIG58u4iFW/vAEGK78vknR+/RiTlDxN/e4UG/VHMgly1s2vPUB6PmudhvrvyMGS7TZ2crldtY +XLVqAvO4g160a75BflcJdURQVc1aEWEhCmHCqYj9E7wtiS/NYeCVvsq1e+F7NGcLH7YMx3weGVPK +p7FKFSBWFHA9K4IsD50VHUeAR/94mQ4xr28+j+2GaR57GIgUssL8gjMunEst+3A7caoreyYn8xrC +3PsXuKHqy6C0rtOUfnrQq8PsOC0RLoi/1D+tEjtCrI8Cbn3M0V9hvqG8OmpI6iZVIhZdXw3/JzOf +GAN0iltSIEdrRU0id4xVJ/CvHozJgyJUt5rQT9nO/NkuHJYosQLTA70lUhw0Zk8jq/R3gpYd0Vcw +CBEF/VfR2ccCAwEAAaNCMEAwHQYDVR0OBBYEFGQUfPxYchamCik0FW8qy7z8r6irMA4GA1UdDwEB +/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQDcAiMI4u8hOscNtybS +YpOnpSNyByCCYN8Y11StaSWSntkUz5m5UoHPrmyKO1o5yGwBQ8IibQLwYs1OY0PAFNr0Y/Dq9HHu +Tofjcan0yVflLl8cebsjqodEV+m9NU1Bu0soo5iyG9kLFwfl9+qd9XbXv8S2gVj/yP9kaWJ5rW4O +H3/uHWnlt3Jxs/6lATWUVCvAUm2PVcTJ0rjLyjQIUYWg9by0F1jqClx6vWPGOi//lkkZhOpn2ASx +YfQAW0q3nHE3GYV5v4GwxxMOdnE+OoAGrgYWp421wsTL/0ClXI2lyTrtcoHKXJg80jQDdwj98ClZ +XSEIx2C/pHF7uNkegr4Jr2VvKKu/S7XuPghHJ6APbw+LP6yVGPO5DtxnVW5inkYO0QR4ynKudtml ++LLfiAlhi+8kTtFZP1rUPcmTPCtk9YENFpb3ksP+MW/oKjJ0DvRMmEoYDjBU1cXrvMUVnuiZIesn +KwkK2/HmcBhWuwzkvvnoEKQTkrgc4NtnHVMDpCKn3F2SEDzq//wbEBrD2NCcnWXL0CsnMQMeNuE9 +dnUM/0Umud1RvCPHX9jYhxBAEg09ODfnRDwYwFMJZI//1ZqmfHAuc1Uh6N//g7kdPjIe1qZ9LPFm +6Vwdp6POXiUyK+OVrCoHzrQoeIY8LaadTdJ0MN1kURXbg4NR16/9M51NZg== +-----END CERTIFICATE----- + +Security Communication ECC RootCA1 +================================== +-----BEGIN CERTIFICATE----- +MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYTAkpQMSUwIwYD +VQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYDVQQDEyJTZWN1cml0eSBDb21t +dW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYxNjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTEL +MAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNV +BAMTIlNlY3VyaXR5IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+CnnfdldB9sELLo +5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpKULGjQjBAMB0GA1UdDgQW +BBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAK +BggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3L +snNdo4gIxwwCMQDAqy0Obe0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70e +N9k= +-----END CERTIFICATE----- + +BJCA Global Root CA1 +==================== +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQG +EwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJK +Q0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAzMTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkG +A1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQD +DBRCSkNBIEdsb2JhbCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFm +CL3ZxRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZspDyRhyS +sTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O558dnJCNPYwpj9mZ9S1Wn +P3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgRat7GGPZHOiJBhyL8xIkoVNiMpTAK+BcW +yqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRj +eulumijWML3mG90Vr4TqnMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNn +MoH1V6XKV0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/pj+b +OT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZOz2nxbkRs1CTqjSSh +GL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXnjSXWgXSHRtQpdaJCbPdzied9v3pK +H9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMB +AAGjQjBAMB0GA1UdDgQWBBTF7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4 +YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3KliawLwQ8hOnThJ +dMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u+2D2/VnGKhs/I0qUJDAnyIm8 +60Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuh +TaRjAv04l5U/BXCga99igUOLtFkNSoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW +4AB+dAb/OMRyHdOoP2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmp +GQrI+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRzznfSxqxx +4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9eVzYH6Eze9mCUAyTF6ps +3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4S +SPfSKcOYKMryMguTjClPPGAyzQWWYezyr/6zcCwupvI= +-----END CERTIFICATE----- + +BJCA Global Root CA2 +==================== +-----BEGIN CERTIFICATE----- +MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQswCQYDVQQGEwJD +TjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJKQ0Eg +R2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgyMVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UE +BhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRC +SkNBIEdsb2JhbCBSb290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jl +SR9BIgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK++kpRuDCK +/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJKsVF/BvDRgh9Obl+rg/xI +1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8 +W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8g +UXOQwKhbYdDFUDn9hf7B43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w== +-----END CERTIFICATE----- + +Sectigo Public Server Authentication Root E46 +============================================= +-----BEGIN CERTIFICATE----- +MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQswCQYDVQQGEwJH +QjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBTZXJ2 +ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5 +WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0 +aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUr +gQQAIgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccCWvkEN/U0 +NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+6xnOQ6OjQjBAMB0GA1Ud +DgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAKBggqhkjOPQQDAwNnADBkAjAn7qRaqCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RH +lAFWovgzJQxC36oCMB3q4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21U +SAGKcw== +-----END CERTIFICATE----- + +Sectigo Public Server Authentication Root R46 +============================================= +-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBfMQswCQYDVQQG +EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT +ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1 +OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T +ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3 +DQEBAQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDaef0rty2k +1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnzSDBh+oF8HqcIStw+Kxwf +GExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xfiOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMP +FF1bFOdLvt30yNoDN9HWOaEhUTCDsG3XME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vu +ZDCQOc2TZYEhMbUjUDM3IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5Qaz +Yw6A3OASVYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgESJ/A +wSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu+Zd4KKTIRJLpfSYF +plhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt8uaZFURww3y8nDnAtOFr94MlI1fZ +EoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+LHaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW +6aWWrL3DkJiy4Pmi1KZHQ3xtzwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWI +IUkwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c +mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQYKlJfp/imTYp +E0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52gDY9hAaLMyZlbcp+nv4fjFg4 +exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZAFv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M +0ejf5lG5Nkc/kLnHvALcWxxPDkjBJYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI +84HxZmduTILA7rpXDhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9m +pFuiTdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5dHn5Hrwd +Vw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65LvKRRFHQV80MNNVIIb/b +E/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmm +J1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAYQqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL +-----END CERTIFICATE----- + +SSL.com TLS RSA Root CA 2022 +============================ +-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQG +EwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBSU0Eg +Um9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloXDTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMC +VVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJv +b3QgQ0EgMjAyMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u +9nTPL3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OYt6/wNr/y +7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0insS657Lb85/bRi3pZ7Qcac +oOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3PnxEX4MN8/HdIGkWCVDi1FW24IBydm5M +R7d1VVm0U3TZlMZBrViKMWYPHqIbKUBOL9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDG +D6C1vBdOSHtRwvzpXGk3R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEW +TO6Af77wdr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS+YCk +8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYSd66UNHsef8JmAOSq +g+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoGAtUjHBPW6dvbxrB6y3snm/vg1UYk +7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2fgTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsu +N+7jhHonLs0ZNbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt +hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsMQtfhWsSWTVTN +j8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvfR4iyrT7gJ4eLSYwfqUdYe5by +iB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJDPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjU +o3KUQyxi4U5cMj29TH0ZR6LDSeeWP4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqo +ENjwuSfr98t67wVylrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7Egkaib +MOlqbLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2wAgDHbICi +vRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3qr5nsLFR+jM4uElZI7xc7 +P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sjiMho6/4UIyYOf8kpIEFR3N+2ivEC+5BB0 +9+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= +-----END CERTIFICATE----- + +SSL.com TLS ECC Root CA 2022 +============================ +-----BEGIN CERTIFICATE----- +MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV +UzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBFQ0MgUm9v +dCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMx +GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3Qg +Q0EgMjAyMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWy +JGYmacCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFNSeR7T5v1 +5wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSJjy+j6CugFFR7 +81a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NWuCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGG +MAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w +7deedWo1dlJF4AIxAMeNb0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5 +Zn6g6g== +-----END CERTIFICATE----- + +Atos TrustedRoot Root CA ECC TLS 2021 +===================================== +-----BEGIN CERTIFICATE----- +MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4wLAYDVQQDDCVB +dG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQswCQYD +VQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3Mg +VHJ1c3RlZFJvb3QgUm9vdCBDQSBFQ0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYT +AkRFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6K +DP/XtXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4AjJn8ZQS +b+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2KCXWfeBmmnoJsmo7jjPX +NtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwW5kp85wxtolrbNa9d+F851F+ +uDrNozZffPc8dz7kUK2o59JZDCaOMDtuCCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGY +a3cpetskz2VAv9LcjBHo9H1/IISpQuQo +-----END CERTIFICATE----- + +Atos TrustedRoot Root CA RSA TLS 2021 +===================================== +-----BEGIN CERTIFICATE----- +MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBMMS4wLAYDVQQD +DCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQsw +CQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0 +b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNV +BAYTAkRFMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BB +l01Z4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYvYe+W/CBG +vevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZkmGbzSoXfduP9LVq6hdK +ZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDsGY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt +0xU6kGpn8bRrZtkh68rZYnxGEFzedUlnnkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVK +PNe0OwANwI8f4UDErmwh3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMY +sluMWuPD0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzygeBY +Br3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8ANSbhqRAvNncTFd+ +rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezBc6eUWsuSZIKmAMFwoW4sKeFYV+xa +fJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lIpw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUdEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0G +CSqGSIb3DQEBDAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS +4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPso0UvFJ/1TCpl +Q3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJqM7F78PRreBrAwA0JrRUITWX +AdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuywxfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9G +slA9hGCZcbUztVdF5kJHdWoOsAgMrr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2Vkt +afcxBPTy+av5EzH4AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9q +TFsR0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuYo7Ey7Nmj +1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5dDTedk+SKlOxJTnbPP/l +PqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcEoji2jbDwN/zIIX8/syQbPYtuzE2wFg2W +HYMfRsCbvUOZ58SWLs5fyQ== +-----END CERTIFICATE----- + +TrustAsia Global Root CA G3 +=========================== +-----BEGIN CERTIFICATE----- +MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEMBQAwWjELMAkG +A1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMM +G1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAeFw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEw +MTlaMFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMu +MSQwIgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNST1QY4Sxz +lZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqKAtCWHwDNBSHvBm3dIZwZ +Q0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/V +P68czH5GX6zfZBCK70bwkPAPLfSIC7Epqq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1Ag +dB4SQXMeJNnKziyhWTXAyB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm +9WAPzJMshH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gXzhqc +D0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAvkV34PmVACxmZySYg +WmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msTf9FkPz2ccEblooV7WIQn3MSAPmea +mseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jAuPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCF +TIcQcf+eQxuulXUtgQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj +7zjKsK5Xf/IhMBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E +BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4wM8zAQLpw6o1 +D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2XFNFV1pF1AWZLy4jVe5jaN/T +G3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNj +duMNhXJEIlU/HHzp/LgV6FL6qj6jITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstl +cHboCoWASzY9M/eVVHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys ++TIxxHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1onAX1daBli +2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d7XB4tmBZrOFdRWOPyN9y +aFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2NtjjgKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsAS +ZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFR +JQJ6+N1rZdVtTTDIZbpoFGWsJwt0ivKH +-----END CERTIFICATE----- + +TrustAsia Global Root CA G4 +=========================== +-----BEGIN CERTIFICATE----- +MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMwWjELMAkGA1UE +BhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMMG1Ry +dXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0yMTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJa +MFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQw +IgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATxs8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbwLxYI+hW8 +m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJijYzBhMA8GA1UdEwEB/wQF +MAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mDpm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/ +pDHel4NZg6ZvccveMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AA +bbd+NvBNEU/zy4k6LHiRUKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xk +dUfFVZDj/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== +-----END CERTIFICATE----- + +CommScope Public Trust ECC Root-01 +================================== +-----BEGIN CERTIFICATE----- +MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMwTjELMAkGA1UE +BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz +dCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNaFw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYT +AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg +RUNDIFJvb3QtMDEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLx +eP0CflfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJEhRGnSjot +6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggqhkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2 +Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liW +pDVfG2XqYZpwI7UNo5uSUm9poIyNStDuiw7LR47QjRE= +-----END CERTIFICATE----- + +CommScope Public Trust ECC Root-02 +================================== +-----BEGIN CERTIFICATE----- +MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMwTjELMAkGA1UE +BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz +dCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRaFw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYT +AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg +RUNDIFJvb3QtMDIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/M +MDALj2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmUv4RDsNuE +SgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggqhkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9 +Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/nich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs7 +3u1Z/GtMMH9ZzkXpc2AVmkzw5l4lIhVtwodZ0LKOag== +-----END CERTIFICATE----- + +CommScope Public Trust RSA Root-01 +================================== +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQELBQAwTjELMAkG +A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU +cnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNV +BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1 +c3QgUlNBIFJvb3QtMDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45Ft +nYSkYZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslhsuitQDy6 +uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0alDrJLpA6lfO741GIDuZNq +ihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3OjWiE260f6GBfZumbCk6SP/F2krfxQapWs +vCQz0b2If4b19bJzKo98rwjyGpg/qYFlP8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/c +Zip8UlF1y5mO6D1cv547KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTif +BSeolz7pUcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/kQO9 +lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JOHg9O5j9ZpSPcPYeo +KFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkBEa801M/XrmLTBQe0MXXgDW1XT2mH ++VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6UCBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm4 +5P3luG0wDQYJKoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6 +NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQnmhUQo8mUuJM +3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+QgvfKNmwrZggvkN80V4aCRck +jXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2vtrV0KnahP/t1MJ+UXjulYPPLXAziDslg+Mkf +Foom3ecnf+slpoq9uC02EJqxWE2aaE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/W +NyVntHKLr4W96ioDj8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+ +o/E4Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0wlREQKC6/ +oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHnYfkUyq+Dj7+vsQpZXdxc +1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVocicCMb3SgazNNtQEo/a2tiRc7ppqEvOuM +6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw +-----END CERTIFICATE----- + +CommScope Public Trust RSA Root-02 +================================== +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQELBQAwTjELMAkG +A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU +cnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNV +BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1 +c3QgUlNBIFJvb3QtMDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3V +rCLENQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0kyI9p+Kx +7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1CrWDaSWqVcN3SAOLMV2MC +e5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxzhkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2W +Wy09X6GDRl224yW4fKcZgBzqZUPckXk2LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rp +M9kzXzehxfCrPfp4sOcsn/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIf +hs1w/tkuFT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5kQMr +eyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3wNemKfrb3vOTlycE +VS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6vwQcQeKwRoi9C8DfF8rhW3Q5iLc4t +Vn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7Gx +cJXvYXowDQYJKoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB +KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3+VGXu6TwYofF +1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbymeAPnCKfWxkxlSaRosTKCL4BWa +MS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3NyqpgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xd +gSGn2rtO/+YHqP65DSdsu3BaVXoT6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2O +HG1QAk8mGEPej1WFsQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+Nm +YWvtPjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2dlklyALKr +dVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670v64fG9PiO/yzcnMcmyiQ +iRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17Org3bhzjlP1v9mxnhMUF6cKojawHhRUzN +lM47ni3niAIi9G7oyOzWPPO5std3eqx7 +-----END CERTIFICATE----- + +Telekom Security TLS ECC Root 2020 +================================== +-----BEGIN CERTIFICATE----- +MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQswCQYDVQQGEwJE +RTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJUZWxl +a29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIwMB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIz +NTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkg +R21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqG +SM49AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/OtdKPD/M1 +2kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDPf8iAC8GXs7s1J8nCG6NC +MEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6fMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZ +Mo7k+5Dck2TOrbRBR2Diz6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdU +ga/sf+Rn27iQ7t0l +-----END CERTIFICATE----- + +Telekom Security TLS RSA Root 2023 +================================== +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQG +EwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJU +ZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAyMDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMy +NzIzNTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJp +dHkgR21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9cUD/h3VC +KSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHVcp6R+SPWcHu79ZvB7JPP +GeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMAU6DksquDOFczJZSfvkgdmOGjup5czQRx +UX11eKvzWarE4GC+j4NSuHUaQTXtvPM6Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWo +l8hHD/BeEIvnHRz+sTugBTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9 +FIS3R/qy8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73Jco4v +zLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg8qKrBC7m8kwOFjQg +rIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8rFEz0ciD0cmfHdRHNCk+y7AO+oML +KFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7S +WWO/gLCMk3PLNaaZlSJhZQNg+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUtqeXgj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2 +p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQpGv7qHBFfLp+ +sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm9S3ul0A8Yute1hTWjOKWi0Fp +kzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErwM807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy +/SKE8YXJN3nptT+/XOR0so8RYgDdGGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4 +mZqTuXNnQkYRIer+CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtz +aL1txKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+w6jv/naa +oqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aKL4x35bcF7DvB7L6Gs4a8 +wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+ljX273CXE2whJdV/LItM3z7gLfEdxquVeE +HVlNjM7IDiPCtyaaEBRx/pOyiriA8A4QntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0 +o82bNSQ3+pCTE4FCxpgmdTdmQRCsu/WU48IxK63nI1bMNSWSs1A= +-----END CERTIFICATE----- + +FIRMAPROFESIONAL CA ROOT-A WEB +============================== +-----BEGIN CERTIFICATE----- +MIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQswCQYDVQQGEwJF +UzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4 +MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENBIFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2 +WhcNNDcwMzMxMDkwMTM2WjBuMQswCQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25h +bCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFM +IENBIFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zfe9MEkVz6 +iMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6CcyvHZpsKjECcfIr28jlg +st7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FD +Y1w8ndYn81LsF7Kpryz3dvgwHQYDVR0OBBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB +/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgL +cFBTApFwhVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dGXSaQ +pYXFuXqUPoeovQA= +-----END CERTIFICATE----- + +TWCA CYBER Root CA +================== +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQMQswCQYDVQQG +EwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB +IENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQG +EwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB +IENZQkVSIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1s +Ts6P40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxFavcokPFh +V8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/34bKS1PE2Y2yHer43CdT +o0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684iJkXXYJndzk834H/nY62wuFm40AZoNWDT +Nq5xQwTxaWV4fPMf88oon1oglWa0zbfuj3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK +/c/WMw+f+5eesRycnupfXtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkH +IuNZW0CP2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDAS9TM +fAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDAoS/xUgXJP+92ZuJF +2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzCkHDXShi8fgGwsOsVHkQGzaRP6AzR +wyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83 +QOGt4A1WNzAdBgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB +AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0ttGlTITVX1olN +c79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn68xDiBaiA9a5F/gZbG0jAn/x +X9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNnTKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDR +IG4kqIQnoVesqlVYL9zZyvpoBJ7tRCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq +/p1hvIbZv97Tujqxf36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0R +FxbIQh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz8ppy6rBe +Pm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4NxKfKjLji7gh7MMrZQzv +It6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzXxeSDwWrruoBa3lwtcHb4yOWHh8qgnaHl +IhInD0Q9HWzq1MKLL295q39QpsQZp6F6t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X +-----END CERTIFICATE----- + +SecureSign Root CA12 +==================== +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQELBQAwUTELMAkG +A1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT +ZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgwNTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJ +BgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU +U2VjdXJlU2lnbiBSb290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3 +emhFKxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mtp7JIKwcc +J/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zdJ1M3s6oYwlkm7Fsf0uZl +fO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gurFzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBF +EaCeVESE99g2zvVQR9wsMJvuwPWW0v4JhscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1Uef +NzFJM3IFTQy2VYzxV4+Kh9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsFAAOC +AQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6LdmmQOmFxv3Y67ilQi +LUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJmBClnW8Zt7vPemVV2zfrPIpyMpce +mik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPS +vWKErI4cqc1avTc7bgoitPQV55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhga +aaI5gdka9at/yOPiZwud9AzqVN/Ssq+xIvEg37xEHA== +-----END CERTIFICATE----- + +SecureSign Root CA14 +==================== +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEMBQAwUTELMAkG +A1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT +ZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgwNzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJ +BgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU +U2VjdXJlU2lnbiBSb290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh +1oq/FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOgvlIfX8xn +bacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy6pJxaeQp8E+BgQQ8sqVb +1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa +/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9JkdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOE +kJTRX45zGRBdAuVwpcAQ0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSx +jVIHvXiby8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac18iz +ju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs0Wq2XSqypWa9a4X0 +dFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIABSMbHdPTGrMNASRZhdCyvjG817XsY +AFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVLApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQAB +o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeq +YR3r6/wtbyPk86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E +rX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ibed87hwriZLoA +ymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopTzfFP7ELyk+OZpDc8h7hi2/Ds +Hzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHSDCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPG +FrojutzdfhrGe0K22VoF3Jpf1d+42kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6q +nsb58Nn4DSEC5MUoFlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/ +OfVyK4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6dB7h7sxa +OgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtlLor6CZpO2oYofaphNdgO +pygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB365jJ6UeTo3cKXhZ+PmhIIynJkBugnLN +eLLIjzwec+fBH7/PzqUqm9tEZDKgu39cJRNItX+S +-----END CERTIFICATE----- + +SecureSign Root CA15 +==================== +-----BEGIN CERTIFICATE----- +MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMwUTELMAkGA1UE +BhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRTZWN1 +cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMyNTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNV +BAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2Vj +dXJlU2lnbiBSb290IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5G +dCx4wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSRZHX+AezB +2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT9DAKBggqhkjOPQQDAwNoADBlAjEA2S6J +fl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJ +SwdLZrWeqrqgHkHZAXQ6bkU6iYAZezKYVWOr62Nuk22rGwlgMU4= +-----END CERTIFICATE----- diff --git a/tools/geoip/composer/ca-bundle/src/CaBundle.php b/tools/geoip/composer/ca-bundle/src/CaBundle.php new file mode 100644 index 000000000..2d6b48c56 --- /dev/null +++ b/tools/geoip/composer/ca-bundle/src/CaBundle.php @@ -0,0 +1,321 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\CaBundle; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Process\PhpProcess; + +/** + * @author Chris Smith + * @author Jordi Boggiano + */ +class CaBundle +{ + /** @var string|null */ + private static $caPath; + /** @var array */ + private static $caFileValidity = array(); + + /** + * Returns the system CA bundle path, or a path to the bundled one + * + * This method was adapted from Sslurp. + * https://github.com/EvanDotPro/Sslurp + * + * (c) Evan Coury + * + * For the full copyright and license information, please see below: + * + * Copyright (c) 2013, Evan Coury + * 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. + * + * @param LoggerInterface $logger optional logger for information about which CA files were loaded + * @return string path to a CA bundle file or directory + */ + public static function getSystemCaRootBundlePath(?LoggerInterface $logger = null) + { + if (self::$caPath !== null) { + return self::$caPath; + } + $caBundlePaths = array(); + + // If SSL_CERT_FILE env variable points to a valid certificate/bundle, use that. + // This mimics how OpenSSL uses the SSL_CERT_FILE env variable. + $caBundlePaths[] = self::getEnvVariable('SSL_CERT_FILE'); + + // If SSL_CERT_DIR env variable points to a valid certificate/bundle, use that. + // This mimics how OpenSSL uses the SSL_CERT_FILE env variable. + $caBundlePaths[] = self::getEnvVariable('SSL_CERT_DIR'); + + $caBundlePaths[] = ini_get('openssl.cafile'); + $caBundlePaths[] = ini_get('openssl.capath'); + + $otherLocations = array( + '/etc/pki/tls/certs/ca-bundle.crt', // Fedora, RHEL, CentOS (ca-certificates package) + '/etc/ssl/certs/ca-certificates.crt', // Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package) + '/etc/ssl/ca-bundle.pem', // SUSE, openSUSE (ca-certificates package) + '/usr/ssl/certs/ca-bundle.crt', // Cygwin + '/opt/local/share/curl/curl-ca-bundle.crt', // OS X macports, curl-ca-bundle package + '/usr/local/share/curl/curl-ca-bundle.crt', // Default cURL CA bunde path (without --with-ca-bundle option) + '/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat? + '/etc/ssl/cert.pem', // OpenBSD + '/usr/local/etc/openssl/cert.pem', // OS X homebrew, openssl package + '/usr/local/etc/openssl@1.1/cert.pem', // OS X homebrew, openssl@1.1 package + '/opt/homebrew/etc/openssl@3/cert.pem', // macOS silicon homebrew, openssl@3 package + '/opt/homebrew/etc/openssl@1.1/cert.pem', // macOS silicon homebrew, openssl@1.1 package + '/etc/pki/tls/certs', + '/etc/ssl/certs', // FreeBSD + ); + + $caBundlePaths = array_merge($caBundlePaths, $otherLocations); + + foreach ($caBundlePaths as $caBundle) { + if ($caBundle && self::caFileUsable($caBundle, $logger)) { + return self::$caPath = $caBundle; + } + + if ($caBundle && self::caDirUsable($caBundle, $logger)) { + return self::$caPath = $caBundle; + } + } + + return self::$caPath = static::getBundledCaBundlePath(); // Bundled CA file, last resort + } + + /** + * Returns the path to the bundled CA file + * + * In case you don't want to trust the user or the system, you can use this directly + * + * @return string path to a CA bundle file + */ + public static function getBundledCaBundlePath() + { + $caBundleFile = __DIR__.'/../res/cacert.pem'; + + // cURL does not understand 'phar://' paths + // see https://github.com/composer/ca-bundle/issues/10 + if (0 === strpos($caBundleFile, 'phar://')) { + $tempCaBundleFile = tempnam(sys_get_temp_dir(), 'openssl-ca-bundle-'); + if (false === $tempCaBundleFile) { + throw new \RuntimeException('Could not create a temporary file to store the bundled CA file'); + } + + file_put_contents( + $tempCaBundleFile, + file_get_contents($caBundleFile) + ); + + register_shutdown_function(function() use ($tempCaBundleFile) { + @unlink($tempCaBundleFile); + }); + + $caBundleFile = $tempCaBundleFile; + } + + return $caBundleFile; + } + + /** + * Validates a CA file using opensl_x509_parse only if it is safe to use + * + * @param string $filename + * @param LoggerInterface $logger optional logger for information about which CA files were loaded + * + * @return bool + */ + public static function validateCaFile($filename, ?LoggerInterface $logger = null) + { + static $warned = false; + + if (isset(self::$caFileValidity[$filename])) { + return self::$caFileValidity[$filename]; + } + + $contents = file_get_contents($filename); + + if (is_string($contents) && strlen($contents) > 0) { + $contents = preg_replace("/^(\\-+(?:BEGIN|END))\\s+TRUSTED\\s+(CERTIFICATE\\-+)\$/m", '$1 $2', $contents); + if (null === $contents) { + // regex extraction failed + $isValid = false; + } else { + $isValid = (bool) openssl_x509_parse($contents); + } + } else { + $isValid = false; + } + + if ($logger) { + $logger->debug('Checked CA file '.realpath($filename).': '.($isValid ? 'valid' : 'invalid')); + } + + return self::$caFileValidity[$filename] = $isValid; + } + + /** + * Test if it is safe to use the PHP function openssl_x509_parse(). + * + * This checks if OpenSSL extensions is vulnerable to remote code execution + * via the exploit documented as CVE-2013-6420. + * + * @return bool + */ + public static function isOpensslParseSafe() + { + return true; + } + + /** + * Resets the static caches + * @return void + */ + public static function reset() + { + self::$caFileValidity = array(); + self::$caPath = null; + } + + /** + * @param string $name + * @return string|false + */ + private static function getEnvVariable($name) + { + if (isset($_SERVER[$name])) { + return (string) $_SERVER[$name]; + } + + if (PHP_SAPI === 'cli' && ($value = getenv($name)) !== false && $value !== null) { + return (string) $value; + } + + return false; + } + + /** + * @param string|false $certFile + * @param LoggerInterface|null $logger + * @return bool + */ + private static function caFileUsable($certFile, ?LoggerInterface $logger = null) + { + return $certFile + && self::isFile($certFile, $logger) + && self::isReadable($certFile, $logger) + && self::validateCaFile($certFile, $logger); + } + + /** + * @param string|false $certDir + * @param LoggerInterface|null $logger + * @return bool + */ + private static function caDirUsable($certDir, ?LoggerInterface $logger = null) + { + return $certDir + && self::isDir($certDir, $logger) + && self::isReadable($certDir, $logger) + && self::glob($certDir . '/*', $logger); + } + + /** + * @param string $certFile + * @param LoggerInterface|null $logger + * @return bool + */ + private static function isFile($certFile, ?LoggerInterface $logger = null) + { + $isFile = @is_file($certFile); + if (!$isFile && $logger) { + $logger->debug(sprintf('Checked CA file %s does not exist or it is not a file.', $certFile)); + } + + return $isFile; + } + + /** + * @param string $certDir + * @param LoggerInterface|null $logger + * @return bool + */ + private static function isDir($certDir, ?LoggerInterface $logger = null) + { + $isDir = @is_dir($certDir); + if (!$isDir && $logger) { + $logger->debug(sprintf('Checked directory %s does not exist or it is not a directory.', $certDir)); + } + + return $isDir; + } + + /** + * @param string $certFileOrDir + * @param LoggerInterface|null $logger + * @return bool + */ + private static function isReadable($certFileOrDir, ?LoggerInterface $logger = null) + { + $isReadable = @is_readable($certFileOrDir); + if (!$isReadable && $logger) { + $logger->debug(sprintf('Checked file or directory %s is not readable.', $certFileOrDir)); + } + + return $isReadable; + } + + /** + * @param string $pattern + * @param LoggerInterface|null $logger + * @return bool + */ + private static function glob($pattern, ?LoggerInterface $logger = null) + { + $certs = glob($pattern); + if ($certs === false) { + if ($logger) { + $logger->debug(sprintf("An error occurred while trying to find certificates for pattern: %s", $pattern)); + } + return false; + } + + if (count($certs) === 0) { + if ($logger) { + $logger->debug(sprintf("No CA files found for pattern: %s", $pattern)); + } + return false; + } + + return true; + } +} diff --git a/tools/geoip/composer/installed.json b/tools/geoip/composer/installed.json new file mode 100644 index 000000000..762917212 --- /dev/null +++ b/tools/geoip/composer/installed.json @@ -0,0 +1,266 @@ +{ + "packages": [ + { + "name": "composer/ca-bundle", + "version": "1.5.4", + "version_normalized": "1.5.4.0", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "bc0593537a463e55cadf45fd938d23b75095b7e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/bc0593537a463e55cadf45fd938d23b75095b7e1", + "reference": "bc0593537a463e55cadf45fd938d23b75095b7e1", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8 || ^9", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "time": "2024-11-27T15:35:25+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues", + "source": "https://github.com/composer/ca-bundle/tree/1.5.4" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "install-path": "./ca-bundle" + }, + { + "name": "geoip2/geoip2", + "version": "v3.1.0", + "version_normalized": "3.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/maxmind/GeoIP2-php.git", + "reference": "c86fbeaa7e42279dd9e7af0b015384e721832b88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/c86fbeaa7e42279dd9e7af0b015384e721832b88", + "reference": "c86fbeaa7e42279dd9e7af0b015384e721832b88", + "shasum": "" + }, + "require": { + "ext-json": "*", + "maxmind-db/reader": "^1.12.0", + "maxmind/web-service-common": "~0.10", + "php": ">=8.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^10.0", + "squizlabs/php_codesniffer": "3.*" + }, + "time": "2024-11-15T16:33:31+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "GeoIp2\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Gregory J. Oschwald", + "email": "goschwald@maxmind.com", + "homepage": "https://www.maxmind.com/" + } + ], + "description": "MaxMind GeoIP2 PHP API", + "homepage": "https://github.com/maxmind/GeoIP2-php", + "keywords": [ + "IP", + "geoip", + "geoip2", + "geolocation", + "maxmind" + ], + "support": { + "issues": "https://github.com/maxmind/GeoIP2-php/issues", + "source": "https://github.com/maxmind/GeoIP2-php/tree/v3.1.0" + }, + "install-path": "../geoip2/geoip2" + }, + { + "name": "maxmind-db/reader", + "version": "v1.12.0", + "version_normalized": "1.12.0.0", + "source": { + "type": "git", + "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git", + "reference": "5b2d7a721dedfaef9dc20822c5fe7d26f9f8eb90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/5b2d7a721dedfaef9dc20822c5fe7d26f9f8eb90", + "reference": "5b2d7a721dedfaef9dc20822c5fe7d26f9f8eb90", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "conflict": { + "ext-maxminddb": "<1.11.1 || >=2.0.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", + "phpunit/phpunit": ">=8.0.0,<10.0.0", + "squizlabs/php_codesniffer": "3.*" + }, + "suggest": { + "ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", + "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", + "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups" + }, + "time": "2024-11-14T22:43:47+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "MaxMind\\Db\\": "src/MaxMind/Db" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Gregory J. Oschwald", + "email": "goschwald@maxmind.com", + "homepage": "https://www.maxmind.com/" + } + ], + "description": "MaxMind DB Reader API", + "homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php", + "keywords": [ + "database", + "geoip", + "geoip2", + "geolocation", + "maxmind" + ], + "support": { + "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues", + "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.12.0" + }, + "install-path": "../maxmind-db/reader" + }, + { + "name": "maxmind/web-service-common", + "version": "v0.10.0", + "version_normalized": "0.10.0.0", + "source": { + "type": "git", + "url": "https://github.com/maxmind/web-service-common-php.git", + "reference": "d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4", + "reference": "d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.0.3", + "ext-curl": "*", + "ext-json": "*", + "php": ">=8.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^8.0 || ^9.0", + "squizlabs/php_codesniffer": "3.*" + }, + "time": "2024-11-14T23:14:52+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "MaxMind\\Exception\\": "src/Exception", + "MaxMind\\WebService\\": "src/WebService" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Gregory Oschwald", + "email": "goschwald@maxmind.com" + } + ], + "description": "Internal MaxMind Web Service API", + "homepage": "https://github.com/maxmind/web-service-common-php", + "support": { + "issues": "https://github.com/maxmind/web-service-common-php/issues", + "source": "https://github.com/maxmind/web-service-common-php/tree/v0.10.0" + }, + "install-path": "../maxmind/web-service-common" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/tools/geoip/composer/installed.php b/tools/geoip/composer/installed.php new file mode 100644 index 000000000..c1d733d97 --- /dev/null +++ b/tools/geoip/composer/installed.php @@ -0,0 +1,59 @@ + array( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => NULL, + 'name' => '__root__', + 'dev' => true, + ), + 'versions' => array( + '__root__' => array( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => NULL, + 'dev_requirement' => false, + ), + 'composer/ca-bundle' => array( + 'pretty_version' => '1.5.4', + 'version' => '1.5.4.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/./ca-bundle', + 'aliases' => array(), + 'reference' => 'bc0593537a463e55cadf45fd938d23b75095b7e1', + 'dev_requirement' => false, + ), + 'geoip2/geoip2' => array( + 'pretty_version' => 'v3.1.0', + 'version' => '3.1.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../geoip2/geoip2', + 'aliases' => array(), + 'reference' => 'c86fbeaa7e42279dd9e7af0b015384e721832b88', + 'dev_requirement' => false, + ), + 'maxmind-db/reader' => array( + 'pretty_version' => 'v1.12.0', + 'version' => '1.12.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../maxmind-db/reader', + 'aliases' => array(), + 'reference' => '5b2d7a721dedfaef9dc20822c5fe7d26f9f8eb90', + 'dev_requirement' => false, + ), + 'maxmind/web-service-common' => array( + 'pretty_version' => 'v0.10.0', + 'version' => '0.10.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../maxmind/web-service-common', + 'aliases' => array(), + 'reference' => 'd7c7c42fc31bff26e0ded73a6e187bcfb193f9c4', + 'dev_requirement' => false, + ), + ), +); diff --git a/tools/geoip/composer/platform_check.php b/tools/geoip/composer/platform_check.php new file mode 100644 index 000000000..4c3a5d68f --- /dev/null +++ b/tools/geoip/composer/platform_check.php @@ -0,0 +1,26 @@ += 80100)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.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/tools/geoip/geoip.inc b/tools/geoip/geoip.inc deleted file mode 100644 index d2aea2e09..000000000 --- a/tools/geoip/geoip.inc +++ /dev/null @@ -1,820 +0,0 @@ - 0, "AP" => 1, "EU" => 2, "AD" => 3, "AE" => 4, "AF" => 5, -"AG" => 6, "AI" => 7, "AL" => 8, "AM" => 9, "CW" => 10, "AO" => 11, -"AQ" => 12, "AR" => 13, "AS" => 14, "AT" => 15, "AU" => 16, "AW" => 17, -"AZ" => 18, "BA" => 19, "BB" => 20, "BD" => 21, "BE" => 22, "BF" => 23, -"BG" => 24, "BH" => 25, "BI" => 26, "BJ" => 27, "BM" => 28, "BN" => 29, -"BO" => 30, "BR" => 31, "BS" => 32, "BT" => 33, "BV" => 34, "BW" => 35, -"BY" => 36, "BZ" => 37, "CA" => 38, "CC" => 39, "CD" => 40, "CF" => 41, -"CG" => 42, "CH" => 43, "CI" => 44, "CK" => 45, "CL" => 46, "CM" => 47, -"CN" => 48, "CO" => 49, "CR" => 50, "CU" => 51, "CV" => 52, "CX" => 53, -"CY" => 54, "CZ" => 55, "DE" => 56, "DJ" => 57, "DK" => 58, "DM" => 59, -"DO" => 60, "DZ" => 61, "EC" => 62, "EE" => 63, "EG" => 64, "EH" => 65, -"ER" => 66, "ES" => 67, "ET" => 68, "FI" => 69, "FJ" => 70, "FK" => 71, -"FM" => 72, "FO" => 73, "FR" => 74, "SX" => 75, "GA" => 76, "GB" => 77, -"GD" => 78, "GE" => 79, "GF" => 80, "GH" => 81, "GI" => 82, "GL" => 83, -"GM" => 84, "GN" => 85, "GP" => 86, "GQ" => 87, "GR" => 88, "GS" => 89, -"GT" => 90, "GU" => 91, "GW" => 92, "GY" => 93, "HK" => 94, "HM" => 95, -"HN" => 96, "HR" => 97, "HT" => 98, "HU" => 99, "ID" => 100, "IE" => 101, -"IL" => 102, "IN" => 103, "IO" => 104, "IQ" => 105, "IR" => 106, "IS" => 107, -"IT" => 108, "JM" => 109, "JO" => 110, "JP" => 111, "KE" => 112, "KG" => 113, -"KH" => 114, "KI" => 115, "KM" => 116, "KN" => 117, "KP" => 118, "KR" => 119, -"KW" => 120, "KY" => 121, "KZ" => 122, "LA" => 123, "LB" => 124, "LC" => 125, -"LI" => 126, "LK" => 127, "LR" => 128, "LS" => 129, "LT" => 130, "LU" => 131, -"LV" => 132, "LY" => 133, "MA" => 134, "MC" => 135, "MD" => 136, "MG" => 137, -"MH" => 138, "MK" => 139, "ML" => 140, "MM" => 141, "MN" => 142, "MO" => 143, -"MP" => 144, "MQ" => 145, "MR" => 146, "MS" => 147, "MT" => 148, "MU" => 149, -"MV" => 150, "MW" => 151, "MX" => 152, "MY" => 153, "MZ" => 154, "NA" => 155, -"NC" => 156, "NE" => 157, "NF" => 158, "NG" => 159, "NI" => 160, "NL" => 161, -"NO" => 162, "NP" => 163, "NR" => 164, "NU" => 165, "NZ" => 166, "OM" => 167, -"PA" => 168, "PE" => 169, "PF" => 170, "PG" => 171, "PH" => 172, "PK" => 173, -"PL" => 174, "PM" => 175, "PN" => 176, "PR" => 177, "PS" => 178, "PT" => 179, -"PW" => 180, "PY" => 181, "QA" => 182, "RE" => 183, "RO" => 184, "RU" => 185, -"RW" => 186, "SA" => 187, "SB" => 188, "SC" => 189, "SD" => 190, "SE" => 191, -"SG" => 192, "SH" => 193, "SI" => 194, "SJ" => 195, "SK" => 196, "SL" => 197, -"SM" => 198, "SN" => 199, "SO" => 200, "SR" => 201, "ST" => 202, "SV" => 203, -"SY" => 204, "SZ" => 205, "TC" => 206, "TD" => 207, "TF" => 208, "TG" => 209, -"TH" => 210, "TJ" => 211, "TK" => 212, "TM" => 213, "TN" => 214, "TO" => 215, -"TL" => 216, "TR" => 217, "TT" => 218, "TV" => 219, "TW" => 220, "TZ" => 221, -"UA" => 222, "UG" => 223, "UM" => 224, "US" => 225, "UY" => 226, "UZ" => 227, -"VA" => 228, "VC" => 229, "VE" => 230, "VG" => 231, "VI" => 232, "VN" => 233, -"VU" => 234, "WF" => 235, "WS" => 236, "YE" => 237, "YT" => 238, "RS" => 239, -"ZA" => 240, "ZM" => 241, "ME" => 242, "ZW" => 243, "A1" => 244, "A2" => 245, -"O1" => 246, "AX" => 247, "GG" => 248, "IM" => 249, "JE" => 250, "BL" => 251, -"MF" => 252, "BQ" => 253, -); - var $GEOIP_COUNTRY_CODES = array( - "","AP","EU","AD","AE","AF","AG","AI","AL","AM","CW", - "AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB", - "BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO", - "BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD", - "CF","CG","CH","CI","CK","CL","CM","CN","CO","CR", - "CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO", - "DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ", - "FK","FM","FO","FR","SX","GA","GB","GD","GE","GF", - "GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT", - "GU","GW","GY","HK","HM","HN","HR","HT","HU","ID", - "IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO", - "JP","KE","KG","KH","KI","KM","KN","KP","KR","KW", - "KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT", - "LU","LV","LY","MA","MC","MD","MG","MH","MK","ML", - "MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV", - "MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI", - "NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF", - "PG","PH","PK","PL","PM","PN","PR","PS","PT","PW", - "PY","QA","RE","RO","RU","RW","SA","SB","SC","SD", - "SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO", - "SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH", - "TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW", - "TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE", - "VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA", - "ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE", - "BL","MF", "BQ"); - var $GEOIP_COUNTRY_CODES3 = array( - "","AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","CUW", - "AGO","ATA","ARG","ASM","AUT","AUS","ABW","AZE","BIH","BRB", - "BGD","BEL","BFA","BGR","BHR","BDI","BEN","BMU","BRN","BOL", - "BRA","BHS","BTN","BVT","BWA","BLR","BLZ","CAN","CCK","COD", - "CAF","COG","CHE","CIV","COK","CHL","CMR","CHN","COL","CRI", - "CUB","CPV","CXR","CYP","CZE","DEU","DJI","DNK","DMA","DOM", - "DZA","ECU","EST","EGY","ESH","ERI","ESP","ETH","FIN","FJI", - "FLK","FSM","FRO","FRA","SXM","GAB","GBR","GRD","GEO","GUF", - "GHA","GIB","GRL","GMB","GIN","GLP","GNQ","GRC","SGS","GTM", - "GUM","GNB","GUY","HKG","HMD","HND","HRV","HTI","HUN","IDN", - "IRL","ISR","IND","IOT","IRQ","IRN","ISL","ITA","JAM","JOR", - "JPN","KEN","KGZ","KHM","KIR","COM","KNA","PRK","KOR","KWT", - "CYM","KAZ","LAO","LBN","LCA","LIE","LKA","LBR","LSO","LTU", - "LUX","LVA","LBY","MAR","MCO","MDA","MDG","MHL","MKD","MLI", - "MMR","MNG","MAC","MNP","MTQ","MRT","MSR","MLT","MUS","MDV", - "MWI","MEX","MYS","MOZ","NAM","NCL","NER","NFK","NGA","NIC", - "NLD","NOR","NPL","NRU","NIU","NZL","OMN","PAN","PER","PYF", - "PNG","PHL","PAK","POL","SPM","PCN","PRI","PSE","PRT","PLW", - "PRY","QAT","REU","ROU","RUS","RWA","SAU","SLB","SYC","SDN", - "SWE","SGP","SHN","SVN","SJM","SVK","SLE","SMR","SEN","SOM", - "SUR","STP","SLV","SYR","SWZ","TCA","TCD","ATF","TGO","THA", - "TJK","TKL","TKM","TUN","TON","TLS","TUR","TTO","TUV","TWN", - "TZA","UKR","UGA","UMI","USA","URY","UZB","VAT","VCT","VEN", - "VGB","VIR","VNM","VUT","WLF","WSM","YEM","MYT","SRB","ZAF", - "ZMB","MNE","ZWE","A1","A2","O1","ALA","GGY","IMN","JEY", - "BLM","MAF", "BES" - ); - var $GEOIP_COUNTRY_NAMES = array( - "","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Curacao", - "Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados", - "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia", - "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the", - "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica", - "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic", - "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji", - "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","Sint Maarten (Dutch part)","Gabon","United Kingdom","Grenada","Georgia","French Guiana", - "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala", - "Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia", - "Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan", - "Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait", - "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania", - "Luxembourg","Latvia","Libya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali", - "Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives", - "Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua", - "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia", - "Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau", - "Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan", - "Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname", - "Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand", - "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan", - "Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela", - "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa", - "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey", - "Saint Barthelemy","Saint Martin", "Bonaire, Saint Eustatius and Saba" -); - - var $GEOIP_CONTINENT_CODES = array( - "--", "AS","EU","EU","AS","AS","NA","NA","EU","AS","NA", - "AF","AN","SA","OC","EU","OC","NA","AS","EU","NA", - "AS","EU","AF","EU","AS","AF","AF","NA","AS","SA", - "SA","NA","AS","AN","AF","EU","NA","NA","AS","AF", - "AF","AF","EU","AF","OC","SA","AF","AS","SA","NA", - "NA","AF","AS","AS","EU","EU","AF","EU","NA","NA", - "AF","SA","EU","AF","AF","AF","EU","AF","EU","OC", - "SA","OC","EU","EU","NA","AF","EU","NA","AS","SA", - "AF","EU","NA","AF","AF","NA","AF","EU","AN","NA", - "OC","AF","SA","AS","AN","NA","EU","NA","EU","AS", - "EU","AS","AS","AS","AS","AS","EU","EU","NA","AS", - "AS","AF","AS","AS","OC","AF","NA","AS","AS","AS", - "NA","AS","AS","AS","NA","EU","AS","AF","AF","EU", - "EU","EU","AF","AF","EU","EU","AF","OC","EU","AF", - "AS","AS","AS","OC","NA","AF","NA","EU","AF","AS", - "AF","NA","AS","AF","AF","OC","AF","OC","AF","NA", - "EU","EU","AS","OC","OC","OC","AS","NA","SA","OC", - "OC","AS","AS","EU","NA","OC","NA","AS","EU","OC", - "SA","AS","AF","EU","EU","AF","AS","OC","AF","AF", - "EU","AS","AF","EU","EU","EU","AF","EU","AF","AF", - "SA","AF","NA","AS","AF","NA","AF","AN","AF","AS", - "AS","OC","AS","AF","OC","AS","EU","NA","OC","AS", - "AF","EU","AF","OC","NA","SA","AS","EU","NA","SA", - "NA","NA","AS","OC","OC","OC","AS","AF","EU","AF", - "AF","EU","AF","--","--","--","EU","EU","EU","EU", - "NA","NA","NA" -); - -} - -if (!function_exists('geoip_load_shared_mem ')){ -function geoip_load_shared_mem ($file) { - - $fp = fopen($file, "rb"); - if (!$fp) { - print "error opening $file: $php_errormsg\n"; - exit; - } - $s_array = fstat($fp); - $size = $s_array['size']; - if ($shmid = @shmop_open (GEOIP_SHM_KEY, "w", 0, 0)) { - shmop_delete ($shmid); - shmop_close ($shmid); - } - $shmid = shmop_open (GEOIP_SHM_KEY, "c", 0644, $size); - shmop_write ($shmid, fread($fp, $size), 0); - shmop_close ($shmid); -} -} - -if (!function_exists('_setup_segments')){ -function _setup_segments($gi){ - $gi->databaseType = GEOIP_COUNTRY_EDITION; - $gi->record_length = STANDARD_RECORD_LENGTH; - if ($gi->flags & GEOIP_SHARED_MEMORY) { - $offset = @shmop_size ($gi->shmid) - 3; - for ($i = 0; $i < STRUCTURE_INFO_MAX_SIZE; $i++) { - $delim = @shmop_read ($gi->shmid, $offset, 3); - $offset += 3; - if ($delim == (chr(255).chr(255).chr(255))) { - $gi->databaseType = ord(@shmop_read ($gi->shmid, $offset, 1)); - $offset++; - - if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){ - $gi->databaseSegments = GEOIP_STATE_BEGIN_REV0; - } else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1){ - $gi->databaseSegments = GEOIP_STATE_BEGIN_REV1; - } else if (($gi->databaseType == GEOIP_CITY_EDITION_REV0)|| - ($gi->databaseType == GEOIP_CITY_EDITION_REV1) - || ($gi->databaseType == GEOIP_ORG_EDITION) - || ($gi->databaseType == GEOIP_ORG_EDITION_V6) - || ($gi->databaseType == GEOIP_DOMAIN_EDITION) - || ($gi->databaseType == GEOIP_DOMAIN_EDITION_V6) - || ($gi->databaseType == GEOIP_ISP_EDITION) - || ($gi->databaseType == GEOIP_ISP_EDITION_V6) - || ($gi->databaseType == GEOIP_USERTYPE_EDITION) - || ($gi->databaseType == GEOIP_USERTYPE_EDITION_V6) - || ($gi->databaseType == GEOIP_LOCATIONA_EDITION) - || ($gi->databaseType == GEOIP_ACCURACYRADIUS_EDITION) - || ($gi->databaseType == GEOIP_CITY_EDITION_REV0_V6) - || ($gi->databaseType == GEOIP_CITY_EDITION_REV1_V6) - || ($gi->databaseType == GEOIP_NETSPEED_EDITION_REV1) - || ($gi->databaseType == GEOIP_NETSPEED_EDITION_REV1_V6) - || ($gi->databaseType == GEOIP_ASNUM_EDITION) - || ($gi->databaseType == GEOIP_ASNUM_EDITION_V6)){ - $gi->databaseSegments = 0; - $buf = @shmop_read ($gi->shmid, $offset, SEGMENT_RECORD_LENGTH); - for ($j = 0;$j < SEGMENT_RECORD_LENGTH;$j++){ - $gi->databaseSegments += (ord($buf[$j]) << ($j * 8)); - } - if (($gi->databaseType == GEOIP_ORG_EDITION) - || ($gi->databaseType == GEOIP_ORG_EDITION_V6) - || ($gi->databaseType == GEOIP_DOMAIN_EDITION) - || ($gi->databaseType == GEOIP_DOMAIN_EDITION_V6) - || ($gi->databaseType == GEOIP_ISP_EDITION) - || ($gi->databaseType == GEOIP_ISP_EDITION_V6)) { - $gi->record_length = ORG_RECORD_LENGTH; - } - } - break; - } else { - $offset -= 4; - } - } - if (($gi->databaseType == GEOIP_COUNTRY_EDITION)|| - ($gi->databaseType == GEOIP_COUNTRY_EDITION_V6)|| - ($gi->databaseType == GEOIP_PROXY_EDITION)|| - ($gi->databaseType == GEOIP_NETSPEED_EDITION)){ - $gi->databaseSegments = GEOIP_COUNTRY_BEGIN; - } - } else { - $filepos = ftell($gi->filehandle); - fseek($gi->filehandle, -3, SEEK_END); - for ($i = 0; $i < STRUCTURE_INFO_MAX_SIZE; $i++) { - $delim = fread($gi->filehandle,3); - if ($delim == (chr(255).chr(255).chr(255))){ - $gi->databaseType = ord(fread($gi->filehandle,1)); - if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){ - $gi->databaseSegments = GEOIP_STATE_BEGIN_REV0; - } - else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1){ - $gi->databaseSegments = GEOIP_STATE_BEGIN_REV1; - } else if (($gi->databaseType == GEOIP_CITY_EDITION_REV0) - || ($gi->databaseType == GEOIP_CITY_EDITION_REV1) - || ($gi->databaseType == GEOIP_CITY_EDITION_REV0_V6) - || ($gi->databaseType == GEOIP_CITY_EDITION_REV1_V6) - || ($gi->databaseType == GEOIP_ORG_EDITION) - || ($gi->databaseType == GEOIP_DOMAIN_EDITION) - || ($gi->databaseType == GEOIP_ISP_EDITION) - || ($gi->databaseType == GEOIP_ORG_EDITION_V6) - || ($gi->databaseType == GEOIP_DOMAIN_EDITION_V6) - || ($gi->databaseType == GEOIP_ISP_EDITION_V6) - || ($gi->databaseType == GEOIP_LOCATIONA_EDITION) - || ($gi->databaseType == GEOIP_ACCURACYRADIUS_EDITION) - || ($gi->databaseType == GEOIP_CITY_EDITION_REV0_V6) - || ($gi->databaseType == GEOIP_CITY_EDITION_REV1_V6) - || ($gi->databaseType == GEOIP_NETSPEED_EDITION_REV1) - || ($gi->databaseType == GEOIP_NETSPEED_EDITION_REV1_V6) - || ($gi->databaseType == GEOIP_USERTYPE_EDITION) - || ($gi->databaseType == GEOIP_USERTYPE_EDITION_V6) - || ($gi->databaseType == GEOIP_ASNUM_EDITION) - || ($gi->databaseType == GEOIP_ASNUM_EDITION_V6)){ - $gi->databaseSegments = 0; - $buf = fread($gi->filehandle,SEGMENT_RECORD_LENGTH); - for ($j = 0;$j < SEGMENT_RECORD_LENGTH;$j++){ - $gi->databaseSegments += (ord($buf[$j]) << ($j * 8)); - } - if ( ( $gi->databaseType == GEOIP_ORG_EDITION ) - || ( $gi->databaseType == GEOIP_DOMAIN_EDITION ) - || ( $gi->databaseType == GEOIP_ISP_EDITION ) - || ( $gi->databaseType == GEOIP_ORG_EDITION_V6 ) - || ( $gi->databaseType == GEOIP_DOMAIN_EDITION_V6 ) - || ( $gi->databaseType == GEOIP_ISP_EDITION_V6 )) { - $gi->record_length = ORG_RECORD_LENGTH; - } - } - break; - } else { - fseek($gi->filehandle, -4, SEEK_CUR); - } - } - if (($gi->databaseType == GEOIP_COUNTRY_EDITION)|| - ($gi->databaseType == GEOIP_COUNTRY_EDITION_V6)|| - ($gi->databaseType == GEOIP_PROXY_EDITION)|| - ($gi->databaseType == GEOIP_NETSPEED_EDITION)){ - $gi->databaseSegments = GEOIP_COUNTRY_BEGIN; - } - fseek($gi->filehandle,$filepos,SEEK_SET); - } - return $gi; -} -} - -if (!function_exists('geoip_open')){ -function geoip_open($filename, $flags) { - $gi = new GeoIP; - $gi->flags = $flags; - if ($gi->flags & GEOIP_SHARED_MEMORY) { - $gi->shmid = @shmop_open (GEOIP_SHM_KEY, "a", 0, 0); - } else { - $gi->filehandle = fopen($filename,"rb") or die( "Can not open $filename\n" ); - if ($gi->flags & GEOIP_MEMORY_CACHE) { - $s_array = fstat($gi->filehandle); - $gi->memory_buffer = fread($gi->filehandle, $s_array['size']); - } - } - - $gi = _setup_segments($gi); - return $gi; -} -} - -if (!function_exists('geoip_close')){ -function geoip_close($gi) { - if ($gi->flags & GEOIP_SHARED_MEMORY) { - return true; - } - - return fclose($gi->filehandle); -} -} - -if (!function_exists('geoip_country_id_by_name_v6')){ -function geoip_country_id_by_name_v6($gi, $name) { - $rec = dns_get_record($name, DNS_AAAA); - if ( !$rec ) { - return false; - } - $addr = $rec[0]["ipv6"]; - if (!$addr || $addr == $name) { - return false; - } - return geoip_country_id_by_addr_v6($gi, $addr); -} -} - -if (!function_exists('geoip_country_id_by_name')){ -function geoip_country_id_by_name($gi, $name) { - $addr = gethostbyname($name); - if (!$addr || $addr == $name) { - return false; - } - return geoip_country_id_by_addr($gi, $addr); -} -} - -if (!function_exists('geoip_country_code_by_name_v6')){ -function geoip_country_code_by_name_v6($gi, $name) { - $country_id = geoip_country_id_by_name_v6($gi,$name); - if ($country_id !== false) { - return $gi->GEOIP_COUNTRY_CODES[$country_id]; - } - return false; -} -} - -if (!function_exists('geoip_country_code_by_name')){ -function geoip_country_code_by_name($gi, $name) { - $country_id = geoip_country_id_by_name($gi,$name); - if ($country_id !== false) { - return $gi->GEOIP_COUNTRY_CODES[$country_id]; - } - return false; -} -} - -if (!function_exists('geoip_country_name_by_name_v6')){ -function geoip_country_name_by_name_v6($gi, $name) { - $country_id = geoip_country_id_by_name_v6($gi,$name); - if ($country_id !== false) { - return $gi->GEOIP_COUNTRY_NAMES[$country_id]; - } - return false; -} -} - -if (!function_exists('geoip_country_name_by_name')){ -function geoip_country_name_by_name($gi, $name) { - $country_id = geoip_country_id_by_name($gi,$name); - if ($country_id !== false) { - return $gi->GEOIP_COUNTRY_NAMES[$country_id]; - } - return false; -} -} - -if (!function_exists('geoip_country_id_by_addr_v6')){ -function geoip_country_id_by_addr_v6($gi, $addr) { - $ipnum = inet_pton($addr); - return _geoip_seek_country_v6($gi, $ipnum) - GEOIP_COUNTRY_BEGIN; -} -} - -if (!function_exists('geoip_country_id_by_addr')){ -function geoip_country_id_by_addr($gi, $addr) { - $ipnum = ip2long($addr); - return _geoip_seek_country($gi, $ipnum) - GEOIP_COUNTRY_BEGIN; -} -} - -if (!function_exists('geoip_country_code_by_addr_v6')){ -function geoip_country_code_by_addr_v6($gi, $addr) { - $country_id = geoip_country_id_by_addr_v6($gi,$addr); - if ($country_id !== false) { - return $gi->GEOIP_COUNTRY_CODES[$country_id]; - } - return false; -} -} - -if (!function_exists('geoip_country_code_by_addr')){ -function geoip_country_code_by_addr($gi, $addr) { - if ($gi->databaseType == GEOIP_CITY_EDITION_REV1) { - $record = geoip_record_by_addr($gi,$addr); - if ( $record !== false ) { - return $record->country_code; - } - } else { - $country_id = geoip_country_id_by_addr($gi,$addr); - if ($country_id !== false) { - return $gi->GEOIP_COUNTRY_CODES[$country_id]; - } - } - return false; -} -} - -if (!function_exists('geoip_country_name_by_addr_v6')){ -function geoip_country_name_by_addr_v6($gi, $addr) { - $country_id = geoip_country_id_by_addr_v6($gi,$addr); - if ($country_id !== false) { - return $gi->GEOIP_COUNTRY_NAMES[$country_id]; - } - return false; -} -} - -if (!function_exists('geoip_country_name_by_addr')){ -function geoip_country_name_by_addr($gi, $addr) { - if ($gi->databaseType == GEOIP_CITY_EDITION_REV1) { - $record = geoip_record_by_addr($gi,$addr); - return $record->country_name; - } else { - $country_id = geoip_country_id_by_addr($gi,$addr); - if ($country_id !== false) { - return $gi->GEOIP_COUNTRY_NAMES[$country_id]; - } - } - return false; -} -} - -if (!function_exists('_geoip_seek_country_v6')){ -function _geoip_seek_country_v6($gi, $ipnum) { - - # arrays from unpack start with offset 1 - # yet another php mystery. array_merge work around - # this broken behaviour - $v6vec = array_merge(unpack( "C16", $ipnum)); - - $offset = 0; - for ($depth = 127; $depth >= 0; --$depth) { - if ($gi->flags & GEOIP_MEMORY_CACHE) { - // workaround php's broken substr, strpos, etc handling with - // mbstring.func_overload and mbstring.internal_encoding - $enc = mb_internal_encoding(); - mb_internal_encoding('ISO-8859-1'); - - $buf = substr($gi->memory_buffer, - 2 * $gi->record_length * $offset, - 2 * $gi->record_length); - - mb_internal_encoding($enc); - } elseif ($gi->flags & GEOIP_SHARED_MEMORY) { - $buf = @shmop_read ($gi->shmid, - 2 * $gi->record_length * $offset, - 2 * $gi->record_length ); - } else { - fseek($gi->filehandle, 2 * $gi->record_length * $offset, SEEK_SET) == 0 - or die("fseek failed"); - $buf = fread($gi->filehandle, 2 * $gi->record_length); - } - $x = array(0,0); - for ($i = 0; $i < 2; ++$i) { - for ($j = 0; $j < $gi->record_length; ++$j) { - $x[$i] += ord($buf[$gi->record_length * $i + $j]) << ($j * 8); - } - } - - $bnum = 127 - $depth; - $idx = $bnum >> 3; - $b_mask = 1 << ( $bnum & 7 ^ 7 ); - if (($v6vec[$idx] & $b_mask) > 0) { - if ($x[1] >= $gi->databaseSegments) { - return $x[1]; - } - $offset = $x[1]; - } else { - if ($x[0] >= $gi->databaseSegments) { - return $x[0]; - } - $offset = $x[0]; - } - } - trigger_error("error traversing database - perhaps it is corrupt?", E_USER_ERROR); - return false; -} -} - -if (!function_exists('_geoip_seek_country')){ -function _geoip_seek_country($gi, $ipnum) { - $offset = 0; - for ($depth = 31; $depth >= 0; --$depth) { - if ($gi->flags & GEOIP_MEMORY_CACHE) { - // workaround php's broken substr, strpos, etc handling with - // mbstring.func_overload and mbstring.internal_encoding - $enc = mb_internal_encoding(); - mb_internal_encoding('ISO-8859-1'); - - $buf = substr($gi->memory_buffer, - 2 * $gi->record_length * $offset, - 2 * $gi->record_length); - - mb_internal_encoding($enc); - } elseif ($gi->flags & GEOIP_SHARED_MEMORY) { - $buf = @shmop_read ($gi->shmid, - 2 * $gi->record_length * $offset, - 2 * $gi->record_length ); - } else { - fseek($gi->filehandle, 2 * $gi->record_length * $offset, SEEK_SET) == 0 - or die("fseek failed"); - $buf = fread($gi->filehandle, 2 * $gi->record_length); - } - $x = array(0,0); - for ($i = 0; $i < 2; ++$i) { - for ($j = 0; $j < $gi->record_length; ++$j) { - $x[$i] += ord($buf[$gi->record_length * $i + $j]) << ($j * 8); - } - } - if ($ipnum & (1 << $depth)) { - if ($x[1] >= $gi->databaseSegments) { - return $x[1]; - } - $offset = $x[1]; - } else { - if ($x[0] >= $gi->databaseSegments) { - return $x[0]; - } - $offset = $x[0]; - } - } - trigger_error("error traversing database - perhaps it is corrupt?", E_USER_ERROR); - return false; -} -} - -if (!function_exists('_common_get_org')){ -function _common_get_org($gi, $seek_org){ - $record_pointer = $seek_org + (2 * $gi->record_length - 1) * $gi->databaseSegments; - if ($gi->flags & GEOIP_SHARED_MEMORY) { - $org_buf = @shmop_read ($gi->shmid, $record_pointer, MAX_ORG_RECORD_LENGTH); - } else { - fseek($gi->filehandle, $record_pointer, SEEK_SET); - $org_buf = fread($gi->filehandle,MAX_ORG_RECORD_LENGTH); - } - // workaround php's broken substr, strpos, etc handling with - // mbstring.func_overload and mbstring.internal_encoding - $enc = mb_internal_encoding(); - mb_internal_encoding('ISO-8859-1'); - $org_buf = substr($org_buf, 0, strpos($org_buf, "\0")); - mb_internal_encoding($enc); - return $org_buf; -} -} - -if (!function_exists('_get_org_v6')){ -function _get_org_v6($gi,$ipnum){ - $seek_org = _geoip_seek_country_v6($gi,$ipnum); - if ($seek_org == $gi->databaseSegments) { - return NULL; - } - return _common_get_org($gi, $seek_org); -} -} - -if (!function_exists('_get_org')){ -function _get_org($gi,$ipnum){ - $seek_org = _geoip_seek_country($gi,$ipnum); - if ($seek_org == $gi->databaseSegments) { - return NULL; - } - return _common_get_org($gi, $seek_org); -} -} - - - -if (!function_exists('geoip_name_by_addr_v6 ')){ -function geoip_name_by_addr_v6 ($gi,$addr) { - if ($addr == NULL) { - return 0; - } - $ipnum = inet_pton($addr); - return _get_org_v6($gi, $ipnum); -} -} - -if (!function_exists('geoip_name_by_addr ')){ -function geoip_name_by_addr ($gi,$addr) { - if ($addr == NULL) { - return 0; - } - $ipnum = ip2long($addr); - return _get_org($gi, $ipnum); -} -} - -if (!function_exists('geoip_org_by_addr ')){ -function geoip_org_by_addr ($gi,$addr) { - return geoip_name_by_addr($gi, $addr); -} -} - -if (!function_exists('_get_region')){ -function _get_region($gi,$ipnum){ - if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){ - $seek_region = _geoip_seek_country($gi,$ipnum) - GEOIP_STATE_BEGIN_REV0; - if ($seek_region >= 1000){ - $country_code = "US"; - $region = chr(($seek_region - 1000)/26 + 65) . chr(($seek_region - 1000)%26 + 65); - } else { - $country_code = $gi->GEOIP_COUNTRY_CODES[$seek_region]; - $region = ""; - } - return array ($country_code,$region); - } else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1) { - $seek_region = _geoip_seek_country($gi,$ipnum) - GEOIP_STATE_BEGIN_REV1; - //print $seek_region; - if ($seek_region < US_OFFSET){ - $country_code = ""; - $region = ""; - } else if ($seek_region < CANADA_OFFSET) { - $country_code = "US"; - $region = chr(($seek_region - US_OFFSET)/26 + 65) . chr(($seek_region - US_OFFSET)%26 + 65); - } else if ($seek_region < WORLD_OFFSET) { - $country_code = "CA"; - $region = chr(($seek_region - CANADA_OFFSET)/26 + 65) . chr(($seek_region - CANADA_OFFSET)%26 + 65); - } else { - $country_code = $gi->GEOIP_COUNTRY_CODES[($seek_region - WORLD_OFFSET) / FIPS_RANGE]; - $region = ""; - } - return array ($country_code,$region); - } -} -} - -if (!function_exists('geoip_region_by_addr ')){ -function geoip_region_by_addr ($gi,$addr) { - if ($addr == NULL) { - return 0; - } - $ipnum = ip2long($addr); - return _get_region($gi, $ipnum); -} -} - -if (!function_exists('getdnsattributes ')){ -function getdnsattributes ($l,$ip){ - $r = new Net_DNS_Resolver(); - $r->nameservers = array("ws1.maxmind.com"); - $p = $r->search($l."." . $ip .".s.maxmind.com","TXT","IN"); - $str = is_object($p->answer[0])?$p->answer[0]->string():''; - $str = substr( $str, 1, -1 ); - return $str; -} -} - -?> diff --git a/tools/geoip/geoip2/geoip2/CHANGELOG.md b/tools/geoip/geoip2/geoip2/CHANGELOG.md new file mode 100644 index 000000000..7f01bd2c2 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/CHANGELOG.md @@ -0,0 +1,352 @@ +CHANGELOG +========= + +3.1.0 (2024-11-15) +------------------ + +* This library no longer uses implicitly nullable parameter types. This + will fix deprecation warning in PHP 8.4. Reported by Steven Lewis. + GitHub #230. +* The PHPDoc type hints have been improved for use with PHPStan. + +3.0.0 (2023-12-04) +------------------ + +* IMPORTANT: PHP 8.1 or greater is now required. +* BREAKING: Read-only properties are now used for the model and record + classes rather than magic methods. This significantly improves performance. +* BREAKING: The `raw` property on model classess and the `record` property on + record classes have been removed. +* BREAKING: On `GeoIp2\Record\Traits`, the deprecated `isAnonymousProxy` and + `isSatelliteProvider` properties have been removed. +* BREAKING: The `jsonSerialize` output has changed. +* `GeoIp2\WebService\Client` methods now throw an `InvalidArgumentException` + if an invalid IP address is passed to them. Previously, they would make + a request to the web service and throw a + `GeoIp2\Exception\InvalidRequestException`. +* The `isAnycast` property was added to `GeoIp2\Record\Traits`. This returns + `true` if the IP address belongs to an [anycast + network](https://en.wikipedia.org/wiki/Anycast). This is available for the + GeoIP2 Country, City Plus, and Insights web services and the GeoIP2 Country, + City, and Enterprise databases. + +2.13.0 (2022-08-05) +------------------- + +* The model class names are no longer constructed by concatenating strings. + This change was made to improve support for tools like PHP-Scoper. + Reported by Andrew Mead. GitHub #194. +* Box 4.0.1 is now used to generate the `geoip2.phar` file. + +2.12.2 (2021-11-30) +------------------- + +* The `geoip2.phar` now works when included from another directory. + Reported by Eduardo Ruiz. GitHub #179. + +2.12.1 (2021-11-23) +------------------- + +* The `geoip2.phar` included in 2.12.0 would only work in CLI applications. + This was due to a change in Box 3.x. The Phar should now work in all + applications. This release only affects users of the Phar file. + +2.12.0 (2021-11-18) +------------------- + +* Support for mobile country code (MCC) and mobile network codes (MNC) was + added for the GeoIP2 ISP and Enterprise databases as well as the GeoIP2 + City and Insights web services. `$mobileCountryCode` and + `$mobileNetworkCode` properties were added to `GeoIp2\Model\Isp` + for the GeoIP2 ISP database and `GeoIp2\Record\Traits` for the Enterprise + database and the GeoIP2 City and Insights web services. We expect this data + to be available by late January, 2022. +* `geoip2.phar` is now generated with Box 3.x. + +2.11.0 (2020-10-01) +------------------- + +* IMPORTANT: PHP 7.2 or greater is now required. +* Added the `isResidentialProxy` property to `GeoIp2\Model\AnonymousIP` and + `GeoIp2\Record\Traits`. +* Additional type hints have been added. + +2.10.0 (2019-12-12) +------------------- + +* PHP 5.6 or greater is now required. +* The `network` property was added to `GeoIp2\Record\Traits`, + `GeoIp2\Model\AnonymousIp`, `GeoIp2\Model\Asn`, + `GeoIp2\Model\ConnectionType`, `Geoip2\Model\Domain`, + and `GeoIp2\Model\Isp`. This is a string in CIDR format representing the + largest network where all of the properties besides `ipAddress` have the + same value. +* Updated documentation of anonymizer properties - `isAnonymousVpn` + and `isHostingProvider` - to be more descriptive. +* The `userCount` property was added to `GeoIp2\Record\Traits`. This is an + integer which indicates the estimated number of users sharing the + IP/network during the past 24 hours. This output is available from GeoIP2 + Precision Insights. +* The `staticIpScore` property was added to `GeoIp2\Record\Traits`. This is + a float which indicates how static or dynamic an IP address is. This + output is available from GeoIP2 Precision Insights. + +2.9.0 (2018-04-10) +------------------ + +* Refer to account IDs using the terminology "account" rather than "user". + +2.8.0 (2018-01-18) +------------------ + +* The `isInEuropeanUnion` property was added to `GeoIp2\Record\Country` + and `GeoIp2\Record\RepresentedCountry`. This property is `true` if the + country is a member state of the European Union. + +2.7.0 (2017-10-27) +------------------ + +* The following new anonymizer properties were added to `GeoIp2\Record\Traits` + for use with GeoIP2 Precision Insights: `isAnonymous`, `isAnonymousVpn`, + `isHostingProvider`, `isPublicProxy`, and `isTorExitNode`. + +2.6.0 (2017-07-10) +----------------- + +* Code clean-up and tidying. +* Set minimum required PHP version to 5.4 in `composer.json`. Previously, + 5.3 would work but was not tested. Now 5.4 is hard minimum version. + +2.5.0 (2017-05-08) +------------------ + +* Support for PHP 5.3 was dropped. +* Added support for GeoLite2 ASN database. + +2.4.5 (2017-01-31) +------------------ + +* Additional error checking on the data returned from `MaxMind\Db\Reader` + was added to help detect corrupt databases. GitHub #83. + +2.4.4 (2016-10-11) +------------------ + +* `isset()` on `mostSpecificSubdivision` attribute now returns the + correct value. Reported by Juan Francisco Giordana. GitHub #81. + +2.4.3 (2016-10-11) +------------------ + +* `isset()` on `name` attribute now returns the correct value. Reported by + Juan Francisco Giordana. GitHub #79. + +2.4.2 (2016-08-17) +------------------ + +* Updated documentation to clarify what the accuracy radius refers to. +* Upgraded `maxmind/web-service-common` to 0.3.0. This version uses + `composer/ca-bundle` rather than our own CA bundle. GitHub #75. +* Improved PHP documentation generation. + +2.4.1 (2016-06-10) +------------------ + +* Corrected type annotations in documentation. GitHub #66. +* Updated documentation to reflect that the accuracy radius is now included + in City. +* Upgraded web service client, which supports setting a proxy. GitHub #59. + +2.4.0 (2016-04-15) +------------------ + +* Added support for the GeoIP2 Enterprise database. + +2.3.3 (2015-09-24) +------------------ + +* Corrected case on `JsonSerializable` interface. Reported by Axel Etcheverry. + GitHub #56. + +2.3.2 (2015-09-23) +------------------ + +* `JsonSerializable` compatibility interface was moved to `GeoIp2\Compat` + rather than the global namespace to prevent autoloading issues. Reported by + Tomas Buteler. GitHub #54. +* Missing documentation for the `$postal` property was added to the + `GeoIp2\Model\City` class. Fix by Roy Sindre Norangshol. GitHub #51. +* In the Phar distribution, source files for this module no longer have their + documentation stripped, allowing IDE introspection to work properly. + Reported by Dominic Black. GitHub #52. + +2.3.1 (2015-06-30) +------------------ + +* Updated `maxmind/web-service-common` to version with fixes for PHP 5.3 and + 5.4. + +2.3.0 (2015-06-29) +------------------ + +* Support for demographics fields `averageIncome` and `populationDensity` in + the `Location` record, returned by the Insights endpoint. +* The `isAnonymousProxy` and `isSatelliteProvider` properties on + `GeoIP2\Record\Traits` have been deprecated. Please use our [GeoIP2 + Anonymous IP database](https://www.maxmind.com/en/geoip2-anonymous-ip-database) + to determine whether an IP address is used by an anonymizing service. + +2.2.0-beta1 (2015-06-09) +------------------------ + +* Typo fix in documentation. + +2.2.0-alpha2 (2015-06-01) +------------------------- + +* `maxmind-ws/web-service-common` was renamed to `maxmind/web-service-common`. + +2.2.0-alpha1 (2015-05-22) +------------------------- + +* The library no longer uses Guzzle and instead uses curl directly. +* Support for `timeout` and `connectTimout` were added to the `$options` array + passed to the `GeoIp2\WebService\Client` constructor. Pull request by Will + Bradley. GitHub #36. + +2.1.1 (2014-12-03) +------------------ + +* The 2.1.0 Phar builds included a shebang line, causing issues when loading + it as a library. This has been corrected. GitHub #33. + +2.1.0 (2014-10-29) +------------------ + +* Update ApiGen dependency to version that isn't broken on case sensitive + file systems. +* Added support for the GeoIP2 Anonymous IP database. The + `GeoIP2\Database\Reader` class now has an `anonymousIp` method which returns + a `GeoIP2\Model\AnonymousIp` object. +* Boolean attributes like those in the `GeoIP2\Record\Traits` class now return + `false` instead of `null` when they were not true. + +2.0.0 (2014-09-22) +------------------ + +* First production release. + +0.9.0 (2014-09-15) +------------------ + +* IMPORTANT: The deprecated `omni()` and `cityIspOrg()` methods have been + removed from `GeoIp2\WebService\Client`. + +0.8.1 (2014-09-12) +------------------ + +* The check added to the `GeoIP2\Database\Reader` lookup methods in 0.8.0 did + not work with the GeoIP2 City Database Subset by Continent with World + Countries. This has been fixed. Fixes GitHub issue #23. + +0.8.0 (2014-09-10) +------------------ + +* The `GeoIp2\Database\Reader` lookup methods (e.g., `city()`, `isp()`) now + throw a `BadMethodCallException` if they are used with a database that + does not match the method. In particular, doing a `city()` lookup on a + GeoIP2 Country database will result in an exception, and vice versa. +* A `metadata()` method has been added to the `GeoIP2\Database\Reader` class. + This returns a `MaxMind\Db\Reader\Metadata` class with information about the + database. +* The name attribute was missing from the RepresentedCountry class. + +0.7.0 (2014-07-22) +------------------ + +* The web service client API has been updated for the v2.1 release of the web + service. In particular, the `cityIspOrg` and `omni` methods on + `GeoIp2\WebService\Client` should be considered deprecated. The `city` + method now provides all of the data formerly provided by `cityIspOrg`, and + the `omni` method has been replaced by the `insights` method. +* Support was added for GeoIP2 Connection Type, Domain and ISP databases. + + +0.6.3 (2014-05-12) +------------------ + +* With the previous Phar builds, some users received `phar error: invalid url + or non-existent phar` errors. The correct alias is now used for the Phar, + and this should no longer be an issue. + +0.6.2 (2014-05-08) +------------------ + +* The Phar build was broken with Guzzle 3.9.0+. This has been fixed. + +0.6.1 (2014-05-01) +------------------ + +* This API now officially supports HHVM. +* The `maxmind-db/reader` dependency was updated to a version that does not + require BC Math. +* The Composer compatibility autoload rules are now targeted more narrowly. +* A `box.json` file is included to build a Phar package. + +0.6.0 (2014-02-19) +------------------ + +* This API is now licensed under the Apache License, Version 2.0. +* Model and record classes now implement `JsonSerializable`. +* `isset` now works with model and record classes. + +0.5.0 (2013-10-21) +------------------ + +* Renamed $languages constructor parameters to $locales for both the Client + and Reader classes. +* Documentation and code clean-up (Ben Morel). +* Added the interface `GeoIp2\ProviderInterface`, which is implemented by both + `\GeoIp2\Database\Reader` and `\GeoIp2\WebService\Client`. + +0.4.0 (2013-07-16) +------------------ + +* This is the first release with the GeoIP2 database reader. Please see the + `README.md` file and the `\GeoIp2\Database\Reader` class. +* The general exception classes were replaced with specific exception classes + representing particular types of errors, such as an authentication error. + +0.3.0 (2013-07-12) +------------------ + +* In namespaces and class names, "GeoIP2" was renamed to "GeoIp2" to improve + consistency. + +0.2.1 (2013-06-10) +------------------ + +* First official beta release. +* Documentation updates and corrections. + +0.2.0 (2013-05-29) +------------------ + +* `GenericException` was renamed to `GeoIP2Exception`. +* We now support more languages. The new languages are de, es, fr, and pt-BR. +* The REST API now returns a record with data about your account. There is + a new `GeoIP\Records\MaxMind` class for this data. +* The `continentCode` attribute on `Continent` was renamed to `code`. +* Documentation updates. + +0.1.1 (2013-05-14) +------------------ + +* Updated Guzzle version requirement. +* Fixed Composer example in README.md. + + +0.1.0 (2013-05-13) +------------------ + +* Initial release. diff --git a/tools/geoip/geoip2/geoip2/LICENSE b/tools/geoip/geoip2/geoip2/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/tools/geoip/geoip2/geoip2/README.md b/tools/geoip/geoip2/geoip2/README.md new file mode 100644 index 000000000..9121b7252 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/README.md @@ -0,0 +1,448 @@ +# GeoIP2 PHP API # + +## Description ## + +This package provides an API for the GeoIP2 and GeoLite2 +[web services](https://dev.maxmind.com/geoip/docs/web-services?lang=en) and +[databases](https://dev.maxmind.com/geoip/docs/databases?lang=en). + +## Install via Composer ## + +We recommend installing this package with [Composer](https://getcomposer.org/). + +### Download Composer ### + +To download Composer, run in the root directory of your project: + +```bash +curl -sS https://getcomposer.org/installer | php +``` + +You should now have the file `composer.phar` in your project directory. + +### Install Dependencies ### + +Run in your project root: + +```sh +php composer.phar require geoip2/geoip2:~2.0 +``` + +You should now have the files `composer.json` and `composer.lock` as well as +the directory `vendor` in your project directory. If you use a version control +system, `composer.json` should be added to it. + +### Require Autoloader ### + +After installing the dependencies, you need to require the Composer autoloader +from your code: + +```php +require 'vendor/autoload.php'; +``` + +## Install via Phar ## + +Although we strongly recommend using Composer, we also provide a +[phar archive](https://php.net/manual/en/book.phar.php) containing most of the +dependencies for GeoIP2. Our latest phar archive is available on +[our releases page](https://github.com/maxmind/GeoIP2-php/releases). + +### Install Dependencies ### + +In order to use the phar archive, you must have the PHP +[Phar extension](https://php.net/manual/en/book.phar.php) installed and +enabled. + +If you will be making web service requests, you must have the PHP +[cURL extension](https://php.net/manual/en/book.curl.php) +installed to use this archive. For Debian based distributions, this can +typically be found in the the `php-curl` package. For other operating +systems, please consult the relevant documentation. After installing the +extension you may need to restart your web server. + +If you are missing this extension, you will see errors like the following: + +``` +PHP Fatal error: Uncaught Error: Call to undefined function MaxMind\WebService\curl_version() +``` + +### Require Package ### + +To use the archive, just require it from your script: + +```php +require 'geoip2.phar'; +``` + +## Optional C Extension ## + +The [MaxMind DB API](https://github.com/maxmind/MaxMind-DB-Reader-php) +includes an optional C extension that you may install to dramatically increase +the performance of lookups in GeoIP2 or GeoLite2 databases. To install, please +follow the instructions included with that API. + +The extension has no effect on web-service lookups. + +## IP Geolocation Usage ## + +IP geolocation is inherently imprecise. Locations are often near the center of +the population. Any location provided by a GeoIP2 database or web service +should not be used to identify a particular address or household. + +## Database Reader ## + +### Usage ### + +To use this API, you must create a new `\GeoIp2\Database\Reader` object with +the path to the database file as the first argument to the constructor. You +may then call the method corresponding to the database you are using. + +If the lookup succeeds, the method call will return a model class for the +record in the database. This model in turn contains multiple container +classes for the different parts of the data such as the city in which the +IP address is located. + +If the record is not found, a `\GeoIp2\Exception\AddressNotFoundException` +is thrown. If the database is invalid or corrupt, a +`\MaxMind\Db\InvalidDatabaseException` will be thrown. + +See the [API documentation](https://maxmind.github.io/GeoIP2-php/) for more +details. + +### City Example ### + +```php +city('128.101.101.101'); + +print($record->country->isoCode . "\n"); // 'US' +print($record->country->name . "\n"); // 'United States' +print($record->country->names['zh-CN'] . "\n"); // '美国' + +print($record->mostSpecificSubdivision->name . "\n"); // 'Minnesota' +print($record->mostSpecificSubdivision->isoCode . "\n"); // 'MN' + +print($record->city->name . "\n"); // 'Minneapolis' + +print($record->postal->code . "\n"); // '55455' + +print($record->location->latitude . "\n"); // 44.9733 +print($record->location->longitude . "\n"); // -93.2323 + +print($record->traits->network . "\n"); // '128.101.101.101/32' + +``` + +### Anonymous IP Example ### + +```php +anonymousIp('128.101.101.101'); + +if ($record->isAnonymous) { print "anon\n"; } +print($record->ipAddress . "\n"); // '128.101.101.101' +print($record->network . "\n"); // '128.101.101.101/32' + +``` + +### Connection-Type Example ### + +```php +connectionType('128.101.101.101'); + +print($record->connectionType . "\n"); // 'Corporate' +print($record->ipAddress . "\n"); // '128.101.101.101' +print($record->network . "\n"); // '128.101.101.101/32' + +``` + +### Domain Example ### + +```php +domain('128.101.101.101'); + +print($record->domain . "\n"); // 'umn.edu' +print($record->ipAddress . "\n"); // '128.101.101.101' +print($record->network . "\n"); // '128.101.101.101/32' + +``` + +### Enterprise Example ### + +```php +enterprise method to do a lookup in the Enterprise database +$record = $enterpriseDbReader->enterprise('128.101.101.101'); + +print($record->country->confidence . "\n"); // 99 +print($record->country->isoCode . "\n"); // 'US' +print($record->country->name . "\n"); // 'United States' +print($record->country->names['zh-CN'] . "\n"); // '美国' + +print($record->mostSpecificSubdivision->confidence . "\n"); // 77 +print($record->mostSpecificSubdivision->name . "\n"); // 'Minnesota' +print($record->mostSpecificSubdivision->isoCode . "\n"); // 'MN' + +print($record->city->confidence . "\n"); // 60 +print($record->city->name . "\n"); // 'Minneapolis' + +print($record->postal->code . "\n"); // '55455' + +print($record->location->accuracyRadius . "\n"); // 50 +print($record->location->latitude . "\n"); // 44.9733 +print($record->location->longitude . "\n"); // -93.2323 + +print($record->traits->network . "\n"); // '128.101.101.101/32' + +``` + +### ISP Example ### + +```php +isp('128.101.101.101'); + +print($record->autonomousSystemNumber . "\n"); // 217 +print($record->autonomousSystemOrganization . "\n"); // 'University of Minnesota' +print($record->isp . "\n"); // 'University of Minnesota' +print($record->organization . "\n"); // 'University of Minnesota' + +print($record->ipAddress . "\n"); // '128.101.101.101' +print($record->network . "\n"); // '128.101.101.101/32' + +``` + +## Database Updates ## + +You can keep your databases up to date with our +[GeoIP Update program](https://github.com/maxmind/geoipupdate/releases). +[Learn more about GeoIP Update on our developer +portal.](https://dev.maxmind.com/geoip/updating-databases?lang=en) + +## Web Service Client ## + +### Usage ### + +To use this API, you must create a new `\GeoIp2\WebService\Client` +object with your `$accountId` and `$licenseKey`: + +```php +$client = new Client(42, 'abcdef123456'); +``` + +You may also call the constructor with additional arguments. The third argument +specifies the language preferences when using the `->name` method on the model +classes that this client creates. The fourth argument is additional options +such as `host` and `timeout`. + +For instance, to call the GeoLite2 web service instead of the GeoIP2 web +service: + +```php +$client = new Client(42, 'abcdef123456', ['en'], ['host' => 'geolite.info']); +``` + +To call the Sandbox GeoIP2 web service instead of the production GeoIP2 web +service: + +```php +$client = new Client(42, 'abcdef123456', ['en'], ['host' => 'sandbox.maxmind.com']); +``` + +After creating the client, you may now call the method corresponding to a +specific endpoint with the IP address to look up, e.g.: + +```php +$record = $client->city('128.101.101.101'); +``` + +If the request succeeds, the method call will return a model class for the +endpoint you called. This model in turn contains multiple record classes, each +of which represents part of the data returned by the web service. + +If there is an error, a structured exception is thrown. + +See the [API documentation](https://maxmind.github.io/GeoIP2-php/) for more +details. + +### Example ### + +```php +city('128.101.101.101'); + +print($record->country->isoCode . "\n"); // 'US' +print($record->country->name . "\n"); // 'United States' +print($record->country->names['zh-CN'] . "\n"); // '美国' + +print($record->mostSpecificSubdivision->name . "\n"); // 'Minnesota' +print($record->mostSpecificSubdivision->isoCode . "\n"); // 'MN' + +print($record->city->name . "\n"); // 'Minneapolis' + +print($record->postal->code . "\n"); // '55455' + +print($record->location->latitude . "\n"); // 44.9733 +print($record->location->longitude . "\n"); // -93.2323 + +print($record->traits->network . "\n"); // '128.101.101.101/32' + +``` + +## Values to use for Database or Array Keys ## + +**We strongly discourage you from using a value from any `names` property as +a key in a database or array.** + +These names may change between releases. Instead we recommend using one of the +following: + +* `GeoIp2\Record\City` - `$city->geonameId` +* `GeoIp2\Record\Continent` - `$continent->code` or `$continent->geonameId` +* `GeoIp2\Record\Country` and `GeoIp2\Record\RepresentedCountry` - + `$country->isoCode` or `$country->geonameId` +* `GeoIp2\Record\Subdivision` - `$subdivision->isoCode` or `$subdivision->geonameId` + +### What data is returned? ### + +While many of the end points return the same basic records, the attributes +which can be populated vary between end points. In addition, while an end +point may offer a particular piece of data, MaxMind does not always have every +piece of data for any given IP address. + +Because of these factors, it is possible for any end point to return a record +where some or all of the attributes are unpopulated. + +See the +[GeoIP2 web service docs](https://dev.maxmind.com/geoip/docs/web-services?lang=en) +for details on what data each end point may return. + +The only piece of data which is always returned is the `ipAddress` +attribute in the `GeoIp2\Record\Traits` record. + +## Integration with GeoNames ## + +[GeoNames](https://www.geonames.org/) offers web services and downloadable +databases with data on geographical features around the world, including +populated places. They offer both free and paid premium data. Each +feature is unique identified by a `geonameId`, which is an integer. + +Many of the records returned by the GeoIP2 web services and databases +include a `geonameId` property. This is the ID of a geographical feature +(city, region, country, etc.) in the GeoNames database. + +Some of the data that MaxMind provides is also sourced from GeoNames. We +source things like place names, ISO codes, and other similar data from +the GeoNames premium data set. + +## Reporting data problems ## + +If the problem you find is that an IP address is incorrectly mapped, +please +[submit your correction to MaxMind](https://www.maxmind.com/en/correction). + +If you find some other sort of mistake, like an incorrect spelling, +please check the [GeoNames site](https://www.geonames.org/) first. Once +you've searched for a place and found it on the GeoNames map view, there +are a number of links you can use to correct data ("move", "edit", +"alternate names", etc.). Once the correction is part of the GeoNames +data set, it will be automatically incorporated into future MaxMind +releases. + +If you are a paying MaxMind customer and you're not sure where to submit +a correction, please +[contact MaxMind support](https://www.maxmind.com/en/support) for help. + +## Other Support ## + +Please report all issues with this code using the +[GitHub issue tracker](https://github.com/maxmind/GeoIP2-php/issues). + +If you are having an issue with a MaxMind service that is not specific +to the client API, please see +[our support page](https://www.maxmind.com/en/support). + +## Requirements ## + +This library requires PHP 8.1 or greater. + +This library also relies on the [MaxMind DB Reader](https://github.com/maxmind/MaxMind-DB-Reader-php). + +## Contributing ## + +Patches and pull requests are encouraged. All code should follow the PSR-2 +style guidelines. Please include unit tests whenever possible. You may obtain +the test data for the maxmind-db folder by running `git submodule update +--init --recursive` or adding `--recursive` to your initial clone, or from +https://github.com/maxmind/MaxMind-DB + +## Versioning ## + +The GeoIP2 PHP API uses [Semantic Versioning](https://semver.org/). + +## Copyright and License ## + +This software is Copyright (c) 2013-2024 by MaxMind, Inc. + +This is free software, licensed under the Apache License, Version 2.0. diff --git a/tools/geoip/geoip2/geoip2/composer.json b/tools/geoip/geoip2/geoip2/composer.json new file mode 100644 index 000000000..6d1f07bf6 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/composer.json @@ -0,0 +1,32 @@ +{ + "name": "geoip2/geoip2", + "description": "MaxMind GeoIP2 PHP API", + "keywords": ["geoip", "geoip2", "geolocation", "ip", "maxmind"], + "homepage": "https://github.com/maxmind/GeoIP2-php", + "type": "library", + "license": "Apache-2.0", + "authors": [ + { + "name": "Gregory J. Oschwald", + "email": "goschwald@maxmind.com", + "homepage": "https://www.maxmind.com/" + } + ], + "require": { + "maxmind-db/reader": "^1.12.0", + "maxmind/web-service-common": "~0.10", + "php": ">=8.1", + "ext-json": "*" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "phpunit/phpunit": "^10.0", + "squizlabs/php_codesniffer": "3.*", + "phpstan/phpstan": "*" + }, + "autoload": { + "psr-4": { + "GeoIp2\\": "src" + } + } +} diff --git a/tools/geoip/geoip2/geoip2/examples/benchmark.php b/tools/geoip/geoip2/geoip2/examples/benchmark.php new file mode 100644 index 000000000..eb657d6fe --- /dev/null +++ b/tools/geoip/geoip2/geoip2/examples/benchmark.php @@ -0,0 +1,27 @@ +city($ip); + } catch (AddressNotFoundException $e) { + } + if ($i % 10000 === 0) { + echo $i . ' ' . $ip . "\n"; + } +} +$endTime = microtime(true); + +$duration = $endTime - $startTime; +echo 'Requests per second: ' . $count / $duration . "\n"; diff --git a/tools/geoip/geoip2/geoip2/src/Database/Reader.php b/tools/geoip/geoip2/geoip2/src/Database/Reader.php new file mode 100644 index 000000000..9e3a128a7 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Database/Reader.php @@ -0,0 +1,271 @@ + + */ + private array $locales; + + /** + * Constructor. + * + * @param string $filename the path to the GeoIP2 database file + * @param array $locales list of locale codes to use in name property + * from most preferred to least preferred + * + * @throws InvalidDatabaseException if the database is corrupt or invalid + */ + public function __construct( + string $filename, + array $locales = ['en'] + ) { + $this->dbReader = new DbReader($filename); + $this->dbType = $this->dbReader->metadata()->databaseType; + $this->locales = $locales; + } + + /** + * This method returns a GeoIP2 City model. + * + * @param string $ipAddress an IPv4 or IPv6 address as a string + * + * @throws AddressNotFoundException if the address is not in the database + * @throws InvalidDatabaseException if the database is corrupt or invalid + */ + public function city(string $ipAddress): City + { + return $this->modelFor(City::class, 'City', $ipAddress); + } + + /** + * This method returns a GeoIP2 Country model. + * + * @param string $ipAddress an IPv4 or IPv6 address as a string + * + * @throws AddressNotFoundException if the address is not in the database + * @throws InvalidDatabaseException if the database is corrupt or invalid + */ + public function country(string $ipAddress): Country + { + return $this->modelFor(Country::class, 'Country', $ipAddress); + } + + /** + * This method returns a GeoIP2 Anonymous IP model. + * + * @param string $ipAddress an IPv4 or IPv6 address as a string + * + * @throws AddressNotFoundException if the address is not in the database + * @throws InvalidDatabaseException if the database is corrupt or invalid + */ + public function anonymousIp(string $ipAddress): AnonymousIp + { + return $this->flatModelFor( + AnonymousIp::class, + 'GeoIP2-Anonymous-IP', + $ipAddress + ); + } + + /** + * This method returns a GeoLite2 ASN model. + * + * @param string $ipAddress an IPv4 or IPv6 address as a string + * + * @throws AddressNotFoundException if the address is not in the database + * @throws InvalidDatabaseException if the database is corrupt or invalid + */ + public function asn(string $ipAddress): Asn + { + return $this->flatModelFor( + Asn::class, + 'GeoLite2-ASN', + $ipAddress + ); + } + + /** + * This method returns a GeoIP2 Connection Type model. + * + * @param string $ipAddress an IPv4 or IPv6 address as a string + * + * @throws AddressNotFoundException if the address is not in the database + * @throws InvalidDatabaseException if the database is corrupt or invalid + */ + public function connectionType(string $ipAddress): ConnectionType + { + return $this->flatModelFor( + ConnectionType::class, + 'GeoIP2-Connection-Type', + $ipAddress + ); + } + + /** + * This method returns a GeoIP2 Domain model. + * + * @param string $ipAddress an IPv4 or IPv6 address as a string + * + * @throws AddressNotFoundException if the address is not in the database + * @throws InvalidDatabaseException if the database is corrupt or invalid + */ + public function domain(string $ipAddress): Domain + { + return $this->flatModelFor( + Domain::class, + 'GeoIP2-Domain', + $ipAddress + ); + } + + /** + * This method returns a GeoIP2 Enterprise model. + * + * @param string $ipAddress an IPv4 or IPv6 address as a string + * + * @throws AddressNotFoundException if the address is not in the database + * @throws InvalidDatabaseException if the database is corrupt or invalid + */ + public function enterprise(string $ipAddress): Enterprise + { + return $this->modelFor(Enterprise::class, 'Enterprise', $ipAddress); + } + + /** + * This method returns a GeoIP2 ISP model. + * + * @param string $ipAddress an IPv4 or IPv6 address as a string + * + * @throws AddressNotFoundException if the address is not in the database + * @throws InvalidDatabaseException if the database is corrupt or invalid + */ + public function isp(string $ipAddress): Isp + { + return $this->flatModelFor( + Isp::class, + 'GeoIP2-ISP', + $ipAddress + ); + } + + private function modelFor(string $class, string $type, string $ipAddress): object + { + [$record, $prefixLen] = $this->getRecord($class, $type, $ipAddress); + + $record['traits']['ip_address'] = $ipAddress; + $record['traits']['prefix_len'] = $prefixLen; + + return new $class($record, $this->locales); + } + + private function flatModelFor(string $class, string $type, string $ipAddress): object + { + [$record, $prefixLen] = $this->getRecord($class, $type, $ipAddress); + + $record['ip_address'] = $ipAddress; + $record['prefix_len'] = $prefixLen; + + return new $class($record); + } + + /** + * @return array{0:array, 1:int} + */ + private function getRecord(string $class, string $type, string $ipAddress): array + { + if (!str_contains($this->dbType, $type)) { + $method = lcfirst((new \ReflectionClass($class))->getShortName()); + + throw new \BadMethodCallException( + "The $method method cannot be used to open a {$this->dbType} database" + ); + } + [$record, $prefixLen] = $this->dbReader->getWithPrefixLen($ipAddress); + if ($record === null) { + throw new AddressNotFoundException( + "The address $ipAddress is not in the database." + ); + } + if (!\is_array($record)) { + // This can happen on corrupt databases. Generally, + // MaxMind\Db\Reader will throw a + // MaxMind\Db\Reader\InvalidDatabaseException, but occasionally + // the lookup may result in a record that looks valid but is not + // an array. This mostly happens when the user is ignoring all + // exceptions and the more frequent InvalidDatabaseException + // exceptions go unnoticed. + throw new InvalidDatabaseException( + "Expected an array when looking up $ipAddress but received: " + . \gettype($record) + ); + } + + return [$record, $prefixLen]; + } + + /** + * @throws \InvalidArgumentException if arguments are passed to the method + * @throws \BadMethodCallException if the database has been closed + * + * @return Metadata object for the database + */ + public function metadata(): Metadata + { + return $this->dbReader->metadata(); + } + + /** + * Closes the GeoIP2 database and returns the resources to the system. + */ + public function close(): void + { + $this->dbReader->close(); + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Exception/AddressNotFoundException.php b/tools/geoip/geoip2/geoip2/src/Exception/AddressNotFoundException.php new file mode 100644 index 000000000..acc251866 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Exception/AddressNotFoundException.php @@ -0,0 +1,11 @@ +uri = $uri; + parent::__construct($message, $httpStatus, $previous); + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Exception/InvalidRequestException.php b/tools/geoip/geoip2/geoip2/src/Exception/InvalidRequestException.php new file mode 100644 index 000000000..e1a1fbfe6 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Exception/InvalidRequestException.php @@ -0,0 +1,28 @@ +error = $error; + parent::__construct($message, $httpStatus, $uri, $previous); + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Exception/OutOfQueriesException.php b/tools/geoip/geoip2/geoip2/src/Exception/OutOfQueriesException.php new file mode 100644 index 000000000..8e866f7c4 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Exception/OutOfQueriesException.php @@ -0,0 +1,11 @@ + $raw + */ + public function __construct(array $raw) + { + $this->isAnonymous = $raw['is_anonymous'] ?? false; + $this->isAnonymousVpn = $raw['is_anonymous_vpn'] ?? false; + $this->isHostingProvider = $raw['is_hosting_provider'] ?? false; + $this->isPublicProxy = $raw['is_public_proxy'] ?? false; + $this->isResidentialProxy = $raw['is_residential_proxy'] ?? false; + $this->isTorExitNode = $raw['is_tor_exit_node'] ?? false; + $ipAddress = $raw['ip_address']; + $this->ipAddress = $ipAddress; + $this->network = Util::cidr($ipAddress, $raw['prefix_len']); + } + + /** + * @return array|null + */ + public function jsonSerialize(): ?array + { + $js = []; + $js['is_anonymous'] = $this->isAnonymous; + $js['is_anonymous_vpn'] = $this->isAnonymousVpn; + $js['is_hosting_provider'] = $this->isHostingProvider; + $js['is_public_proxy'] = $this->isPublicProxy; + $js['is_residential_proxy'] = $this->isResidentialProxy; + $js['is_tor_exit_node'] = $this->isTorExitNode; + $js['ip_address'] = $this->ipAddress; + $js['network'] = $this->network; + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Model/Asn.php b/tools/geoip/geoip2/geoip2/src/Model/Asn.php new file mode 100644 index 000000000..5feae2f0f --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Model/Asn.php @@ -0,0 +1,73 @@ + $raw + */ + public function __construct(array $raw) + { + $this->autonomousSystemNumber = $raw['autonomous_system_number'] ?? null; + $this->autonomousSystemOrganization = + $raw['autonomous_system_organization'] ?? null; + $ipAddress = $raw['ip_address']; + $this->ipAddress = $ipAddress; + $this->network = Util::cidr($ipAddress, $raw['prefix_len']); + } + + /** + * @return array|null + */ + public function jsonSerialize(): ?array + { + $js = []; + + if ($this->autonomousSystemNumber !== null) { + $js['autonomous_system_number'] = $this->autonomousSystemNumber; + } + if ($this->autonomousSystemOrganization !== null) { + $js['autonomous_system_organization'] = $this->autonomousSystemOrganization; + } + $js['ip_address'] = $this->ipAddress; + $js['network'] = $this->network; + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Model/City.php b/tools/geoip/geoip2/geoip2/src/Model/City.php new file mode 100644 index 000000000..bf2323ed4 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Model/City.php @@ -0,0 +1,129 @@ + An array of \GeoIp2\Record\Subdivision + * objects representing the country + * subdivisions for the requested IP + * address. The number and type of + * subdivisions varies by country, + * but a subdivision is typically a + * state, province, county, etc. + * Subdivisions are ordered from most + * general (largest) to most specific + * (smallest). If the response did + * not contain any subdivisions, this + * method returns an empty array. + */ + public readonly array $subdivisions; + + /** + * @ignore + * + * @param array $raw + * @param list $locales + */ + public function __construct(array $raw, array $locales = ['en']) + { + parent::__construct($raw, $locales); + + $this->city = new CityRecord($raw['city'] ?? [], $locales); + $this->location = new Location($raw['location'] ?? []); + $this->postal = new Postal($raw['postal'] ?? []); + + if (!isset($raw['subdivisions'])) { + $this->subdivisions = []; + $this->mostSpecificSubdivision = + new Subdivision([], $locales); + + return; + } + + $subdivisions = []; + foreach ($raw['subdivisions'] as $sub) { + $subdivisions[] = + new Subdivision($sub, $locales) + ; + } + + // Not using end as we don't want to modify internal pointer. + $this->mostSpecificSubdivision = + $subdivisions[\count($subdivisions) - 1]; + $this->subdivisions = $subdivisions; + } + + /** + * @return array|null + */ + public function jsonSerialize(): ?array + { + $js = parent::jsonSerialize(); + + $city = $this->city->jsonSerialize(); + if (!empty($city)) { + $js['city'] = $city; + } + + $location = $this->location->jsonSerialize(); + if (!empty($location)) { + $js['location'] = $location; + } + + $postal = + $this->postal->jsonSerialize(); + if (!empty($postal)) { + $js['postal'] = $postal; + } + + $subdivisions = []; + foreach ($this->subdivisions as $sub) { + $subdivisions[] = $sub->jsonSerialize(); + } + if (!empty($subdivisions)) { + $js['subdivisions'] = $subdivisions; + } + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Model/ConnectionType.php b/tools/geoip/geoip2/geoip2/src/Model/ConnectionType.php new file mode 100644 index 000000000..47e24cc42 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Model/ConnectionType.php @@ -0,0 +1,61 @@ + $raw + */ + public function __construct(array $raw) + { + $this->connectionType = $raw['connection_type'] ?? null; + $ipAddress = $raw['ip_address']; + $this->ipAddress = $ipAddress; + $this->network = Util::cidr($ipAddress, $raw['prefix_len']); + } + + /** + * @return array|null + */ + public function jsonSerialize(): ?array + { + $js = []; + if ($this->connectionType !== null) { + $js['connection_type'] = $this->connectionType; + } + $js['ip_address'] = $this->ipAddress; + $js['network'] = $this->network; + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Model/Country.php b/tools/geoip/geoip2/geoip2/src/Model/Country.php new file mode 100644 index 000000000..c41af4a2b --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Model/Country.php @@ -0,0 +1,120 @@ + $raw + * @param list $locales + */ + public function __construct(array $raw, array $locales = ['en']) + { + $this->continent = new Continent( + $raw['continent'] ?? [], + $locales + ); + $this->country = new CountryRecord( + $raw['country'] ?? [], + $locales + ); + $this->maxmind = new MaxMind($raw['maxmind'] ?? []); + $this->registeredCountry = new CountryRecord( + $raw['registered_country'] ?? [], + $locales + ); + $this->representedCountry = new RepresentedCountry( + $raw['represented_country'] ?? [], + $locales + ); + $this->traits = new Traits($raw['traits'] ?? []); + } + + /** + * @return array|null + */ + public function jsonSerialize(): ?array + { + $js = []; + $continent = $this->continent->jsonSerialize(); + if (!empty($continent)) { + $js['continent'] = $continent; + } + $country = $this->country->jsonSerialize(); + if (!empty($country)) { + $js['country'] = $country; + } + $maxmind = $this->maxmind->jsonSerialize(); + if (!empty($maxmind)) { + $js['maxmind'] = $maxmind; + } + $registeredCountry = $this->registeredCountry->jsonSerialize(); + if (!empty($registeredCountry)) { + $js['registered_country'] = $registeredCountry; + } + $representedCountry = $this->representedCountry->jsonSerialize(); + if (!empty($representedCountry)) { + $js['represented_country'] = $representedCountry; + } + $traits = $this->traits->jsonSerialize(); + if (!empty($traits)) { + $js['traits'] = $traits; + } + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Model/Domain.php b/tools/geoip/geoip2/geoip2/src/Model/Domain.php new file mode 100644 index 000000000..ed401c8c2 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Model/Domain.php @@ -0,0 +1,61 @@ + $raw + */ + public function __construct(array $raw) + { + $this->domain = $raw['domain'] ?? null; + $ipAddress = $raw['ip_address']; + $this->ipAddress = $ipAddress; + $this->network = Util::cidr($ipAddress, $raw['prefix_len']); + } + + /** + * @return array|null + */ + public function jsonSerialize(): ?array + { + $js = []; + if ($this->domain !== null) { + $js['domain'] = $this->domain; + } + $js['ip_address'] = $this->ipAddress; + $js['network'] = $this->network; + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Model/Enterprise.php b/tools/geoip/geoip2/geoip2/src/Model/Enterprise.php new file mode 100644 index 000000000..57f10d845 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Model/Enterprise.php @@ -0,0 +1,14 @@ + $raw + */ + public function __construct(array $raw) + { + $this->autonomousSystemNumber = $raw['autonomous_system_number'] ?? null; + $this->autonomousSystemOrganization = + $raw['autonomous_system_organization'] ?? null; + $this->isp = $raw['isp'] ?? null; + $this->mobileCountryCode = $raw['mobile_country_code'] ?? null; + $this->mobileNetworkCode = $raw['mobile_network_code'] ?? null; + $this->organization = $raw['organization'] ?? null; + + $ipAddress = $raw['ip_address']; + $this->ipAddress = $ipAddress; + $this->network = Util::cidr($ipAddress, $raw['prefix_len']); + } + + /** + * @return array|null + */ + public function jsonSerialize(): ?array + { + $js = []; + if ($this->autonomousSystemNumber !== null) { + $js['autonomous_system_number'] = $this->autonomousSystemNumber; + } + if ($this->autonomousSystemOrganization !== null) { + $js['autonomous_system_organization'] = $this->autonomousSystemOrganization; + } + if ($this->isp !== null) { + $js['isp'] = $this->isp; + } + if ($this->mobileCountryCode !== null) { + $js['mobile_country_code'] = $this->mobileCountryCode; + } + if ($this->mobileNetworkCode !== null) { + $js['mobile_network_code'] = $this->mobileNetworkCode; + } + if ($this->organization !== null) { + $js['organization'] = $this->organization; + } + $js['ip_address'] = $this->ipAddress; + $js['network'] = $this->network; + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/ProviderInterface.php b/tools/geoip/geoip2/geoip2/src/ProviderInterface.php new file mode 100644 index 000000000..8f40bee59 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/ProviderInterface.php @@ -0,0 +1,22 @@ + An array map where the keys are locale codes + * and the values are names. This attribute is returned by all location + * services and databases. + */ + public readonly array $names; + + /** + * @ignore + * + * @param array $record + * @param list $locales + */ + public function __construct(array $record, array $locales = ['en']) + { + $this->names = $record['names'] ?? []; + + foreach ($locales as $locale) { + if (isset($this->names[$locale])) { + $this->name = $this->names[$locale]; + + return; + } + } + $this->name = null; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + $js = []; + if (!empty($this->names)) { + $js['names'] = $this->names; + } + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Record/AbstractPlaceRecord.php b/tools/geoip/geoip2/geoip2/src/Record/AbstractPlaceRecord.php new file mode 100644 index 000000000..71b68abd6 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Record/AbstractPlaceRecord.php @@ -0,0 +1,52 @@ + $record + * @param list $locales + */ + public function __construct(array $record, array $locales = ['en']) + { + parent::__construct($record, $locales); + + $this->confidence = $record['confidence'] ?? null; + $this->geonameId = $record['geoname_id'] ?? null; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + $js = parent::jsonSerialize(); + if ($this->confidence !== null) { + $js['confidence'] = $this->confidence; + } + + if ($this->geonameId !== null) { + $js['geoname_id'] = $this->geonameId; + } + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Record/City.php b/tools/geoip/geoip2/geoip2/src/Record/City.php new file mode 100644 index 000000000..9ebb9a28b --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Record/City.php @@ -0,0 +1,14 @@ + $record + * @param list $locales + */ + public function __construct(array $record, array $locales = ['en']) + { + parent::__construct($record, $locales); + + $this->code = $record['code'] ?? null; + $this->geonameId = $record['geoname_id'] ?? null; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + $js = parent::jsonSerialize(); + if ($this->code !== null) { + $js['code'] = $this->code; + } + if ($this->geonameId !== null) { + $js['geoname_id'] = $this->geonameId; + } + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Record/Country.php b/tools/geoip/geoip2/geoip2/src/Record/Country.php new file mode 100644 index 000000000..60fd1f905 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Record/Country.php @@ -0,0 +1,57 @@ + $record + * @param list $locales + */ + public function __construct(array $record, array $locales = ['en']) + { + parent::__construct($record, $locales); + + $this->isInEuropeanUnion = $record['is_in_european_union'] ?? false; + $this->isoCode = $record['iso_code'] ?? null; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + $js = parent::jsonSerialize(); + if ($this->isInEuropeanUnion !== false) { + $js['is_in_european_union'] = $this->isInEuropeanUnion; + } + if ($this->isoCode !== null) { + $js['iso_code'] = $this->isoCode; + } + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Record/Location.php b/tools/geoip/geoip2/geoip2/src/Record/Location.php new file mode 100644 index 000000000..6172ac83c --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Record/Location.php @@ -0,0 +1,113 @@ + $record + */ + public function __construct(array $record) + { + $this->averageIncome = $record['average_income'] ?? null; + $this->accuracyRadius = $record['accuracy_radius'] ?? null; + $this->latitude = $record['latitude'] ?? null; + $this->longitude = $record['longitude'] ?? null; + $this->metroCode = $record['metro_code'] ?? null; + $this->populationDensity = $record['population_density'] ?? null; + $this->timeZone = $record['time_zone'] ?? null; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + $js = []; + if ($this->averageIncome !== null) { + $js['average_income'] = $this->averageIncome; + } + if ($this->accuracyRadius !== null) { + $js['accuracy_radius'] = $this->accuracyRadius; + } + if ($this->latitude !== null) { + $js['latitude'] = $this->latitude; + } + if ($this->longitude !== null) { + $js['longitude'] = $this->longitude; + } + if ($this->metroCode !== null) { + $js['metro_code'] = $this->metroCode; + } + if ($this->populationDensity !== null) { + $js['population_density'] = $this->populationDensity; + } + if ($this->timeZone !== null) { + $js['time_zone'] = $this->timeZone; + } + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Record/MaxMind.php b/tools/geoip/geoip2/geoip2/src/Record/MaxMind.php new file mode 100644 index 000000000..b2c33d9c8 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Record/MaxMind.php @@ -0,0 +1,42 @@ + $record + */ + public function __construct(array $record) + { + $this->queriesRemaining = $record['queries_remaining'] ?? null; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + $js = []; + if ($this->queriesRemaining !== null) { + $js['queries_remaining'] = $this->queriesRemaining; + } + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Record/Postal.php b/tools/geoip/geoip2/geoip2/src/Record/Postal.php new file mode 100644 index 000000000..cea2f2ae5 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Record/Postal.php @@ -0,0 +1,57 @@ + $record + */ + public function __construct(array $record) + { + $this->code = $record['code'] ?? null; + $this->confidence = $record['confidence'] ?? null; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + $js = []; + if ($this->code !== null) { + $js['code'] = $this->code; + } + if ($this->confidence !== null) { + $js['confidence'] = $this->confidence; + } + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Record/RepresentedCountry.php b/tools/geoip/geoip2/geoip2/src/Record/RepresentedCountry.php new file mode 100644 index 000000000..67f24b08f --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Record/RepresentedCountry.php @@ -0,0 +1,48 @@ +military + * but this could expand to include other types in the future. + */ + public readonly ?string $type; + + /** + * @ignore + * + * @param array $record + * @param list $locales + */ + public function __construct(array $record, array $locales = ['en']) + { + parent::__construct($record, $locales); + + $this->type = $record['type'] ?? null; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + $js = parent::jsonSerialize(); + if ($this->type !== null) { + $js['type'] = $this->type; + } + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Record/Subdivision.php b/tools/geoip/geoip2/geoip2/src/Record/Subdivision.php new file mode 100644 index 000000000..3719a6c35 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Record/Subdivision.php @@ -0,0 +1,48 @@ + $record + * @param list $locales + */ + public function __construct(array $record, array $locales = ['en']) + { + parent::__construct($record, $locales); + + $this->isoCode = $record['iso_code'] ?? null; + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + $js = parent::jsonSerialize(); + if ($this->isoCode !== null) { + $js['iso_code'] = $this->isoCode; + } + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Record/Traits.php b/tools/geoip/geoip2/geoip2/src/Record/Traits.php new file mode 100644 index 000000000..d75a8f711 --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Record/Traits.php @@ -0,0 +1,306 @@ +The user type associated with the IP + * address. This can be one of the following values:

+ *
    + *
  • business + *
  • cafe + *
  • cellular + *
  • college + *
  • consumer_privacy_network + *
  • content_delivery_network + *
  • dialup + *
  • government + *
  • hosting + *
  • library + *
  • military + *
  • residential + *
  • router + *
  • school + *
  • search_engine_spider + *
  • traveler + *
+ *

+ * This attribute is only available from the Insights web service and the + * GeoIP2 Enterprise database. + *

+ */ + public readonly ?string $userType; + + /** + * @ignore + * + * @param array $record + */ + public function __construct(array $record) + { + $this->autonomousSystemNumber = $record['autonomous_system_number'] ?? null; + $this->autonomousSystemOrganization = $record['autonomous_system_organization'] ?? null; + $this->connectionType = $record['connection_type'] ?? null; + $this->domain = $record['domain'] ?? null; + $this->ipAddress = $record['ip_address'] ?? null; + $this->isAnonymous = $record['is_anonymous'] ?? false; + $this->isAnonymousVpn = $record['is_anonymous_vpn'] ?? false; + $this->isAnycast = $record['is_anycast'] ?? false; + $this->isHostingProvider = $record['is_hosting_provider'] ?? false; + $this->isLegitimateProxy = $record['is_legitimate_proxy'] ?? false; + $this->isp = $record['isp'] ?? null; + $this->isPublicProxy = $record['is_public_proxy'] ?? false; + $this->isResidentialProxy = $record['is_residential_proxy'] ?? false; + $this->isTorExitNode = $record['is_tor_exit_node'] ?? false; + $this->mobileCountryCode = $record['mobile_country_code'] ?? null; + $this->mobileNetworkCode = $record['mobile_network_code'] ?? null; + $this->organization = $record['organization'] ?? null; + $this->staticIpScore = $record['static_ip_score'] ?? null; + $this->userCount = $record['user_count'] ?? null; + $this->userType = $record['user_type'] ?? null; + + if (isset($record['network'])) { + $this->network = $record['network']; + } else { + $this->network = isset($record['prefix_len']) ? Util::cidr($this->ipAddress, $record['prefix_len']) : null; + } + } + + /** + * @return array + */ + public function jsonSerialize(): array + { + $js = []; + if ($this->autonomousSystemNumber !== null) { + $js['autonomous_system_number'] = $this->autonomousSystemNumber; + } + if ($this->autonomousSystemOrganization !== null) { + $js['autonomous_system_organization'] = $this->autonomousSystemOrganization; + } + if ($this->connectionType !== null) { + $js['connection_type'] = $this->connectionType; + } + if ($this->domain !== null) { + $js['domain'] = $this->domain; + } + if ($this->ipAddress !== null) { + $js['ip_address'] = $this->ipAddress; + } + if ($this->isAnonymous !== false) { + $js['is_anonymous'] = $this->isAnonymous; + } + if ($this->isAnonymousVpn !== false) { + $js['is_anonymous_vpn'] = $this->isAnonymousVpn; + } + if ($this->isAnycast !== false) { + $js['is_anycast'] = $this->isAnycast; + } + if ($this->isHostingProvider !== false) { + $js['is_hosting_provider'] = $this->isHostingProvider; + } + if ($this->isLegitimateProxy !== false) { + $js['is_legitimate_proxy'] = $this->isLegitimateProxy; + } + if ($this->isPublicProxy !== false) { + $js['is_public_proxy'] = $this->isPublicProxy; + } + if ($this->isResidentialProxy !== false) { + $js['is_residential_proxy'] = $this->isResidentialProxy; + } + if ($this->isTorExitNode !== false) { + $js['is_tor_exit_node'] = $this->isTorExitNode; + } + if ($this->isp !== null) { + $js['isp'] = $this->isp; + } + if ($this->mobileCountryCode !== null) { + $js['mobile_country_code'] = $this->mobileCountryCode; + } + if ($this->mobileNetworkCode !== null) { + $js['mobile_network_code'] = $this->mobileNetworkCode; + } + if ($this->network !== null) { + $js['network'] = $this->network; + } + if ($this->organization !== null) { + $js['organization'] = $this->organization; + } + if ($this->staticIpScore !== null) { + $js['static_ip_score'] = $this->staticIpScore; + } + if ($this->userCount !== null) { + $js['user_count'] = $this->userCount; + } + if ($this->userType !== null) { + $js['user_type'] = $this->userType; + } + + return $js; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/Util.php b/tools/geoip/geoip2/geoip2/src/Util.php new file mode 100644 index 000000000..79e813aaf --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/Util.php @@ -0,0 +1,37 @@ + 0; $i++) { + $b = $ipBytes[$i]; + if ($curPrefix < 8) { + $shiftN = 8 - $curPrefix; + $b = \chr(0xFF & (\ord($b) >> $shiftN) << $shiftN); + } + $networkBytes[$i] = $b; + $curPrefix -= 8; + } + + $network = inet_ntop($networkBytes); + + return "$network/$prefixLen"; + } +} diff --git a/tools/geoip/geoip2/geoip2/src/WebService/Client.php b/tools/geoip/geoip2/geoip2/src/WebService/Client.php new file mode 100644 index 000000000..fb3966eff --- /dev/null +++ b/tools/geoip/geoip2/geoip2/src/WebService/Client.php @@ -0,0 +1,263 @@ + + */ + private array $locales; + private WsClient $client; + private static string $basePath = '/geoip/v2.1'; + + public const VERSION = 'v3.1.0'; + + /** + * Constructor. + * + * @param int $accountId your MaxMind account ID + * @param string $licenseKey your MaxMind license key + * @param list $locales list of locale codes to use in name property + * from most preferred to least preferred + * @param array $options array of options. Valid options include: + * * `host` - The host to use when querying the web + * service. To query the GeoLite2 web service + * instead of the GeoIP2 web service, set the + * host to `geolite.info`. To query the Sandbox + * GeoIP2 web service instead of the production + * GeoIP2 web service, set the host to + * `sandbox.maxmind.com`. The sandbox allows you to + * experiment with the API without affecting your + * production data. + * * `timeout` - Timeout in seconds. + * * `connectTimeout` - Initial connection timeout in seconds. + * * `proxy` - The HTTP proxy to use. May include a schema, port, + * username, and password, e.g., + * `http://username:password@127.0.0.1:10`. + */ + public function __construct( + int $accountId, + string $licenseKey, + array $locales = ['en'], + array $options = [] + ) { + $this->locales = $locales; + + // This is for backwards compatibility. Do not remove except for a + // major version bump. + // @phpstan-ignore-next-line + if (\is_string($options)) { + $options = ['host' => $options]; + } + + if (!isset($options['host'])) { + $options['host'] = 'geoip.maxmind.com'; + } + + $options['userAgent'] = $this->userAgent(); + + $this->client = new WsClient($accountId, $licenseKey, $options); + } + + private function userAgent(): string + { + return 'GeoIP2-API/' . self::VERSION; + } + + /** + * This method calls the City Plus service. + * + * @param string $ipAddress IPv4 or IPv6 address as a string. If no + * address is provided, the address that the web service is called + * from will be used. + * + * @throws AddressNotFoundException if the address you provided is not in our database (e.g., + * a private address). + * @throws AuthenticationException if there is a problem with the account ID or license key + * that you provided + * @throws OutOfQueriesException if your account is out of queries + * @throws InvalidRequestException if your request was received by the web service but is + * invalid for some other reason. This may indicate an issue + * with this API. Please report the error to MaxMind. + * @throws HttpException if an unexpected HTTP error code or message was returned. + * This could indicate a problem with the connection between + * your server and the web service or that the web service + * returned an invalid document or 500 error code + * @throws GeoIp2Exception This serves as the parent + * class to the above exceptions. It will be thrown directly + * if a 200 status code is returned but the body is invalid. + * @throws \InvalidArgumentException if something other than a single IP address or "me" is + * passed to the method + */ + public function city(string $ipAddress = 'me'): City + { + // @phpstan-ignore-next-line + return $this->responseFor('city', City::class, $ipAddress); + } + + /** + * This method calls the Country service. + * + * @param string $ipAddress IPv4 or IPv6 address as a string. If no + * address is provided, the address that the web service is called + * from will be used. + * + * @throws AddressNotFoundException if the address you provided is not in our database (e.g., + * a private address). + * @throws AuthenticationException if there is a problem with the account ID or license key that you provided + * @throws OutOfQueriesException if your account is out of queries + * @throws InvalidRequestException if your request was received by the web service but is + * invalid for some other reason. This may indicate an + * issue with this API. Please report the error to MaxMind. + * @throws HttpException if an unexpected HTTP error + * code or message was returned. This could indicate a problem + * with the connection between your server and the web service + * or that the web service returned an invalid document or 500 + * error code. + * @throws GeoIp2Exception This serves as the parent class to the above exceptions. It + * will be thrown directly if a 200 status code is returned but + * the body is invalid. + * @throws \InvalidArgumentException if something other than a single IP address or "me" is + * passed to the method + */ + public function country(string $ipAddress = 'me'): Country + { + return $this->responseFor('country', Country::class, $ipAddress); + } + + /** + * This method calls the Insights service. Insights is only supported by + * the GeoIP2 web service. The GeoLite2 web service does not support it. + * + * @param string $ipAddress IPv4 or IPv6 address as a string. If no + * address is provided, the address that the web service is called + * from will be used. + * + * @throws AddressNotFoundException if the address you provided is not in our database (e.g., + * a private address). + * @throws AuthenticationException if there is a problem with the account ID or license key + * that you provided + * @throws OutOfQueriesException if your account is out of queries + * @throws InvalidRequestException if your request was received by the web service but is + * invalid for some other reason. This may indicate an + * issue with this API. Please report the error to MaxMind. + * @throws HttpException if an unexpected HTTP error code or message was returned. + * This could indicate a problem with the connection between + * your server and the web service or that the web service + * returned an invalid document or 500 error code + * @throws GeoIp2Exception This serves as the parent + * class to the above exceptions. It will be thrown directly + * if a 200 status code is returned but the body is invalid. + * @throws \InvalidArgumentException if something other than a single IP address or "me" is + * passed to the method + */ + public function insights(string $ipAddress = 'me'): Insights + { + // @phpstan-ignore-next-line + return $this->responseFor('insights', Insights::class, $ipAddress); + } + + private function responseFor(string $endpoint, string $class, string $ipAddress): Country + { + if ($ipAddress !== 'me' && !filter_var($ipAddress, \FILTER_VALIDATE_IP)) { + throw new \InvalidArgumentException( + "The value \"$ipAddress\" is not a valid IP address." + ); + } + $path = implode('/', [self::$basePath, $endpoint, $ipAddress]); + + try { + $service = (new \ReflectionClass($class))->getShortName(); + $body = $this->client->get('GeoIP2 ' . $service, $path); + } catch (IpAddressNotFoundException $ex) { + throw new AddressNotFoundException( + $ex->getMessage(), + $ex->getStatusCode(), + $ex + ); + } catch (\MaxMind\Exception\AuthenticationException $ex) { + throw new AuthenticationException( + $ex->getMessage(), + $ex->getStatusCode(), + $ex + ); + } catch (InsufficientFundsException $ex) { + throw new OutOfQueriesException( + $ex->getMessage(), + $ex->getStatusCode(), + $ex + ); + } catch (\MaxMind\Exception\InvalidRequestException $ex) { + throw new InvalidRequestException( + $ex->getMessage(), + $ex->getErrorCode(), + $ex->getStatusCode(), + $ex->getUri(), + $ex + ); + } catch (\MaxMind\Exception\HttpException $ex) { + throw new HttpException( + $ex->getMessage(), + $ex->getStatusCode(), + $ex->getUri(), + $ex + ); + } catch (WebServiceException $ex) { + throw new GeoIp2Exception( + $ex->getMessage(), + $ex->getCode(), + $ex + ); + } + + return new $class($body, $this->locales); + } +} diff --git a/tools/geoip/geoipcity.inc b/tools/geoip/geoipcity.inc deleted file mode 100644 index a93c3d35d..000000000 --- a/tools/geoip/geoipcity.inc +++ /dev/null @@ -1,237 +0,0 @@ -country_code = $value; - } - if ($key == "ci"){ - $record->city = $value; - } - if ($key == "re"){ - $record->region = $value; - } - if ($key == "ac"){ - $record->areacode = $value; - } - if ($key == "dm" || $key == "me" ){ - $record->dmacode = $value; - $record->metrocode = $value; - } - if ($key == "is"){ - $record->isp = $value; - } - if ($key == "or"){ - $record->org = $value; - } - if ($key == "zi"){ - $record->postal_code = $value; - } - if ($key == "la"){ - $record->latitude = $value; - } - if ($key == "lo"){ - $record->longitude = $value; - } - } - $number = $GLOBALS['GEOIP_COUNTRY_CODE_TO_NUMBER'][$record->country_code]; - $record->country_code3 = $GLOBALS['GEOIP_COUNTRY_CODES3'][$number]; - $record->country_name = $GLOBALS['GEOIP_COUNTRY_NAMES'][$number]; - if ($record->region != "") { - if (($record->country_code == "US") || ($record->country_code == "CA")){ - $record->regionname = $GLOBALS['ISO'][$record->country_code][$record->region]; - } else { - $record->regionname = $GLOBALS['FIPS'][$record->country_code][$record->region]; - } - } - return $record; -} - - -function _get_record_v6($gi,$ipnum){ - $seek_country = _geoip_seek_country_v6($gi,$ipnum); - if ($seek_country == $gi->databaseSegments) { - return NULL; - } - return _common_get_record($gi, $seek_country); -} - -function _common_get_record($gi, $seek_country){ - // workaround php's broken substr, strpos, etc handling with - // mbstring.func_overload and mbstring.internal_encoding - $enc = mb_internal_encoding(); - mb_internal_encoding('ISO-8859-1'); - - $record_pointer = $seek_country + (2 * $gi->record_length - 1) * $gi->databaseSegments; - - if ($gi->flags & GEOIP_MEMORY_CACHE) { - $record_buf = substr($gi->memory_buffer,$record_pointer,FULL_RECORD_LENGTH); - } elseif ($gi->flags & GEOIP_SHARED_MEMORY){ - $record_buf = @shmop_read($gi->shmid,$record_pointer,FULL_RECORD_LENGTH); - } else { - fseek($gi->filehandle, $record_pointer, SEEK_SET); - $record_buf = fread($gi->filehandle,FULL_RECORD_LENGTH); - } - $record = new geoiprecord; - $record_buf_pos = 0; - $char = ord(substr($record_buf,$record_buf_pos,1)); - $record->country_code = $gi->GEOIP_COUNTRY_CODES[$char]; - $record->country_code3 = $gi->GEOIP_COUNTRY_CODES3[$char]; - $record->country_name = $gi->GEOIP_COUNTRY_NAMES[$char]; - $record->continent_code = $gi->GEOIP_CONTINENT_CODES[$char]; - $record_buf_pos++; - $str_length = 0; - // Get region - $char = ord(substr($record_buf,$record_buf_pos+$str_length,1)); - while ($char != 0){ - $str_length++; - $char = ord(substr($record_buf,$record_buf_pos+$str_length,1)); - } - if ($str_length > 0){ - $record->region = substr($record_buf,$record_buf_pos,$str_length); - } - $record_buf_pos += $str_length + 1; - $str_length = 0; - // Get city - $char = ord(substr($record_buf,$record_buf_pos+$str_length,1)); - while ($char != 0){ - $str_length++; - $char = ord(substr($record_buf,$record_buf_pos+$str_length,1)); - } - if ($str_length > 0){ - $record->city = substr($record_buf,$record_buf_pos,$str_length); - } - $record_buf_pos += $str_length + 1; - $str_length = 0; - // Get postal code - $char = ord(substr($record_buf,$record_buf_pos+$str_length,1)); - while ($char != 0){ - $str_length++; - $char = ord(substr($record_buf,$record_buf_pos+$str_length,1)); - } - if ($str_length > 0){ - $record->postal_code = substr($record_buf,$record_buf_pos,$str_length); - } - $record_buf_pos += $str_length + 1; - $str_length = 0; - // Get latitude and longitude - $latitude = 0; - $longitude = 0; - for ($j = 0;$j < 3; ++$j){ - $char = ord(substr($record_buf,$record_buf_pos++,1)); - $latitude += ($char << ($j * 8)); - } - $record->latitude = ($latitude/10000) - 180; - for ($j = 0;$j < 3; ++$j){ - $char = ord(substr($record_buf,$record_buf_pos++,1)); - $longitude += ($char << ($j * 8)); - } - $record->longitude = ($longitude/10000) - 180; - if (GEOIP_CITY_EDITION_REV1 == $gi->databaseType){ - $metroarea_combo = 0; - if ($record->country_code == "US"){ - for ($j = 0;$j < 3;++$j){ - $char = ord(substr($record_buf,$record_buf_pos++,1)); - $metroarea_combo += ($char << ($j * 8)); - } - $record->metro_code = $record->dma_code = floor($metroarea_combo/1000); - $record->area_code = $metroarea_combo%1000; - } - } - mb_internal_encoding($enc); - return $record; -} - -function GeoIP_record_by_addr_v6 ($gi,$addr){ - if ($addr == NULL){ - return 0; - } - $ipnum = inet_pton($addr); - return _get_record_v6($gi, $ipnum); -} - -function _get_record($gi,$ipnum){ - $seek_country = _geoip_seek_country($gi,$ipnum); - if ($seek_country == $gi->databaseSegments) { - return NULL; - } - return _common_get_record($gi, $seek_country); -} - -function GeoIP_record_by_addr ($gi,$addr){ - if ($addr == NULL){ - return 0; - } - $ipnum = ip2long($addr); - return _get_record($gi, $ipnum); -} - -?> diff --git a/tools/geoip/geoipregionvars.php b/tools/geoip/geoipregionvars.php deleted file mode 100644 index 18947e7f0..000000000 --- a/tools/geoip/geoipregionvars.php +++ /dev/null @@ -1,4191 +0,0 @@ - array( - "02" => "Canillo", - "03" => "Encamp", - "04" => "La Massana", - "05" => "Ordino", - "06" => "Sant Julia de Loria", - "07" => "Andorra la Vella", - "08" => "Escaldes-Engordany"), -"AE" => array( - "01" => "Abu Dhabi", - "02" => "Ajman", - "03" => "Dubai", - "04" => "Fujairah", - "05" => "Ras Al Khaimah", - "06" => "Sharjah", - "07" => "Umm Al Quwain"), -"AF" => array( - "01" => "Badakhshan", - "02" => "Badghis", - "03" => "Baghlan", - "05" => "Bamian", - "06" => "Farah", - "07" => "Faryab", - "08" => "Ghazni", - "09" => "Ghowr", - "10" => "Helmand", - "11" => "Herat", - "13" => "Kabol", - "14" => "Kapisa", - "17" => "Lowgar", - "18" => "Nangarhar", - "19" => "Nimruz", - "23" => "Kandahar", - "24" => "Kondoz", - "26" => "Takhar", - "27" => "Vardak", - "28" => "Zabol", - "29" => "Paktika", - "30" => "Balkh", - "31" => "Jowzjan", - "32" => "Samangan", - "33" => "Sar-e Pol", - "34" => "Konar", - "35" => "Laghman", - "36" => "Paktia", - "37" => "Khowst", - "38" => "Nurestan", - "39" => "Oruzgan", - "40" => "Parvan", - "41" => "Daykondi", - "42" => "Panjshir"), -"AG" => array( - "01" => "Barbuda", - "03" => "Saint George", - "04" => "Saint John", - "05" => "Saint Mary", - "06" => "Saint Paul", - "07" => "Saint Peter", - "08" => "Saint Philip", - "09" => "Redonda"), -"AL" => array( - "40" => "Berat", - "41" => "Diber", - "42" => "Durres", - "43" => "Elbasan", - "44" => "Fier", - "45" => "Gjirokaster", - "46" => "Korce", - "47" => "Kukes", - "48" => "Lezhe", - "49" => "Shkoder", - "50" => "Tirane", - "51" => "Vlore"), -"AM" => array( - "01" => "Aragatsotn", - "02" => "Ararat", - "03" => "Armavir", - "04" => "Geghark'unik'", - "05" => "Kotayk'", - "06" => "Lorri", - "07" => "Shirak", - "08" => "Syunik'", - "09" => "Tavush", - "10" => "Vayots' Dzor", - "11" => "Yerevan"), -"AO" => array( - "01" => "Benguela", - "02" => "Bie", - "03" => "Cabinda", - "04" => "Cuando Cubango", - "05" => "Cuanza Norte", - "06" => "Cuanza Sul", - "07" => "Cunene", - "08" => "Huambo", - "09" => "Huila", - "12" => "Malanje", - "13" => "Namibe", - "14" => "Moxico", - "15" => "Uige", - "16" => "Zaire", - "17" => "Lunda Norte", - "18" => "Lunda Sul", - "19" => "Bengo", - "20" => "Luanda"), -"AR" => array( - "01" => "Buenos Aires", - "02" => "Catamarca", - "03" => "Chaco", - "04" => "Chubut", - "05" => "Cordoba", - "06" => "Corrientes", - "07" => "Distrito Federal", - "08" => "Entre Rios", - "09" => "Formosa", - "10" => "Jujuy", - "11" => "La Pampa", - "12" => "La Rioja", - "13" => "Mendoza", - "14" => "Misiones", - "15" => "Neuquen", - "16" => "Rio Negro", - "17" => "Salta", - "18" => "San Juan", - "19" => "San Luis", - "20" => "Santa Cruz", - "21" => "Santa Fe", - "22" => "Santiago del Estero", - "23" => "Tierra del Fuego", - "24" => "Tucuman"), -"AT" => array( - "01" => "Burgenland", - "02" => "Karnten", - "03" => "Niederosterreich", - "04" => "Oberosterreich", - "05" => "Salzburg", - "06" => "Steiermark", - "07" => "Tirol", - "08" => "Vorarlberg", - "09" => "Wien"), -"AU" => array( - "01" => "Australian Capital Territory", - "02" => "New South Wales", - "03" => "Northern Territory", - "04" => "Queensland", - "05" => "South Australia", - "06" => "Tasmania", - "07" => "Victoria", - "08" => "Western Australia"), -"AZ" => array( - "01" => "Abseron", - "02" => "Agcabadi", - "03" => "Agdam", - "04" => "Agdas", - "05" => "Agstafa", - "06" => "Agsu", - "07" => "Ali Bayramli", - "08" => "Astara", - "09" => "Baki", - "10" => "Balakan", - "11" => "Barda", - "12" => "Beylaqan", - "13" => "Bilasuvar", - "14" => "Cabrayil", - "15" => "Calilabad", - "16" => "Daskasan", - "17" => "Davaci", - "18" => "Fuzuli", - "19" => "Gadabay", - "20" => "Ganca", - "21" => "Goranboy", - "22" => "Goycay", - "23" => "Haciqabul", - "24" => "Imisli", - "25" => "Ismayilli", - "26" => "Kalbacar", - "27" => "Kurdamir", - "28" => "Lacin", - "29" => "Lankaran", - "30" => "Lankaran", - "31" => "Lerik", - "32" => "Masalli", - "33" => "Mingacevir", - "34" => "Naftalan", - "35" => "Naxcivan", - "36" => "Neftcala", - "37" => "Oguz", - "38" => "Qabala", - "39" => "Qax", - "40" => "Qazax", - "41" => "Qobustan", - "42" => "Quba", - "43" => "Qubadli", - "44" => "Qusar", - "45" => "Saatli", - "46" => "Sabirabad", - "47" => "Saki", - "48" => "Saki", - "49" => "Salyan", - "50" => "Samaxi", - "51" => "Samkir", - "52" => "Samux", - "53" => "Siyazan", - "54" => "Sumqayit", - "55" => "Susa", - "56" => "Susa", - "57" => "Tartar", - "58" => "Tovuz", - "59" => "Ucar", - "60" => "Xacmaz", - "61" => "Xankandi", - "62" => "Xanlar", - "63" => "Xizi", - "64" => "Xocali", - "65" => "Xocavand", - "66" => "Yardimli", - "67" => "Yevlax", - "68" => "Yevlax", - "69" => "Zangilan", - "70" => "Zaqatala", - "71" => "Zardab"), -"BA" => array( - "01" => "Federation of Bosnia and Herzegovina", - "02" => "Republika Srpska"), -"BB" => array( - "01" => "Christ Church", - "02" => "Saint Andrew", - "03" => "Saint George", - "04" => "Saint James", - "05" => "Saint John", - "06" => "Saint Joseph", - "07" => "Saint Lucy", - "08" => "Saint Michael", - "09" => "Saint Peter", - "10" => "Saint Philip", - "11" => "Saint Thomas"), -"BD" => array( - "81" => "Dhaka", - "82" => "Khulna", - "83" => "Rajshahi", - "84" => "Chittagong", - "85" => "Barisal", - "86" => "Sylhet"), -"BE" => array( - "01" => "Antwerpen", - "03" => "Hainaut", - "04" => "Liege", - "05" => "Limburg", - "06" => "Luxembourg", - "07" => "Namur", - "08" => "Oost-Vlaanderen", - "09" => "West-Vlaanderen", - "10" => "Brabant Wallon", - "11" => "Brussels Hoofdstedelijk Gewest", - "12" => "Vlaams-Brabant", - "13" => "Flanders", - "14" => "Wallonia"), -"BF" => array( - "15" => "Bam", - "19" => "Boulkiemde", - "20" => "Ganzourgou", - "21" => "Gnagna", - "28" => "Kouritenga", - "33" => "Oudalan", - "34" => "Passore", - "36" => "Sanguie", - "40" => "Soum", - "42" => "Tapoa", - "44" => "Zoundweogo", - "45" => "Bale", - "46" => "Banwa", - "47" => "Bazega", - "48" => "Bougouriba", - "49" => "Boulgou", - "50" => "Gourma", - "51" => "Houet", - "52" => "Ioba", - "53" => "Kadiogo", - "54" => "Kenedougou", - "55" => "Komoe", - "56" => "Komondjari", - "57" => "Kompienga", - "58" => "Kossi", - "59" => "Koulpelogo", - "60" => "Kourweogo", - "61" => "Leraba", - "62" => "Loroum", - "63" => "Mouhoun", - "64" => "Namentenga", - "65" => "Naouri", - "66" => "Nayala", - "67" => "Noumbiel", - "68" => "Oubritenga", - "69" => "Poni", - "70" => "Sanmatenga", - "71" => "Seno", - "72" => "Sissili", - "73" => "Sourou", - "74" => "Tuy", - "75" => "Yagha", - "76" => "Yatenga", - "77" => "Ziro", - "78" => "Zondoma"), -"BG" => array( - "33" => "Mikhaylovgrad", - "38" => "Blagoevgrad", - "39" => "Burgas", - "40" => "Dobrich", - "41" => "Gabrovo", - "42" => "Grad Sofiya", - "43" => "Khaskovo", - "44" => "Kurdzhali", - "45" => "Kyustendil", - "46" => "Lovech", - "47" => "Montana", - "48" => "Pazardzhik", - "49" => "Pernik", - "50" => "Pleven", - "51" => "Plovdiv", - "52" => "Razgrad", - "53" => "Ruse", - "54" => "Shumen", - "55" => "Silistra", - "56" => "Sliven", - "57" => "Smolyan", - "58" => "Sofiya", - "59" => "Stara Zagora", - "60" => "Turgovishte", - "61" => "Varna", - "62" => "Veliko Turnovo", - "63" => "Vidin", - "64" => "Vratsa", - "65" => "Yambol"), -"BH" => array( - "01" => "Al Hadd", - "02" => "Al Manamah", - "05" => "Jidd Hafs", - "06" => "Sitrah", - "08" => "Al Mintaqah al Gharbiyah", - "09" => "Mintaqat Juzur Hawar", - "10" => "Al Mintaqah ash Shamaliyah", - "11" => "Al Mintaqah al Wusta", - "12" => "Madinat", - "13" => "Ar Rifa", - "14" => "Madinat Hamad", - "15" => "Al Muharraq", - "16" => "Al Asimah", - "17" => "Al Janubiyah", - "18" => "Ash Shamaliyah", - "19" => "Al Wusta"), -"BI" => array( - "02" => "Bujumbura", - "09" => "Bubanza", - "10" => "Bururi", - "11" => "Cankuzo", - "12" => "Cibitoke", - "13" => "Gitega", - "14" => "Karuzi", - "15" => "Kayanza", - "16" => "Kirundo", - "17" => "Makamba", - "18" => "Muyinga", - "19" => "Ngozi", - "20" => "Rutana", - "21" => "Ruyigi", - "22" => "Muramvya", - "23" => "Mwaro"), -"BJ" => array( - "07" => "Alibori", - "08" => "Atakora", - "09" => "Atlanyique", - "10" => "Borgou", - "11" => "Collines", - "12" => "Kouffo", - "13" => "Donga", - "14" => "Littoral", - "15" => "Mono", - "16" => "Oueme", - "17" => "Plateau", - "18" => "Zou"), -"BM" => array( - "01" => "Devonshire", - "02" => "Hamilton", - "03" => "Hamilton", - "04" => "Paget", - "05" => "Pembroke", - "06" => "Saint George", - "07" => "Saint George's", - "08" => "Sandys", - "09" => "Smiths", - "10" => "Southampton", - "11" => "Warwick"), -"BN" => array( - "07" => "Alibori", - "08" => "Belait", - "09" => "Brunei and Muara", - "10" => "Temburong", - "11" => "Collines", - "12" => "Kouffo", - "13" => "Donga", - "14" => "Littoral", - "15" => "Tutong", - "16" => "Oueme", - "17" => "Plateau", - "18" => "Zou"), -"BO" => array( - "01" => "Chuquisaca", - "02" => "Cochabamba", - "03" => "El Beni", - "04" => "La Paz", - "05" => "Oruro", - "06" => "Pando", - "07" => "Potosi", - "08" => "Santa Cruz", - "09" => "Tarija"), -"BR" => array( - "01" => "Acre", - "02" => "Alagoas", - "03" => "Amapa", - "04" => "Amazonas", - "05" => "Bahia", - "06" => "Ceara", - "07" => "Distrito Federal", - "08" => "Espirito Santo", - "11" => "Mato Grosso do Sul", - "13" => "Maranhao", - "14" => "Mato Grosso", - "15" => "Minas Gerais", - "16" => "Para", - "17" => "Paraiba", - "18" => "Parana", - "20" => "Piaui", - "21" => "Rio de Janeiro", - "22" => "Rio Grande do Norte", - "23" => "Rio Grande do Sul", - "24" => "Rondonia", - "25" => "Roraima", - "26" => "Santa Catarina", - "27" => "Sao Paulo", - "28" => "Sergipe", - "29" => "Goias", - "30" => "Pernambuco", - "31" => "Tocantins"), -"BS" => array( - "05" => "Bimini", - "06" => "Cat Island", - "10" => "Exuma", - "13" => "Inagua", - "15" => "Long Island", - "16" => "Mayaguana", - "18" => "Ragged Island", - "22" => "Harbour Island", - "23" => "New Providence", - "24" => "Acklins and Crooked Islands", - "25" => "Freeport", - "26" => "Fresh Creek", - "27" => "Governor's Harbour", - "28" => "Green Turtle Cay", - "29" => "High Rock", - "30" => "Kemps Bay", - "31" => "Marsh Harbour", - "32" => "Nichollstown and Berry Islands", - "33" => "Rock Sound", - "34" => "Sandy Point", - "35" => "San Salvador and Rum Cay"), -"BT" => array( - "05" => "Bumthang", - "06" => "Chhukha", - "07" => "Chirang", - "08" => "Daga", - "09" => "Geylegphug", - "10" => "Ha", - "11" => "Lhuntshi", - "12" => "Mongar", - "13" => "Paro", - "14" => "Pemagatsel", - "15" => "Punakha", - "16" => "Samchi", - "17" => "Samdrup", - "18" => "Shemgang", - "19" => "Tashigang", - "20" => "Thimphu", - "21" => "Tongsa", - "22" => "Wangdi Phodrang"), -"BW" => array( - "01" => "Central", - "03" => "Ghanzi", - "04" => "Kgalagadi", - "05" => "Kgatleng", - "06" => "Kweneng", - "08" => "North-East", - "09" => "South-East", - "10" => "Southern", - "11" => "North-West"), -"BY" => array( - "01" => "Brestskaya Voblasts'", - "02" => "Homyel'skaya Voblasts'", - "03" => "Hrodzyenskaya Voblasts'", - "04" => "Minsk", - "05" => "Minskaya Voblasts'", - "06" => "Mahilyowskaya Voblasts'", - "07" => "Vitsyebskaya Voblasts'"), -"BZ" => array( - "01" => "Belize", - "02" => "Cayo", - "03" => "Corozal", - "04" => "Orange Walk", - "05" => "Stann Creek", - "06" => "Toledo"), -"CA" => array( - "AB" => "Alberta", - "BC" => "British Columbia", - "MB" => "Manitoba", - "NB" => "New Brunswick", - "NL" => "Newfoundland", - "NS" => "Nova Scotia", - "NT" => "Northwest Territories", - "NU" => "Nunavut", - "ON" => "Ontario", - "PE" => "Prince Edward Island", - "QC" => "Quebec", - "SK" => "Saskatchewan", - "YT" => "Yukon Territory"), -"CD" => array( - "01" => "Bandundu", - "02" => "Equateur", - "04" => "Kasai-Oriental", - "05" => "Katanga", - "06" => "Kinshasa", - "08" => "Bas-Congo", - "09" => "Orientale", - "10" => "Maniema", - "11" => "Nord-Kivu", - "12" => "Sud-Kivu"), -"CF" => array( - "01" => "Bamingui-Bangoran", - "02" => "Basse-Kotto", - "03" => "Haute-Kotto", - "04" => "Mambere-Kadei", - "05" => "Haut-Mbomou", - "06" => "Kemo", - "07" => "Lobaye", - "08" => "Mbomou", - "09" => "Nana-Mambere", - "11" => "Ouaka", - "12" => "Ouham", - "13" => "Ouham-Pende", - "14" => "Cuvette-Ouest", - "15" => "Nana-Grebizi", - "16" => "Sangha-Mbaere", - "17" => "Ombella-Mpoko", - "18" => "Bangui"), -"CG" => array( - "01" => "Bouenza", - "04" => "Kouilou", - "05" => "Lekoumou", - "06" => "Likouala", - "07" => "Niari", - "08" => "Plateaux", - "10" => "Sangha", - "11" => "Pool", - "12" => "Brazzaville", - "13" => "Cuvette", - "14" => "Cuvette-Ouest"), -"CH" => array( - "01" => "Aargau", - "02" => "Ausser-Rhoden", - "03" => "Basel-Landschaft", - "04" => "Basel-Stadt", - "05" => "Bern", - "06" => "Fribourg", - "07" => "Geneve", - "08" => "Glarus", - "09" => "Graubunden", - "10" => "Inner-Rhoden", - "11" => "Luzern", - "12" => "Neuchatel", - "13" => "Nidwalden", - "14" => "Obwalden", - "15" => "Sankt Gallen", - "16" => "Schaffhausen", - "17" => "Schwyz", - "18" => "Solothurn", - "19" => "Thurgau", - "20" => "Ticino", - "21" => "Uri", - "22" => "Valais", - "23" => "Vaud", - "24" => "Zug", - "25" => "Zurich", - "26" => "Jura"), -"CI" => array( - "74" => "Agneby", - "75" => "Bafing", - "76" => "Bas-Sassandra", - "77" => "Denguele", - "78" => "Dix-Huit Montagnes", - "79" => "Fromager", - "80" => "Haut-Sassandra", - "81" => "Lacs", - "82" => "Lagunes", - "83" => "Marahoue", - "84" => "Moyen-Cavally", - "85" => "Moyen-Comoe", - "86" => "N'zi-Comoe", - "87" => "Savanes", - "88" => "Sud-Bandama", - "89" => "Sud-Comoe", - "90" => "Vallee du Bandama", - "91" => "Worodougou", - "92" => "Zanzan"), -"CL" => array( - "01" => "Valparaiso", - "02" => "Aisen del General Carlos Ibanez del Campo", - "03" => "Antofagasta", - "04" => "Araucania", - "05" => "Atacama", - "06" => "Bio-Bio", - "07" => "Coquimbo", - "08" => "Libertador General Bernardo O'Higgins", - "09" => "Los Lagos", - "10" => "Magallanes y de la Antartica Chilena", - "11" => "Maule", - "12" => "Region Metropolitana", - "13" => "Tarapaca", - "14" => "Los Lagos", - "15" => "Tarapaca", - "16" => "Arica y Parinacota", - "17" => "Los Rios"), -"CM" => array( - "04" => "Est", - "05" => "Littoral", - "07" => "Nord-Ouest", - "08" => "Ouest", - "09" => "Sud-Ouest", - "10" => "Adamaoua", - "11" => "Centre", - "12" => "Extreme-Nord", - "13" => "Nord", - "14" => "Sud"), -"CN" => array( - "01" => "Anhui", - "02" => "Zhejiang", - "03" => "Jiangxi", - "04" => "Jiangsu", - "05" => "Jilin", - "06" => "Qinghai", - "07" => "Fujian", - "08" => "Heilongjiang", - "09" => "Henan", - "10" => "Hebei", - "11" => "Hunan", - "12" => "Hubei", - "13" => "Xinjiang", - "14" => "Xizang", - "15" => "Gansu", - "16" => "Guangxi", - "18" => "Guizhou", - "19" => "Liaoning", - "20" => "Nei Mongol", - "21" => "Ningxia", - "22" => "Beijing", - "23" => "Shanghai", - "24" => "Shanxi", - "25" => "Shandong", - "26" => "Shaanxi", - "28" => "Tianjin", - "29" => "Yunnan", - "30" => "Guangdong", - "31" => "Hainan", - "32" => "Sichuan", - "33" => "Chongqing"), -"CO" => array( - "01" => "Amazonas", - "02" => "Antioquia", - "03" => "Arauca", - "04" => "Atlantico", - "08" => "Caqueta", - "09" => "Cauca", - "10" => "Cesar", - "11" => "Choco", - "12" => "Cordoba", - "14" => "Guaviare", - "15" => "Guainia", - "16" => "Huila", - "17" => "La Guajira", - "19" => "Meta", - "20" => "Narino", - "21" => "Norte de Santander", - "22" => "Putumayo", - "23" => "Quindio", - "24" => "Risaralda", - "25" => "San Andres y Providencia", - "26" => "Santander", - "27" => "Sucre", - "28" => "Tolima", - "29" => "Valle del Cauca", - "30" => "Vaupes", - "31" => "Vichada", - "32" => "Casanare", - "33" => "Cundinamarca", - "34" => "Distrito Especial", - "35" => "Bolivar", - "36" => "Boyaca", - "37" => "Caldas", - "38" => "Magdalena"), -"CR" => array( - "01" => "Alajuela", - "02" => "Cartago", - "03" => "Guanacaste", - "04" => "Heredia", - "06" => "Limon", - "07" => "Puntarenas", - "08" => "San Jose"), -"CU" => array( - "01" => "Pinar del Rio", - "02" => "Ciudad de la Habana", - "03" => "Matanzas", - "04" => "Isla de la Juventud", - "05" => "Camaguey", - "07" => "Ciego de Avila", - "08" => "Cienfuegos", - "09" => "Granma", - "10" => "Guantanamo", - "11" => "La Habana", - "12" => "Holguin", - "13" => "Las Tunas", - "14" => "Sancti Spiritus", - "15" => "Santiago de Cuba", - "16" => "Villa Clara"), -"CV" => array( - "01" => "Boa Vista", - "02" => "Brava", - "04" => "Maio", - "05" => "Paul", - "07" => "Ribeira Grande", - "08" => "Sal", - "10" => "Sao Nicolau", - "11" => "Sao Vicente", - "13" => "Mosteiros", - "14" => "Praia", - "15" => "Santa Catarina", - "16" => "Santa Cruz", - "17" => "Sao Domingos", - "18" => "Sao Filipe", - "19" => "Sao Miguel", - "20" => "Tarrafal"), -"CY" => array( - "01" => "Famagusta", - "02" => "Kyrenia", - "03" => "Larnaca", - "04" => "Nicosia", - "05" => "Limassol", - "06" => "Paphos"), -"CZ" => array( - "52" => "Hlavni mesto Praha", - "78" => "Jihomoravsky kraj", - "79" => "Jihocesky kraj", - "80" => "Vysocina", - "81" => "Karlovarsky kraj", - "82" => "Kralovehradecky kraj", - "83" => "Liberecky kraj", - "84" => "Olomoucky kraj", - "85" => "Moravskoslezsky kraj", - "86" => "Pardubicky kraj", - "87" => "Plzensky kraj", - "88" => "Stredocesky kraj", - "89" => "Ustecky kraj", - "90" => "Zlinsky kraj"), -"DE" => array( - "01" => "Baden-Wurttemberg", - "02" => "Bayern", - "03" => "Bremen", - "04" => "Hamburg", - "05" => "Hessen", - "06" => "Niedersachsen", - "07" => "Nordrhein-Westfalen", - "08" => "Rheinland-Pfalz", - "09" => "Saarland", - "10" => "Schleswig-Holstein", - "11" => "Brandenburg", - "12" => "Mecklenburg-Vorpommern", - "13" => "Sachsen", - "14" => "Sachsen-Anhalt", - "15" => "Thuringen", - "16" => "Berlin"), -"DJ" => array( - "01" => "Ali Sabieh", - "04" => "Obock", - "05" => "Tadjoura", - "06" => "Dikhil", - "07" => "Djibouti", - "08" => "Arta"), -"DK" => array( - "17" => "Hovedstaden", - "18" => "Midtjylland", - "19" => "Nordjylland", - "20" => "Sjelland", - "21" => "Syddanmark"), -"DM" => array( - "02" => "Saint Andrew", - "03" => "Saint David", - "04" => "Saint George", - "05" => "Saint John", - "06" => "Saint Joseph", - "07" => "Saint Luke", - "08" => "Saint Mark", - "09" => "Saint Patrick", - "10" => "Saint Paul", - "11" => "Saint Peter"), -"DO" => array( - "01" => "Azua", - "02" => "Baoruco", - "03" => "Barahona", - "04" => "Dajabon", - "05" => "Distrito Nacional", - "06" => "Duarte", - "08" => "Espaillat", - "09" => "Independencia", - "10" => "La Altagracia", - "11" => "Elias Pina", - "12" => "La Romana", - "14" => "Maria Trinidad Sanchez", - "15" => "Monte Cristi", - "16" => "Pedernales", - "17" => "Peravia", - "18" => "Puerto Plata", - "19" => "Salcedo", - "20" => "Samana", - "21" => "Sanchez Ramirez", - "23" => "San Juan", - "24" => "San Pedro De Macoris", - "25" => "Santiago", - "26" => "Santiago Rodriguez", - "27" => "Valverde", - "28" => "El Seibo", - "29" => "Hato Mayor", - "30" => "La Vega", - "31" => "Monsenor Nouel", - "32" => "Monte Plata", - "33" => "San Cristobal", - "34" => "Distrito Nacional", - "35" => "Peravia", - "36" => "San Jose de Ocoa", - "37" => "Santo Domingo"), -"DZ" => array( - "01" => "Alger", - "03" => "Batna", - "04" => "Constantine", - "06" => "Medea", - "07" => "Mostaganem", - "09" => "Oran", - "10" => "Saida", - "12" => "Setif", - "13" => "Tiaret", - "14" => "Tizi Ouzou", - "15" => "Tlemcen", - "18" => "Bejaia", - "19" => "Biskra", - "20" => "Blida", - "21" => "Bouira", - "22" => "Djelfa", - "23" => "Guelma", - "24" => "Jijel", - "25" => "Laghouat", - "26" => "Mascara", - "27" => "M'sila", - "29" => "Oum el Bouaghi", - "30" => "Sidi Bel Abbes", - "31" => "Skikda", - "33" => "Tebessa", - "34" => "Adrar", - "35" => "Ain Defla", - "36" => "Ain Temouchent", - "37" => "Annaba", - "38" => "Bechar", - "39" => "Bordj Bou Arreridj", - "40" => "Boumerdes", - "41" => "Chlef", - "42" => "El Bayadh", - "43" => "El Oued", - "44" => "El Tarf", - "45" => "Ghardaia", - "46" => "Illizi", - "47" => "Khenchela", - "48" => "Mila", - "49" => "Naama", - "50" => "Ouargla", - "51" => "Relizane", - "52" => "Souk Ahras", - "53" => "Tamanghasset", - "54" => "Tindouf", - "55" => "Tipaza", - "56" => "Tissemsilt"), -"EC" => array( - "01" => "Galapagos", - "02" => "Azuay", - "03" => "Bolivar", - "04" => "Canar", - "05" => "Carchi", - "06" => "Chimborazo", - "07" => "Cotopaxi", - "08" => "El Oro", - "09" => "Esmeraldas", - "10" => "Guayas", - "11" => "Imbabura", - "12" => "Loja", - "13" => "Los Rios", - "14" => "Manabi", - "15" => "Morona-Santiago", - "17" => "Pastaza", - "18" => "Pichincha", - "19" => "Tungurahua", - "20" => "Zamora-Chinchipe", - "22" => "Sucumbios", - "23" => "Napo", - "24" => "Orellana"), -"EE" => array( - "01" => "Harjumaa", - "02" => "Hiiumaa", - "03" => "Ida-Virumaa", - "04" => "Jarvamaa", - "05" => "Jogevamaa", - "06" => "Kohtla-Jarve", - "07" => "Laanemaa", - "08" => "Laane-Virumaa", - "09" => "Narva", - "10" => "Parnu", - "11" => "Parnumaa", - "12" => "Polvamaa", - "13" => "Raplamaa", - "14" => "Saaremaa", - "15" => "Sillamae", - "16" => "Tallinn", - "17" => "Tartu", - "18" => "Tartumaa", - "19" => "Valgamaa", - "20" => "Viljandimaa", - "21" => "Vorumaa"), -"EG" => array( - "01" => "Ad Daqahliyah", - "02" => "Al Bahr al Ahmar", - "03" => "Al Buhayrah", - "04" => "Al Fayyum", - "05" => "Al Gharbiyah", - "06" => "Al Iskandariyah", - "07" => "Al Isma'iliyah", - "08" => "Al Jizah", - "09" => "Al Minufiyah", - "10" => "Al Minya", - "11" => "Al Qahirah", - "12" => "Al Qalyubiyah", - "13" => "Al Wadi al Jadid", - "14" => "Ash Sharqiyah", - "15" => "As Suways", - "16" => "Aswan", - "17" => "Asyut", - "18" => "Bani Suwayf", - "19" => "Bur Sa'id", - "20" => "Dumyat", - "21" => "Kafr ash Shaykh", - "22" => "Matruh", - "23" => "Qina", - "24" => "Suhaj", - "26" => "Janub Sina'", - "27" => "Shamal Sina'"), -"ER" => array( - "01" => "Anseba", - "02" => "Debub", - "03" => "Debubawi K'eyih Bahri", - "04" => "Gash Barka", - "05" => "Ma'akel", - "06" => "Semenawi K'eyih Bahri"), -"ES" => array( - "07" => "Islas Baleares", - "27" => "La Rioja", - "29" => "Madrid", - "31" => "Murcia", - "32" => "Navarra", - "34" => "Asturias", - "39" => "Cantabria", - "51" => "Andalucia", - "52" => "Aragon", - "53" => "Canarias", - "54" => "Castilla-La Mancha", - "55" => "Castilla y Leon", - "56" => "Catalonia", - "57" => "Extremadura", - "58" => "Galicia", - "59" => "Pais Vasco", - "60" => "Comunidad Valenciana"), -"ET" => array( - "44" => "Adis Abeba", - "45" => "Afar", - "46" => "Amara", - "47" => "Binshangul Gumuz", - "48" => "Dire Dawa", - "49" => "Gambela Hizboch", - "50" => "Hareri Hizb", - "51" => "Oromiya", - "52" => "Sumale", - "53" => "Tigray", - "54" => "YeDebub Biheroch Bihereseboch na Hizboch"), -"FI" => array( - "01" => "Aland", - "06" => "Lapland", - "08" => "Oulu", - "13" => "Southern Finland", - "14" => "Eastern Finland", - "15" => "Western Finland"), -"FJ" => array( - "01" => "Central", - "02" => "Eastern", - "03" => "Northern", - "04" => "Rotuma", - "05" => "Western"), -"FM" => array( - "01" => "Kosrae", - "02" => "Pohnpei", - "03" => "Chuuk", - "04" => "Yap"), -"FR" => array( - "97" => "Aquitaine", - "98" => "Auvergne", - "99" => "Basse-Normandie", - "A1" => "Bourgogne", - "A2" => "Bretagne", - "A3" => "Centre", - "A4" => "Champagne-Ardenne", - "A5" => "Corse", - "A6" => "Franche-Comte", - "A7" => "Haute-Normandie", - "A8" => "Ile-de-France", - "A9" => "Languedoc-Roussillon", - "B1" => "Limousin", - "B2" => "Lorraine", - "B3" => "Midi-Pyrenees", - "B4" => "Nord-Pas-de-Calais", - "B5" => "Pays de la Loire", - "B6" => "Picardie", - "B7" => "Poitou-Charentes", - "B8" => "Provence-Alpes-Cote d'Azur", - "B9" => "Rhone-Alpes", - "C1" => "Alsace"), -"GA" => array( - "01" => "Estuaire", - "02" => "Haut-Ogooue", - "03" => "Moyen-Ogooue", - "04" => "Ngounie", - "05" => "Nyanga", - "06" => "Ogooue-Ivindo", - "07" => "Ogooue-Lolo", - "08" => "Ogooue-Maritime", - "09" => "Woleu-Ntem"), -"GB" => array( - "A1" => "Barking and Dagenham", - "A2" => "Barnet", - "A3" => "Barnsley", - "A4" => "Bath and North East Somerset", - "A5" => "Bedfordshire", - "A6" => "Bexley", - "A7" => "Birmingham", - "A8" => "Blackburn with Darwen", - "A9" => "Blackpool", - "B1" => "Bolton", - "B2" => "Bournemouth", - "B3" => "Bracknell Forest", - "B4" => "Bradford", - "B5" => "Brent", - "B6" => "Brighton and Hove", - "B7" => "Bristol, City of", - "B8" => "Bromley", - "B9" => "Buckinghamshire", - "C1" => "Bury", - "C2" => "Calderdale", - "C3" => "Cambridgeshire", - "C4" => "Camden", - "C5" => "Cheshire", - "C6" => "Cornwall", - "C7" => "Coventry", - "C8" => "Croydon", - "C9" => "Cumbria", - "D1" => "Darlington", - "D2" => "Derby", - "D3" => "Derbyshire", - "D4" => "Devon", - "D5" => "Doncaster", - "D6" => "Dorset", - "D7" => "Dudley", - "D8" => "Durham", - "D9" => "Ealing", - "E1" => "East Riding of Yorkshire", - "E2" => "East Sussex", - "E3" => "Enfield", - "E4" => "Essex", - "E5" => "Gateshead", - "E6" => "Gloucestershire", - "E7" => "Greenwich", - "E8" => "Hackney", - "E9" => "Halton", - "F1" => "Hammersmith and Fulham", - "F2" => "Hampshire", - "F3" => "Haringey", - "F4" => "Harrow", - "F5" => "Hartlepool", - "F6" => "Havering", - "F7" => "Herefordshire", - "F8" => "Hertford", - "F9" => "Hillingdon", - "G1" => "Hounslow", - "G2" => "Isle of Wight", - "G3" => "Islington", - "G4" => "Kensington and Chelsea", - "G5" => "Kent", - "G6" => "Kingston upon Hull, City of", - "G7" => "Kingston upon Thames", - "G8" => "Kirklees", - "G9" => "Knowsley", - "H1" => "Lambeth", - "H2" => "Lancashire", - "H3" => "Leeds", - "H4" => "Leicester", - "H5" => "Leicestershire", - "H6" => "Lewisham", - "H7" => "Lincolnshire", - "H8" => "Liverpool", - "H9" => "London, City of", - "I1" => "Luton", - "I2" => "Manchester", - "I3" => "Medway", - "I4" => "Merton", - "I5" => "Middlesbrough", - "I6" => "Milton Keynes", - "I7" => "Newcastle upon Tyne", - "I8" => "Newham", - "I9" => "Norfolk", - "J1" => "Northamptonshire", - "J2" => "North East Lincolnshire", - "J3" => "North Lincolnshire", - "J4" => "North Somerset", - "J5" => "North Tyneside", - "J6" => "Northumberland", - "J7" => "North Yorkshire", - "J8" => "Nottingham", - "J9" => "Nottinghamshire", - "K1" => "Oldham", - "K2" => "Oxfordshire", - "K3" => "Peterborough", - "K4" => "Plymouth", - "K5" => "Poole", - "K6" => "Portsmouth", - "K7" => "Reading", - "K8" => "Redbridge", - "K9" => "Redcar and Cleveland", - "L1" => "Richmond upon Thames", - "L2" => "Rochdale", - "L3" => "Rotherham", - "L4" => "Rutland", - "L5" => "Salford", - "L6" => "Shropshire", - "L7" => "Sandwell", - "L8" => "Sefton", - "L9" => "Sheffield", - "M1" => "Slough", - "M2" => "Solihull", - "M3" => "Somerset", - "M4" => "Southampton", - "M5" => "Southend-on-Sea", - "M6" => "South Gloucestershire", - "M7" => "South Tyneside", - "M8" => "Southwark", - "M9" => "Staffordshire", - "N1" => "St. Helens", - "N2" => "Stockport", - "N3" => "Stockton-on-Tees", - "N4" => "Stoke-on-Trent", - "N5" => "Suffolk", - "N6" => "Sunderland", - "N7" => "Surrey", - "N8" => "Sutton", - "N9" => "Swindon", - "O1" => "Tameside", - "O2" => "Telford and Wrekin", - "O3" => "Thurrock", - "O4" => "Torbay", - "O5" => "Tower Hamlets", - "O6" => "Trafford", - "O7" => "Wakefield", - "O8" => "Walsall", - "O9" => "Waltham Forest", - "P1" => "Wandsworth", - "P2" => "Warrington", - "P3" => "Warwickshire", - "P4" => "West Berkshire", - "P5" => "Westminster", - "P6" => "West Sussex", - "P7" => "Wigan", - "P8" => "Wiltshire", - "P9" => "Windsor and Maidenhead", - "Q1" => "Wirral", - "Q2" => "Wokingham", - "Q3" => "Wolverhampton", - "Q4" => "Worcestershire", - "Q5" => "York", - "Q6" => "Antrim", - "Q7" => "Ards", - "Q8" => "Armagh", - "Q9" => "Ballymena", - "R1" => "Ballymoney", - "R2" => "Banbridge", - "R3" => "Belfast", - "R4" => "Carrickfergus", - "R5" => "Castlereagh", - "R6" => "Coleraine", - "R7" => "Cookstown", - "R8" => "Craigavon", - "R9" => "Down", - "S1" => "Dungannon", - "S2" => "Fermanagh", - "S3" => "Larne", - "S4" => "Limavady", - "S5" => "Lisburn", - "S6" => "Derry", - "S7" => "Magherafelt", - "S8" => "Moyle", - "S9" => "Newry and Mourne", - "T1" => "Newtownabbey", - "T2" => "North Down", - "T3" => "Omagh", - "T4" => "Strabane", - "T5" => "Aberdeen City", - "T6" => "Aberdeenshire", - "T7" => "Angus", - "T8" => "Argyll and Bute", - "T9" => "Scottish Borders, The", - "U1" => "Clackmannanshire", - "U2" => "Dumfries and Galloway", - "U3" => "Dundee City", - "U4" => "East Ayrshire", - "U5" => "East Dunbartonshire", - "U6" => "East Lothian", - "U7" => "East Renfrewshire", - "U8" => "Edinburgh, City of", - "U9" => "Falkirk", - "V1" => "Fife", - "V2" => "Glasgow City", - "V3" => "Highland", - "V4" => "Inverclyde", - "V5" => "Midlothian", - "V6" => "Moray", - "V7" => "North Ayrshire", - "V8" => "North Lanarkshire", - "V9" => "Orkney", - "W1" => "Perth and Kinross", - "W2" => "Renfrewshire", - "W3" => "Shetland Islands", - "W4" => "South Ayrshire", - "W5" => "South Lanarkshire", - "W6" => "Stirling", - "W7" => "West Dunbartonshire", - "W8" => "Eilean Siar", - "W9" => "West Lothian", - "X1" => "Isle of Anglesey", - "X2" => "Blaenau Gwent", - "X3" => "Bridgend", - "X4" => "Caerphilly", - "X5" => "Cardiff", - "X6" => "Ceredigion", - "X7" => "Carmarthenshire", - "X8" => "Conwy", - "X9" => "Denbighshire", - "Y1" => "Flintshire", - "Y2" => "Gwynedd", - "Y3" => "Merthyr Tydfil", - "Y4" => "Monmouthshire", - "Y5" => "Neath Port Talbot", - "Y6" => "Newport", - "Y7" => "Pembrokeshire", - "Y8" => "Powys", - "Y9" => "Rhondda Cynon Taff", - "Z1" => "Swansea", - "Z2" => "Torfaen", - "Z3" => "Vale of Glamorgan, The", - "Z4" => "Wrexham"), -"GD" => array( - "01" => "Saint Andrew", - "02" => "Saint David", - "03" => "Saint George", - "04" => "Saint John", - "05" => "Saint Mark", - "06" => "Saint Patrick"), -"GE" => array( - "01" => "Abashis Raioni", - "02" => "Abkhazia", - "03" => "Adigenis Raioni", - "04" => "Ajaria", - "05" => "Akhalgoris Raioni", - "06" => "Akhalk'alak'is Raioni", - "07" => "Akhalts'ikhis Raioni", - "08" => "Akhmetis Raioni", - "09" => "Ambrolauris Raioni", - "10" => "Aspindzis Raioni", - "11" => "Baghdat'is Raioni", - "12" => "Bolnisis Raioni", - "13" => "Borjomis Raioni", - "14" => "Chiat'ura", - "15" => "Ch'khorotsqus Raioni", - "16" => "Ch'okhatauris Raioni", - "17" => "Dedop'listsqaros Raioni", - "18" => "Dmanisis Raioni", - "19" => "Dushet'is Raioni", - "20" => "Gardabanis Raioni", - "21" => "Gori", - "22" => "Goris Raioni", - "23" => "Gurjaanis Raioni", - "24" => "Javis Raioni", - "25" => "K'arelis Raioni", - "26" => "Kaspis Raioni", - "27" => "Kharagaulis Raioni", - "28" => "Khashuris Raioni", - "29" => "Khobis Raioni", - "30" => "Khonis Raioni", - "31" => "K'ut'aisi", - "32" => "Lagodekhis Raioni", - "33" => "Lanch'khut'is Raioni", - "34" => "Lentekhis Raioni", - "35" => "Marneulis Raioni", - "36" => "Martvilis Raioni", - "37" => "Mestiis Raioni", - "38" => "Mts'khet'is Raioni", - "39" => "Ninotsmindis Raioni", - "40" => "Onis Raioni", - "41" => "Ozurget'is Raioni", - "42" => "P'ot'i", - "43" => "Qazbegis Raioni", - "44" => "Qvarlis Raioni", - "45" => "Rust'avi", - "46" => "Sach'kheris Raioni", - "47" => "Sagarejos Raioni", - "48" => "Samtrediis Raioni", - "49" => "Senakis Raioni", - "50" => "Sighnaghis Raioni", - "51" => "T'bilisi", - "52" => "T'elavis Raioni", - "53" => "T'erjolis Raioni", - "54" => "T'et'ritsqaros Raioni", - "55" => "T'ianet'is Raioni", - "56" => "Tqibuli", - "57" => "Ts'ageris Raioni", - "58" => "Tsalenjikhis Raioni", - "59" => "Tsalkis Raioni", - "60" => "Tsqaltubo", - "61" => "Vanis Raioni", - "62" => "Zestap'onis Raioni", - "63" => "Zugdidi", - "64" => "Zugdidis Raioni"), -"GH" => array( - "01" => "Greater Accra", - "02" => "Ashanti", - "03" => "Brong-Ahafo", - "04" => "Central", - "05" => "Eastern", - "06" => "Northern", - "08" => "Volta", - "09" => "Western", - "10" => "Upper East", - "11" => "Upper West"), -"GL" => array( - "01" => "Nordgronland", - "02" => "Ostgronland", - "03" => "Vestgronland"), -"GM" => array( - "01" => "Banjul", - "02" => "Lower River", - "03" => "Central River", - "04" => "Upper River", - "05" => "Western", - "07" => "North Bank"), -"GN" => array( - "01" => "Beyla", - "02" => "Boffa", - "03" => "Boke", - "04" => "Conakry", - "05" => "Dabola", - "06" => "Dalaba", - "07" => "Dinguiraye", - "09" => "Faranah", - "10" => "Forecariah", - "11" => "Fria", - "12" => "Gaoual", - "13" => "Gueckedou", - "15" => "Kerouane", - "16" => "Kindia", - "17" => "Kissidougou", - "18" => "Koundara", - "19" => "Kouroussa", - "21" => "Macenta", - "22" => "Mali", - "23" => "Mamou", - "25" => "Pita", - "27" => "Telimele", - "28" => "Tougue", - "29" => "Yomou", - "30" => "Coyah", - "31" => "Dubreka", - "32" => "Kankan", - "33" => "Koubia", - "34" => "Labe", - "35" => "Lelouma", - "36" => "Lola", - "37" => "Mandiana", - "38" => "Nzerekore", - "39" => "Siguiri"), -"GQ" => array( - "03" => "Annobon", - "04" => "Bioko Norte", - "05" => "Bioko Sur", - "06" => "Centro Sur", - "07" => "Kie-Ntem", - "08" => "Litoral", - "09" => "Wele-Nzas"), -"GR" => array( - "01" => "Evros", - "02" => "Rodhopi", - "03" => "Xanthi", - "04" => "Drama", - "05" => "Serrai", - "06" => "Kilkis", - "07" => "Pella", - "08" => "Florina", - "09" => "Kastoria", - "10" => "Grevena", - "11" => "Kozani", - "12" => "Imathia", - "13" => "Thessaloniki", - "14" => "Kavala", - "15" => "Khalkidhiki", - "16" => "Pieria", - "17" => "Ioannina", - "18" => "Thesprotia", - "19" => "Preveza", - "20" => "Arta", - "21" => "Larisa", - "22" => "Trikala", - "23" => "Kardhitsa", - "24" => "Magnisia", - "25" => "Kerkira", - "26" => "Levkas", - "27" => "Kefallinia", - "28" => "Zakinthos", - "29" => "Fthiotis", - "30" => "Evritania", - "31" => "Aitolia kai Akarnania", - "32" => "Fokis", - "33" => "Voiotia", - "34" => "Evvoia", - "35" => "Attiki", - "36" => "Argolis", - "37" => "Korinthia", - "38" => "Akhaia", - "39" => "Ilia", - "40" => "Messinia", - "41" => "Arkadhia", - "42" => "Lakonia", - "43" => "Khania", - "44" => "Rethimni", - "45" => "Iraklion", - "46" => "Lasithi", - "47" => "Dhodhekanisos", - "48" => "Samos", - "49" => "Kikladhes", - "50" => "Khios", - "51" => "Lesvos"), -"GT" => array( - "01" => "Alta Verapaz", - "02" => "Baja Verapaz", - "03" => "Chimaltenango", - "04" => "Chiquimula", - "05" => "El Progreso", - "06" => "Escuintla", - "07" => "Guatemala", - "08" => "Huehuetenango", - "09" => "Izabal", - "10" => "Jalapa", - "11" => "Jutiapa", - "12" => "Peten", - "13" => "Quetzaltenango", - "14" => "Quiche", - "15" => "Retalhuleu", - "16" => "Sacatepequez", - "17" => "San Marcos", - "18" => "Santa Rosa", - "19" => "Solola", - "20" => "Suchitepequez", - "21" => "Totonicapan", - "22" => "Zacapa"), -"GW" => array( - "01" => "Bafata", - "02" => "Quinara", - "04" => "Oio", - "05" => "Bolama", - "06" => "Cacheu", - "07" => "Tombali", - "10" => "Gabu", - "11" => "Bissau", - "12" => "Biombo"), -"GY" => array( - "10" => "Barima-Waini", - "11" => "Cuyuni-Mazaruni", - "12" => "Demerara-Mahaica", - "13" => "East Berbice-Corentyne", - "14" => "Essequibo Islands-West Demerara", - "15" => "Mahaica-Berbice", - "16" => "Pomeroon-Supenaam", - "17" => "Potaro-Siparuni", - "18" => "Upper Demerara-Berbice", - "19" => "Upper Takutu-Upper Essequibo"), -"HN" => array( - "01" => "Atlantida", - "02" => "Choluteca", - "03" => "Colon", - "04" => "Comayagua", - "05" => "Copan", - "06" => "Cortes", - "07" => "El Paraiso", - "08" => "Francisco Morazan", - "09" => "Gracias a Dios", - "10" => "Intibuca", - "11" => "Islas de la Bahia", - "12" => "La Paz", - "13" => "Lempira", - "14" => "Ocotepeque", - "15" => "Olancho", - "16" => "Santa Barbara", - "17" => "Valle", - "18" => "Yoro"), -"HR" => array( - "01" => "Bjelovarsko-Bilogorska", - "02" => "Brodsko-Posavska", - "03" => "Dubrovacko-Neretvanska", - "04" => "Istarska", - "05" => "Karlovacka", - "06" => "Koprivnicko-Krizevacka", - "07" => "Krapinsko-Zagorska", - "08" => "Licko-Senjska", - "09" => "Medimurska", - "10" => "Osjecko-Baranjska", - "11" => "Pozesko-Slavonska", - "12" => "Primorsko-Goranska", - "13" => "Sibensko-Kninska", - "14" => "Sisacko-Moslavacka", - "15" => "Splitsko-Dalmatinska", - "16" => "Varazdinska", - "17" => "Viroviticko-Podravska", - "18" => "Vukovarsko-Srijemska", - "19" => "Zadarska", - "20" => "Zagrebacka", - "21" => "Grad Zagreb"), -"HT" => array( - "03" => "Nord-Ouest", - "06" => "Artibonite", - "07" => "Centre", - "09" => "Nord", - "10" => "Nord-Est", - "11" => "Ouest", - "12" => "Sud", - "13" => "Sud-Est", - "14" => "Grand' Anse", - "15" => "Nippes"), -"HU" => array( - "01" => "Bacs-Kiskun", - "02" => "Baranya", - "03" => "Bekes", - "04" => "Borsod-Abauj-Zemplen", - "05" => "Budapest", - "06" => "Csongrad", - "07" => "Debrecen", - "08" => "Fejer", - "09" => "Gyor-Moson-Sopron", - "10" => "Hajdu-Bihar", - "11" => "Heves", - "12" => "Komarom-Esztergom", - "13" => "Miskolc", - "14" => "Nograd", - "15" => "Pecs", - "16" => "Pest", - "17" => "Somogy", - "18" => "Szabolcs-Szatmar-Bereg", - "19" => "Szeged", - "20" => "Jasz-Nagykun-Szolnok", - "21" => "Tolna", - "22" => "Vas", - "23" => "Veszprem", - "24" => "Zala", - "25" => "Gyor", - "26" => "Bekescsaba", - "27" => "Dunaujvaros", - "28" => "Eger", - "29" => "Hodmezovasarhely", - "30" => "Kaposvar", - "31" => "Kecskemet", - "32" => "Nagykanizsa", - "33" => "Nyiregyhaza", - "34" => "Sopron", - "35" => "Szekesfehervar", - "36" => "Szolnok", - "37" => "Szombathely", - "38" => "Tatabanya", - "39" => "Veszprem", - "40" => "Zalaegerszeg", - "41" => "Salgotarjan", - "42" => "Szekszard", - "43" => "Erd"), -"ID" => array( - "01" => "Aceh", - "02" => "Bali", - "03" => "Bengkulu", - "04" => "Jakarta Raya", - "05" => "Jambi", - "07" => "Jawa Tengah", - "08" => "Jawa Timur", - "10" => "Yogyakarta", - "11" => "Kalimantan Barat", - "12" => "Kalimantan Selatan", - "13" => "Kalimantan Tengah", - "14" => "Kalimantan Timur", - "15" => "Lampung", - "17" => "Nusa Tenggara Barat", - "18" => "Nusa Tenggara Timur", - "21" => "Sulawesi Tengah", - "22" => "Sulawesi Tenggara", - "24" => "Sumatera Barat", - "26" => "Sumatera Utara", - "28" => "Maluku", - "29" => "Maluku Utara", - "30" => "Jawa Barat", - "31" => "Sulawesi Utara", - "32" => "Sumatera Selatan", - "33" => "Banten", - "34" => "Gorontalo", - "35" => "Kepulauan Bangka Belitung", - "36" => "Papua", - "37" => "Riau", - "38" => "Sulawesi Selatan", - "39" => "Irian Jaya Barat", - "40" => "Kepulauan Riau", - "41" => "Sulawesi Barat"), -"IE" => array( - "01" => "Carlow", - "02" => "Cavan", - "03" => "Clare", - "04" => "Cork", - "06" => "Donegal", - "07" => "Dublin", - "10" => "Galway", - "11" => "Kerry", - "12" => "Kildare", - "13" => "Kilkenny", - "14" => "Leitrim", - "15" => "Laois", - "16" => "Limerick", - "18" => "Longford", - "19" => "Louth", - "20" => "Mayo", - "21" => "Meath", - "22" => "Monaghan", - "23" => "Offaly", - "24" => "Roscommon", - "25" => "Sligo", - "26" => "Tipperary", - "27" => "Waterford", - "29" => "Westmeath", - "30" => "Wexford", - "31" => "Wicklow"), -"IL" => array( - "01" => "HaDarom", - "02" => "HaMerkaz", - "03" => "HaZafon", - "04" => "Hefa", - "05" => "Tel Aviv", - "06" => "Yerushalayim"), -"IN" => array( - "01" => "Andaman and Nicobar Islands", - "02" => "Andhra Pradesh", - "03" => "Assam", - "05" => "Chandigarh", - "06" => "Dadra and Nagar Haveli", - "07" => "Delhi", - "09" => "Gujarat", - "10" => "Haryana", - "11" => "Himachal Pradesh", - "12" => "Jammu and Kashmir", - "13" => "Kerala", - "14" => "Lakshadweep", - "16" => "Maharashtra", - "17" => "Manipur", - "18" => "Meghalaya", - "19" => "Karnataka", - "20" => "Nagaland", - "21" => "Orissa", - "22" => "Puducherry", - "23" => "Punjab", - "24" => "Rajasthan", - "25" => "Tamil Nadu", - "26" => "Tripura", - "28" => "West Bengal", - "29" => "Sikkim", - "30" => "Arunachal Pradesh", - "31" => "Mizoram", - "32" => "Daman and Diu", - "33" => "Goa", - "34" => "Bihar", - "35" => "Madhya Pradesh", - "36" => "Uttar Pradesh", - "37" => "Chhattisgarh", - "38" => "Jharkhand", - "39" => "Uttarakhand"), -"IQ" => array( - "01" => "Al Anbar", - "02" => "Al Basrah", - "03" => "Al Muthanna", - "04" => "Al Qadisiyah", - "05" => "As Sulaymaniyah", - "06" => "Babil", - "07" => "Baghdad", - "08" => "Dahuk", - "09" => "Dhi Qar", - "10" => "Diyala", - "11" => "Arbil", - "12" => "Karbala'", - "13" => "At Ta'mim", - "14" => "Maysan", - "15" => "Ninawa", - "16" => "Wasit", - "17" => "An Najaf", - "18" => "Salah ad Din"), -"IR" => array( - "01" => "Azarbayjan-e Bakhtari", - "03" => "Chahar Mahall va Bakhtiari", - "04" => "Sistan va Baluchestan", - "05" => "Kohkiluyeh va Buyer Ahmadi", - "07" => "Fars", - "08" => "Gilan", - "09" => "Hamadan", - "10" => "Ilam", - "11" => "Hormozgan", - "12" => "Kerman", - "13" => "Bakhtaran", - "15" => "Khuzestan", - "16" => "Kordestan", - "17" => "Mazandaran", - "18" => "Semnan Province", - "19" => "Markazi", - "21" => "Zanjan", - "22" => "Bushehr", - "23" => "Lorestan", - "24" => "Markazi", - "25" => "Semnan", - "26" => "Tehran", - "27" => "Zanjan", - "28" => "Esfahan", - "29" => "Kerman", - "30" => "Khorasan", - "31" => "Yazd", - "32" => "Ardabil", - "33" => "East Azarbaijan", - "34" => "Markazi", - "35" => "Mazandaran", - "36" => "Zanjan", - "37" => "Golestan", - "38" => "Qazvin", - "39" => "Qom", - "40" => "Yazd", - "41" => "Khorasan-e Janubi", - "42" => "Khorasan-e Razavi", - "43" => "Khorasan-e Shemali"), -"IS" => array( - "03" => "Arnessysla", - "05" => "Austur-Hunavatnssysla", - "06" => "Austur-Skaftafellssysla", - "07" => "Borgarfjardarsysla", - "09" => "Eyjafjardarsysla", - "10" => "Gullbringusysla", - "15" => "Kjosarsysla", - "17" => "Myrasysla", - "20" => "Nordur-Mulasysla", - "21" => "Nordur-Tingeyjarsysla", - "23" => "Rangarvallasysla", - "28" => "Skagafjardarsysla", - "29" => "Snafellsnes- og Hnappadalssysla", - "30" => "Strandasysla", - "31" => "Sudur-Mulasysla", - "32" => "Sudur-Tingeyjarsysla", - "34" => "Vestur-Bardastrandarsysla", - "35" => "Vestur-Hunavatnssysla", - "36" => "Vestur-Isafjardarsysla", - "37" => "Vestur-Skaftafellssysla", - "40" => "Norourland Eystra", - "41" => "Norourland Vestra", - "42" => "Suourland", - "43" => "Suournes", - "44" => "Vestfiroir", - "45" => "Vesturland"), -"IT" => array( - "01" => "Abruzzi", - "02" => "Basilicata", - "03" => "Calabria", - "04" => "Campania", - "05" => "Emilia-Romagna", - "06" => "Friuli-Venezia Giulia", - "07" => "Lazio", - "08" => "Liguria", - "09" => "Lombardia", - "10" => "Marche", - "11" => "Molise", - "12" => "Piemonte", - "13" => "Puglia", - "14" => "Sardegna", - "15" => "Sicilia", - "16" => "Toscana", - "17" => "Trentino-Alto Adige", - "18" => "Umbria", - "19" => "Valle d'Aosta", - "20" => "Veneto"), -"JM" => array( - "01" => "Clarendon", - "02" => "Hanover", - "04" => "Manchester", - "07" => "Portland", - "08" => "Saint Andrew", - "09" => "Saint Ann", - "10" => "Saint Catherine", - "11" => "Saint Elizabeth", - "12" => "Saint James", - "13" => "Saint Mary", - "14" => "Saint Thomas", - "15" => "Trelawny", - "16" => "Westmoreland", - "17" => "Kingston"), -"JO" => array( - "02" => "Al Balqa'", - "09" => "Al Karak", - "12" => "At Tafilah", - "15" => "Al Mafraq", - "16" => "Amman", - "17" => "Az Zaraqa", - "18" => "Irbid", - "19" => "Ma'an", - "20" => "Ajlun", - "21" => "Al Aqabah", - "22" => "Jarash", - "23" => "Madaba"), -"JP" => array( - "01" => "Aichi", - "02" => "Akita", - "03" => "Aomori", - "04" => "Chiba", - "05" => "Ehime", - "06" => "Fukui", - "07" => "Fukuoka", - "08" => "Fukushima", - "09" => "Gifu", - "10" => "Gumma", - "11" => "Hiroshima", - "12" => "Hokkaido", - "13" => "Hyogo", - "14" => "Ibaraki", - "15" => "Ishikawa", - "16" => "Iwate", - "17" => "Kagawa", - "18" => "Kagoshima", - "19" => "Kanagawa", - "20" => "Kochi", - "21" => "Kumamoto", - "22" => "Kyoto", - "23" => "Mie", - "24" => "Miyagi", - "25" => "Miyazaki", - "26" => "Nagano", - "27" => "Nagasaki", - "28" => "Nara", - "29" => "Niigata", - "30" => "Oita", - "31" => "Okayama", - "32" => "Osaka", - "33" => "Saga", - "34" => "Saitama", - "35" => "Shiga", - "36" => "Shimane", - "37" => "Shizuoka", - "38" => "Tochigi", - "39" => "Tokushima", - "40" => "Tokyo", - "41" => "Tottori", - "42" => "Toyama", - "43" => "Wakayama", - "44" => "Yamagata", - "45" => "Yamaguchi", - "46" => "Yamanashi", - "47" => "Okinawa"), -"KE" => array( - "01" => "Central", - "02" => "Coast", - "03" => "Eastern", - "05" => "Nairobi Area", - "06" => "North-Eastern", - "07" => "Nyanza", - "08" => "Rift Valley", - "09" => "Western"), -"KG" => array( - "01" => "Bishkek", - "02" => "Chuy", - "03" => "Jalal-Abad", - "04" => "Naryn", - "05" => "Osh", - "06" => "Talas", - "07" => "Ysyk-Kol", - "08" => "Osh", - "09" => "Batken"), -"KH" => array( - "01" => "Batdambang", - "02" => "Kampong Cham", - "03" => "Kampong Chhnang", - "04" => "Kampong Speu", - "05" => "Kampong Thum", - "06" => "Kampot", - "07" => "Kandal", - "08" => "Koh Kong", - "09" => "Kracheh", - "10" => "Mondulkiri", - "11" => "Phnum Penh", - "12" => "Pursat", - "13" => "Preah Vihear", - "14" => "Prey Veng", - "15" => "Ratanakiri Kiri", - "16" => "Siem Reap", - "17" => "Stung Treng", - "18" => "Svay Rieng", - "19" => "Takeo", - "25" => "Banteay Meanchey", - "29" => "Batdambang", - "30" => "Pailin"), -"KI" => array( - "01" => "Gilbert Islands", - "02" => "Line Islands", - "03" => "Phoenix Islands"), -"KM" => array( - "01" => "Anjouan", - "02" => "Grande Comore", - "03" => "Moheli"), -"KN" => array( - "01" => "Christ Church Nichola Town", - "02" => "Saint Anne Sandy Point", - "03" => "Saint George Basseterre", - "04" => "Saint George Gingerland", - "05" => "Saint James Windward", - "06" => "Saint John Capisterre", - "07" => "Saint John Figtree", - "08" => "Saint Mary Cayon", - "09" => "Saint Paul Capisterre", - "10" => "Saint Paul Charlestown", - "11" => "Saint Peter Basseterre", - "12" => "Saint Thomas Lowland", - "13" => "Saint Thomas Middle Island", - "15" => "Trinity Palmetto Point"), -"KP" => array( - "01" => "Chagang-do", - "03" => "Hamgyong-namdo", - "06" => "Hwanghae-namdo", - "07" => "Hwanghae-bukto", - "08" => "Kaesong-si", - "09" => "Kangwon-do", - "11" => "P'yongan-bukto", - "12" => "P'yongyang-si", - "13" => "Yanggang-do", - "14" => "Namp'o-si", - "15" => "P'yongan-namdo", - "17" => "Hamgyong-bukto", - "18" => "Najin Sonbong-si"), -"KR" => array( - "01" => "Cheju-do", - "03" => "Cholla-bukto", - "05" => "Ch'ungch'ong-bukto", - "06" => "Kangwon-do", - "10" => "Pusan-jikhalsi", - "11" => "Seoul-t'ukpyolsi", - "12" => "Inch'on-jikhalsi", - "13" => "Kyonggi-do", - "14" => "Kyongsang-bukto", - "15" => "Taegu-jikhalsi", - "16" => "Cholla-namdo", - "17" => "Ch'ungch'ong-namdo", - "18" => "Kwangju-jikhalsi", - "19" => "Taejon-jikhalsi", - "20" => "Kyongsang-namdo", - "21" => "Ulsan-gwangyoksi"), -"KW" => array( - "01" => "Al Ahmadi", - "02" => "Al Kuwayt", - "05" => "Al Jahra", - "07" => "Al Farwaniyah", - "08" => "Hawalli", - "09" => "Mubarak al Kabir"), -"KY" => array( - "01" => "Creek", - "02" => "Eastern", - "03" => "Midland", - "04" => "South Town", - "05" => "Spot Bay", - "06" => "Stake Bay", - "07" => "West End", - "08" => "Western"), -"KZ" => array( - "01" => "Almaty", - "02" => "Almaty City", - "03" => "Aqmola", - "04" => "Aqtobe", - "05" => "Astana", - "06" => "Atyrau", - "07" => "West Kazakhstan", - "08" => "Bayqonyr", - "09" => "Mangghystau", - "10" => "South Kazakhstan", - "11" => "Pavlodar", - "12" => "Qaraghandy", - "13" => "Qostanay", - "14" => "Qyzylorda", - "15" => "East Kazakhstan", - "16" => "North Kazakhstan", - "17" => "Zhambyl"), -"LA" => array( - "01" => "Attapu", - "02" => "Champasak", - "03" => "Houaphan", - "04" => "Khammouan", - "05" => "Louang Namtha", - "07" => "Oudomxai", - "08" => "Phongsali", - "09" => "Saravan", - "10" => "Savannakhet", - "11" => "Vientiane", - "13" => "Xaignabouri", - "14" => "Xiangkhoang", - "17" => "Louangphrabang"), -"LB" => array( - "01" => "Beqaa", - "02" => "Al Janub", - "03" => "Liban-Nord", - "04" => "Beyrouth", - "05" => "Mont-Liban", - "06" => "Liban-Sud", - "07" => "Nabatiye", - "08" => "Beqaa", - "09" => "Liban-Nord", - "10" => "Aakk,r", - "11" => "Baalbek-Hermel"), -"LC" => array( - "01" => "Anse-la-Raye", - "02" => "Dauphin", - "03" => "Castries", - "04" => "Choiseul", - "05" => "Dennery", - "06" => "Gros-Islet", - "07" => "Laborie", - "08" => "Micoud", - "09" => "Soufriere", - "10" => "Vieux-Fort", - "11" => "Praslin"), -"LI" => array( - "01" => "Balzers", - "02" => "Eschen", - "03" => "Gamprin", - "04" => "Mauren", - "05" => "Planken", - "06" => "Ruggell", - "07" => "Schaan", - "08" => "Schellenberg", - "09" => "Triesen", - "10" => "Triesenberg", - "11" => "Vaduz", - "21" => "Gbarpolu", - "22" => "River Gee"), -"LK" => array( - "01" => "Amparai", - "02" => "Anuradhapura", - "03" => "Badulla", - "04" => "Batticaloa", - "06" => "Galle", - "07" => "Hambantota", - "09" => "Kalutara", - "10" => "Kandy", - "11" => "Kegalla", - "12" => "Kurunegala", - "14" => "Matale", - "15" => "Matara", - "16" => "Moneragala", - "17" => "Nuwara Eliya", - "18" => "Polonnaruwa", - "19" => "Puttalam", - "20" => "Ratnapura", - "21" => "Trincomalee", - "23" => "Colombo", - "24" => "Gampaha", - "25" => "Jaffna", - "26" => "Mannar", - "27" => "Mullaittivu", - "28" => "Vavuniya", - "29" => "Central", - "30" => "North Central", - "31" => "Northern", - "32" => "North Western", - "33" => "Sabaragamuwa", - "34" => "Southern", - "35" => "Uva", - "36" => "Western"), -"LR" => array( - "01" => "Bong", - "04" => "Grand Cape Mount", - "05" => "Lofa", - "06" => "Maryland", - "07" => "Monrovia", - "09" => "Nimba", - "10" => "Sino", - "11" => "Grand Bassa", - "12" => "Grand Cape Mount", - "13" => "Maryland", - "14" => "Montserrado", - "17" => "Margibi", - "18" => "River Cess", - "19" => "Grand Gedeh", - "20" => "Lofa", - "21" => "Gbarpolu", - "22" => "River Gee"), -"LS" => array( - "10" => "Berea", - "11" => "Butha-Buthe", - "12" => "Leribe", - "13" => "Mafeteng", - "14" => "Maseru", - "15" => "Mohales Hoek", - "16" => "Mokhotlong", - "17" => "Qachas Nek", - "18" => "Quthing", - "19" => "Thaba-Tseka"), -"LT" => array( - "56" => "Alytaus Apskritis", - "57" => "Kauno Apskritis", - "58" => "Klaipedos Apskritis", - "59" => "Marijampoles Apskritis", - "60" => "Panevezio Apskritis", - "61" => "Siauliu Apskritis", - "62" => "Taurages Apskritis", - "63" => "Telsiu Apskritis", - "64" => "Utenos Apskritis", - "65" => "Vilniaus Apskritis"), -"LU" => array( - "01" => "Diekirch", - "02" => "Grevenmacher", - "03" => "Luxembourg"), -"LV" => array( - "01" => "Aizkraukles", - "02" => "Aluksnes", - "03" => "Balvu", - "04" => "Bauskas", - "05" => "Cesu", - "06" => "Daugavpils", - "07" => "Daugavpils", - "08" => "Dobeles", - "09" => "Gulbenes", - "10" => "Jekabpils", - "11" => "Jelgava", - "12" => "Jelgavas", - "13" => "Jurmala", - "14" => "Kraslavas", - "15" => "Kuldigas", - "16" => "Liepaja", - "17" => "Liepajas", - "18" => "Limbazu", - "19" => "Ludzas", - "20" => "Madonas", - "21" => "Ogres", - "22" => "Preilu", - "23" => "Rezekne", - "24" => "Rezeknes", - "25" => "Riga", - "26" => "Rigas", - "27" => "Saldus", - "28" => "Talsu", - "29" => "Tukuma", - "30" => "Valkas", - "31" => "Valmieras", - "32" => "Ventspils", - "33" => "Ventspils"), -"LY" => array( - "03" => "Al Aziziyah", - "05" => "Al Jufrah", - "08" => "Al Kufrah", - "13" => "Ash Shati'", - "30" => "Murzuq", - "34" => "Sabha", - "41" => "Tarhunah", - "42" => "Tubruq", - "45" => "Zlitan", - "47" => "Ajdabiya", - "48" => "Al Fatih", - "49" => "Al Jabal al Akhdar", - "50" => "Al Khums", - "51" => "An Nuqat al Khams", - "52" => "Awbari", - "53" => "Az Zawiyah", - "54" => "Banghazi", - "55" => "Darnah", - "56" => "Ghadamis", - "57" => "Gharyan", - "58" => "Misratah", - "59" => "Sawfajjin", - "60" => "Surt", - "61" => "Tarabulus", - "62" => "Yafran"), -"MA" => array( - "45" => "Grand Casablanca", - "46" => "Fes-Boulemane", - "47" => "Marrakech-Tensift-Al Haouz", - "48" => "Meknes-Tafilalet", - "49" => "Rabat-Sale-Zemmour-Zaer", - "50" => "Chaouia-Ouardigha", - "51" => "Doukkala-Abda", - "52" => "Gharb-Chrarda-Beni Hssen", - "53" => "Guelmim-Es Smara", - "54" => "Oriental", - "55" => "Souss-Massa-Dr,a", - "56" => "Tadla-Azilal", - "57" => "Tanger-Tetouan", - "58" => "Taza-Al Hoceima-Taounate", - "59" => "La,youne-Boujdour-Sakia El Hamra"), -"MC" => array( - "01" => "La Condamine", - "02" => "Monaco", - "03" => "Monte-Carlo"), -"MD" => array( - "51" => "Gagauzia", - "57" => "Chisinau", - "58" => "Stinga Nistrului", - "59" => "Anenii Noi", - "60" => "Balti", - "61" => "Basarabeasca", - "62" => "Bender", - "63" => "Briceni", - "64" => "Cahul", - "65" => "Cantemir", - "66" => "Calarasi", - "67" => "Causeni", - "68" => "Cimislia", - "69" => "Criuleni", - "70" => "Donduseni", - "71" => "Drochia", - "72" => "Dubasari", - "73" => "Edinet", - "74" => "Falesti", - "75" => "Floresti", - "76" => "Glodeni", - "77" => "Hincesti", - "78" => "Ialoveni", - "79" => "Leova", - "80" => "Nisporeni", - "81" => "Ocnita", - "82" => "Orhei", - "83" => "Rezina", - "84" => "Riscani", - "85" => "Singerei", - "86" => "Soldanesti", - "87" => "Soroca", - "88" => "Stefan-Voda", - "89" => "Straseni", - "90" => "Taraclia", - "91" => "Telenesti", - "92" => "Ungheni"), -"MG" => array( - "01" => "Antsiranana", - "02" => "Fianarantsoa", - "03" => "Mahajanga", - "04" => "Toamasina", - "05" => "Antananarivo", - "06" => "Toliara"), -"MK" => array( - "01" => "Aracinovo", - "02" => "Bac", - "03" => "Belcista", - "04" => "Berovo", - "05" => "Bistrica", - "06" => "Bitola", - "07" => "Blatec", - "08" => "Bogdanci", - "09" => "Bogomila", - "10" => "Bogovinje", - "11" => "Bosilovo", - "12" => "Brvenica", - "13" => "Cair", - "14" => "Capari", - "15" => "Caska", - "16" => "Cegrane", - "17" => "Centar", - "18" => "Centar Zupa", - "19" => "Cesinovo", - "20" => "Cucer-Sandevo", - "21" => "Debar", - "22" => "Delcevo", - "23" => "Delogozdi", - "24" => "Demir Hisar", - "25" => "Demir Kapija", - "26" => "Dobrusevo", - "27" => "Dolna Banjica", - "28" => "Dolneni", - "29" => "Dorce Petrov", - "30" => "Drugovo", - "31" => "Dzepciste", - "32" => "Gazi Baba", - "33" => "Gevgelija", - "34" => "Gostivar", - "35" => "Gradsko", - "36" => "Ilinden", - "37" => "Izvor", - "38" => "Jegunovce", - "39" => "Kamenjane", - "40" => "Karbinci", - "41" => "Karpos", - "42" => "Kavadarci", - "43" => "Kicevo", - "44" => "Kisela Voda", - "45" => "Klecevce", - "46" => "Kocani", - "47" => "Konce", - "48" => "Kondovo", - "49" => "Konopiste", - "50" => "Kosel", - "51" => "Kratovo", - "52" => "Kriva Palanka", - "53" => "Krivogastani", - "54" => "Krusevo", - "55" => "Kuklis", - "56" => "Kukurecani", - "57" => "Kumanovo", - "58" => "Labunista", - "59" => "Lipkovo", - "60" => "Lozovo", - "61" => "Lukovo", - "62" => "Makedonska Kamenica", - "63" => "Makedonski Brod", - "64" => "Mavrovi Anovi", - "65" => "Meseista", - "66" => "Miravci", - "67" => "Mogila", - "68" => "Murtino", - "69" => "Negotino", - "70" => "Negotino-Polosko", - "71" => "Novaci", - "72" => "Novo Selo", - "73" => "Oblesevo", - "74" => "Ohrid", - "75" => "Orasac", - "76" => "Orizari", - "77" => "Oslomej", - "78" => "Pehcevo", - "79" => "Petrovec", - "80" => "Plasnica", - "81" => "Podares", - "82" => "Prilep", - "83" => "Probistip", - "84" => "Radovis", - "85" => "Rankovce", - "86" => "Resen", - "87" => "Rosoman", - "88" => "Rostusa", - "89" => "Samokov", - "90" => "Saraj", - "91" => "Sipkovica", - "92" => "Sopiste", - "93" => "Sopotnica", - "94" => "Srbinovo", - "95" => "Staravina", - "96" => "Star Dojran", - "97" => "Staro Nagoricane", - "98" => "Stip", - "99" => "Struga", - "A1" => "Strumica", - "A2" => "Studenicani", - "A3" => "Suto Orizari", - "A4" => "Sveti Nikole", - "A5" => "Tearce", - "A6" => "Tetovo", - "A7" => "Topolcani", - "A8" => "Valandovo", - "A9" => "Vasilevo", - "B1" => "Veles", - "B2" => "Velesta", - "B3" => "Vevcani", - "B4" => "Vinica", - "B5" => "Vitoliste", - "B6" => "Vranestica", - "B7" => "Vrapciste", - "B8" => "Vratnica", - "B9" => "Vrutok", - "C1" => "Zajas", - "C2" => "Zelenikovo", - "C3" => "Zelino", - "C4" => "Zitose", - "C5" => "Zletovo", - "C6" => "Zrnovci"), -"ML" => array( - "01" => "Bamako", - "03" => "Kayes", - "04" => "Mopti", - "05" => "Segou", - "06" => "Sikasso", - "07" => "Koulikoro", - "08" => "Tombouctou", - "09" => "Gao", - "10" => "Kidal"), -"MM" => array( - "01" => "Rakhine State", - "02" => "Chin State", - "03" => "Irrawaddy", - "04" => "Kachin State", - "05" => "Karan State", - "06" => "Kayah State", - "07" => "Magwe", - "08" => "Mandalay", - "09" => "Pegu", - "10" => "Sagaing", - "11" => "Shan State", - "12" => "Tenasserim", - "13" => "Mon State", - "14" => "Rangoon", - "17" => "Yangon"), -"MN" => array( - "01" => "Arhangay", - "02" => "Bayanhongor", - "03" => "Bayan-Olgiy", - "05" => "Darhan", - "06" => "Dornod", - "07" => "Dornogovi", - "08" => "Dundgovi", - "09" => "Dzavhan", - "10" => "Govi-Altay", - "11" => "Hentiy", - "12" => "Hovd", - "13" => "Hovsgol", - "14" => "Omnogovi", - "15" => "Ovorhangay", - "16" => "Selenge", - "17" => "Suhbaatar", - "18" => "Tov", - "19" => "Uvs", - "20" => "Ulaanbaatar", - "21" => "Bulgan", - "22" => "Erdenet", - "23" => "Darhan-Uul", - "24" => "Govisumber", - "25" => "Orhon"), -"MO" => array( - "01" => "Ilhas", - "02" => "Macau"), -"MR" => array( - "01" => "Hodh Ech Chargui", - "02" => "Hodh El Gharbi", - "03" => "Assaba", - "04" => "Gorgol", - "05" => "Brakna", - "06" => "Trarza", - "07" => "Adrar", - "08" => "Dakhlet Nouadhibou", - "09" => "Tagant", - "10" => "Guidimaka", - "11" => "Tiris Zemmour", - "12" => "Inchiri"), -"MS" => array( - "01" => "Saint Anthony", - "02" => "Saint Georges", - "03" => "Saint Peter"), -"MU" => array( - "12" => "Black River", - "13" => "Flacq", - "14" => "Grand Port", - "15" => "Moka", - "16" => "Pamplemousses", - "17" => "Plaines Wilhems", - "18" => "Port Louis", - "19" => "Riviere du Rempart", - "20" => "Savanne", - "21" => "Agalega Islands", - "22" => "Cargados Carajos", - "23" => "Rodrigues"), -"MV" => array( - "01" => "Seenu", - "05" => "Laamu", - "30" => "Alifu", - "31" => "Baa", - "32" => "Dhaalu", - "33" => "Faafu ", - "34" => "Gaafu Alifu", - "35" => "Gaafu Dhaalu", - "36" => "Haa Alifu", - "37" => "Haa Dhaalu", - "38" => "Kaafu", - "39" => "Lhaviyani", - "40" => "Maale", - "41" => "Meemu", - "42" => "Gnaviyani", - "43" => "Noonu", - "44" => "Raa", - "45" => "Shaviyani", - "46" => "Thaa", - "47" => "Vaavu"), -"MW" => array( - "02" => "Chikwawa", - "03" => "Chiradzulu", - "04" => "Chitipa", - "05" => "Thyolo", - "06" => "Dedza", - "07" => "Dowa", - "08" => "Karonga", - "09" => "Kasungu", - "11" => "Lilongwe", - "12" => "Mangochi", - "13" => "Mchinji", - "15" => "Mzimba", - "16" => "Ntcheu", - "17" => "Nkhata Bay", - "18" => "Nkhotakota", - "19" => "Nsanje", - "20" => "Ntchisi", - "21" => "Rumphi", - "22" => "Salima", - "23" => "Zomba", - "24" => "Blantyre", - "25" => "Mwanza", - "26" => "Balaka", - "27" => "Likoma", - "28" => "Machinga", - "29" => "Mulanje", - "30" => "Phalombe"), -"MX" => array( - "01" => "Aguascalientes", - "02" => "Baja California", - "03" => "Baja California Sur", - "04" => "Campeche", - "05" => "Chiapas", - "06" => "Chihuahua", - "07" => "Coahuila de Zaragoza", - "08" => "Colima", - "09" => "Distrito Federal", - "10" => "Durango", - "11" => "Guanajuato", - "12" => "Guerrero", - "13" => "Hidalgo", - "14" => "Jalisco", - "15" => "Mexico", - "16" => "Michoacan de Ocampo", - "17" => "Morelos", - "18" => "Nayarit", - "19" => "Nuevo Leon", - "20" => "Oaxaca", - "21" => "Puebla", - "22" => "Queretaro de Arteaga", - "23" => "Quintana Roo", - "24" => "San Luis Potosi", - "25" => "Sinaloa", - "26" => "Sonora", - "27" => "Tabasco", - "28" => "Tamaulipas", - "29" => "Tlaxcala", - "30" => "Veracruz-Llave", - "31" => "Yucatan", - "32" => "Zacatecas"), -"MY" => array( - "01" => "Johor", - "02" => "Kedah", - "03" => "Kelantan", - "04" => "Melaka", - "05" => "Negeri Sembilan", - "06" => "Pahang", - "07" => "Perak", - "08" => "Perlis", - "09" => "Pulau Pinang", - "11" => "Sarawak", - "12" => "Selangor", - "13" => "Terengganu", - "14" => "Kuala Lumpur", - "15" => "Labuan", - "16" => "Sabah", - "17" => "Putrajaya"), -"MZ" => array( - "01" => "Cabo Delgado", - "02" => "Gaza", - "03" => "Inhambane", - "04" => "Maputo", - "05" => "Sofala", - "06" => "Nampula", - "07" => "Niassa", - "08" => "Tete", - "09" => "Zambezia", - "10" => "Manica", - "11" => "Maputo"), -"NA" => array( - "01" => "Bethanien", - "02" => "Caprivi Oos", - "03" => "Boesmanland", - "04" => "Gobabis", - "05" => "Grootfontein", - "06" => "Kaokoland", - "07" => "Karibib", - "08" => "Keetmanshoop", - "09" => "Luderitz", - "10" => "Maltahohe", - "11" => "Okahandja", - "12" => "Omaruru", - "13" => "Otjiwarongo", - "14" => "Outjo", - "15" => "Owambo", - "16" => "Rehoboth", - "17" => "Swakopmund", - "18" => "Tsumeb", - "20" => "Karasburg", - "21" => "Windhoek", - "22" => "Damaraland", - "23" => "Hereroland Oos", - "24" => "Hereroland Wes", - "25" => "Kavango", - "26" => "Mariental", - "27" => "Namaland", - "28" => "Caprivi", - "29" => "Erongo", - "30" => "Hardap", - "31" => "Karas", - "32" => "Kunene", - "33" => "Ohangwena", - "34" => "Okavango", - "35" => "Omaheke", - "36" => "Omusati", - "37" => "Oshana", - "38" => "Oshikoto", - "39" => "Otjozondjupa"), -"NE" => array( - "01" => "Agadez", - "02" => "Diffa", - "03" => "Dosso", - "04" => "Maradi", - "05" => "Niamey", - "06" => "Tahoua", - "07" => "Zinder", - "08" => "Niamey"), -"NG" => array( - "05" => "Lagos", - "11" => "Federal Capital Territory", - "16" => "Ogun", - "21" => "Akwa Ibom", - "22" => "Cross River", - "23" => "Kaduna", - "24" => "Katsina", - "25" => "Anambra", - "26" => "Benue", - "27" => "Borno", - "28" => "Imo", - "29" => "Kano", - "30" => "Kwara", - "31" => "Niger", - "32" => "Oyo", - "35" => "Adamawa", - "36" => "Delta", - "37" => "Edo", - "39" => "Jigawa", - "40" => "Kebbi", - "41" => "Kogi", - "42" => "Osun", - "43" => "Taraba", - "44" => "Yobe", - "45" => "Abia", - "46" => "Bauchi", - "47" => "Enugu", - "48" => "Ondo", - "49" => "Plateau", - "50" => "Rivers", - "51" => "Sokoto", - "52" => "Bayelsa", - "53" => "Ebonyi", - "54" => "Ekiti", - "55" => "Gombe", - "56" => "Nassarawa", - "57" => "Zamfara"), -"NI" => array( - "01" => "Boaco", - "02" => "Carazo", - "03" => "Chinandega", - "04" => "Chontales", - "05" => "Esteli", - "06" => "Granada", - "07" => "Jinotega", - "08" => "Leon", - "09" => "Madriz", - "10" => "Managua", - "11" => "Masaya", - "12" => "Matagalpa", - "13" => "Nueva Segovia", - "14" => "Rio San Juan", - "15" => "Rivas", - "16" => "Zelaya", - "17" => "Autonoma Atlantico Norte", - "18" => "Region Autonoma Atlantico Sur"), -"NL" => array( - "01" => "Drenthe", - "02" => "Friesland", - "03" => "Gelderland", - "04" => "Groningen", - "05" => "Limburg", - "06" => "Noord-Brabant", - "07" => "Noord-Holland", - "09" => "Utrecht", - "10" => "Zeeland", - "11" => "Zuid-Holland", - "15" => "Overijssel", - "16" => "Flevoland"), -"NO" => array( - "01" => "Akershus", - "02" => "Aust-Agder", - "04" => "Buskerud", - "05" => "Finnmark", - "06" => "Hedmark", - "07" => "Hordaland", - "08" => "More og Romsdal", - "09" => "Nordland", - "10" => "Nord-Trondelag", - "11" => "Oppland", - "12" => "Oslo", - "13" => "Ostfold", - "14" => "Rogaland", - "15" => "Sogn og Fjordane", - "16" => "Sor-Trondelag", - "17" => "Telemark", - "18" => "Troms", - "19" => "Vest-Agder", - "20" => "Vestfold"), -"NP" => array( - "01" => "Bagmati", - "02" => "Bheri", - "03" => "Dhawalagiri", - "04" => "Gandaki", - "05" => "Janakpur", - "06" => "Karnali", - "07" => "Kosi", - "08" => "Lumbini", - "09" => "Mahakali", - "10" => "Mechi", - "11" => "Narayani", - "12" => "Rapti", - "13" => "Sagarmatha", - "14" => "Seti"), -"NR" => array( - "01" => "Aiwo", - "02" => "Anabar", - "03" => "Anetan", - "04" => "Anibare", - "05" => "Baiti", - "06" => "Boe", - "07" => "Buada", - "08" => "Denigomodu", - "09" => "Ewa", - "10" => "Ijuw", - "11" => "Meneng", - "12" => "Nibok", - "13" => "Uaboe", - "14" => "Yaren"), -"NZ" => array( - "10" => "Chatham Islands", - "E7" => "Auckland", - "E8" => "Bay of Plenty", - "E9" => "Canterbury", - "F1" => "Gisborne", - "F2" => "Hawke's Bay", - "F3" => "Manawatu-Wanganui", - "F4" => "Marlborough", - "F5" => "Nelson", - "F6" => "Northland", - "F7" => "Otago", - "F8" => "Southland", - "F9" => "Taranaki", - "G1" => "Waikato", - "G2" => "Wellington", - "G3" => "West Coast"), -"OM" => array( - "01" => "Ad Dakhiliyah", - "02" => "Al Batinah", - "03" => "Al Wusta", - "04" => "Ash Sharqiyah", - "05" => "Az Zahirah", - "06" => "Masqat", - "07" => "Musandam", - "08" => "Zufar"), -"PA" => array( - "01" => "Bocas del Toro", - "02" => "Chiriqui", - "03" => "Cocle", - "04" => "Colon", - "05" => "Darien", - "06" => "Herrera", - "07" => "Los Santos", - "08" => "Panama", - "09" => "San Blas", - "10" => "Veraguas"), -"PE" => array( - "01" => "Amazonas", - "02" => "Ancash", - "03" => "Apurimac", - "04" => "Arequipa", - "05" => "Ayacucho", - "06" => "Cajamarca", - "07" => "Callao", - "08" => "Cusco", - "09" => "Huancavelica", - "10" => "Huanuco", - "11" => "Ica", - "12" => "Junin", - "13" => "La Libertad", - "14" => "Lambayeque", - "15" => "Lima", - "16" => "Loreto", - "17" => "Madre de Dios", - "18" => "Moquegua", - "19" => "Pasco", - "20" => "Piura", - "21" => "Puno", - "22" => "San Martin", - "23" => "Tacna", - "24" => "Tumbes", - "25" => "Ucayali"), -"PG" => array( - "01" => "Central", - "02" => "Gulf", - "03" => "Milne Bay", - "04" => "Northern", - "05" => "Southern Highlands", - "06" => "Western", - "07" => "North Solomons", - "08" => "Chimbu", - "09" => "Eastern Highlands", - "10" => "East New Britain", - "11" => "East Sepik", - "12" => "Madang", - "13" => "Manus", - "14" => "Morobe", - "15" => "New Ireland", - "16" => "Western Highlands", - "17" => "West New Britain", - "18" => "Sandaun", - "19" => "Enga", - "20" => "National Capital"), -"PH" => array( - "01" => "Abra", - "02" => "Agusan del Norte", - "03" => "Agusan del Sur", - "04" => "Aklan", - "05" => "Albay", - "06" => "Antique", - "07" => "Bataan", - "08" => "Batanes", - "09" => "Batangas", - "10" => "Benguet", - "11" => "Bohol", - "12" => "Bukidnon", - "13" => "Bulacan", - "14" => "Cagayan", - "15" => "Camarines Norte", - "16" => "Camarines Sur", - "17" => "Camiguin", - "18" => "Capiz", - "19" => "Catanduanes", - "20" => "Cavite", - "21" => "Cebu", - "22" => "Basilan", - "23" => "Eastern Samar", - "24" => "Davao", - "25" => "Davao del Sur", - "26" => "Davao Oriental", - "27" => "Ifugao", - "28" => "Ilocos Norte", - "29" => "Ilocos Sur", - "30" => "Iloilo", - "31" => "Isabela", - "32" => "Kalinga-Apayao", - "33" => "Laguna", - "34" => "Lanao del Norte", - "35" => "Lanao del Sur", - "36" => "La Union", - "37" => "Leyte", - "38" => "Marinduque", - "39" => "Masbate", - "40" => "Mindoro Occidental", - "41" => "Mindoro Oriental", - "42" => "Misamis Occidental", - "43" => "Misamis Oriental", - "44" => "Mountain", - "45" => "Negros Occidental", - "46" => "Negros Oriental", - "47" => "Nueva Ecija", - "48" => "Nueva Vizcaya", - "49" => "Palawan", - "50" => "Pampanga", - "51" => "Pangasinan", - "53" => "Rizal", - "54" => "Romblon", - "55" => "Samar", - "56" => "Maguindanao", - "57" => "North Cotabato", - "58" => "Sorsogon", - "59" => "Southern Leyte", - "60" => "Sulu", - "61" => "Surigao del Norte", - "62" => "Surigao del Sur", - "63" => "Tarlac", - "64" => "Zambales", - "65" => "Zamboanga del Norte", - "66" => "Zamboanga del Sur", - "67" => "Northern Samar", - "68" => "Quirino", - "69" => "Siquijor", - "70" => "South Cotabato", - "71" => "Sultan Kudarat", - "72" => "Tawitawi", - "A1" => "Angeles", - "A2" => "Bacolod", - "A3" => "Bago", - "A4" => "Baguio", - "A5" => "Bais", - "A6" => "Basilan City", - "A7" => "Batangas City", - "A8" => "Butuan", - "A9" => "Cabanatuan", - "B1" => "Cadiz", - "B2" => "Cagayan de Oro", - "B3" => "Calbayog", - "B4" => "Caloocan", - "B5" => "Canlaon", - "B6" => "Cavite City", - "B7" => "Cebu City", - "B8" => "Cotabato", - "B9" => "Dagupan", - "C1" => "Danao", - "C2" => "Dapitan", - "C3" => "Davao City", - "C4" => "Dipolog", - "C5" => "Dumaguete", - "C6" => "General Santos", - "C7" => "Gingoog", - "C8" => "Iligan", - "C9" => "Iloilo City", - "D1" => "Iriga", - "D2" => "La Carlota", - "D3" => "Laoag", - "D4" => "Lapu-Lapu", - "D5" => "Legaspi", - "D6" => "Lipa", - "D7" => "Lucena", - "D8" => "Mandaue", - "D9" => "Manila", - "E1" => "Marawi", - "E2" => "Naga", - "E3" => "Olongapo", - "E4" => "Ormoc", - "E5" => "Oroquieta", - "E6" => "Ozamis", - "E7" => "Pagadian", - "E8" => "Palayan", - "E9" => "Pasay", - "F1" => "Puerto Princesa", - "F2" => "Quezon City", - "F3" => "Roxas", - "F4" => "San Carlos", - "F5" => "San Carlos", - "F6" => "San Jose", - "F7" => "San Pablo", - "F8" => "Silay", - "F9" => "Surigao", - "G1" => "Tacloban", - "G2" => "Tagaytay", - "G3" => "Tagbilaran", - "G4" => "Tangub", - "G5" => "Toledo", - "G6" => "Trece Martires", - "G7" => "Zamboanga", - "G8" => "Aurora", - "H2" => "Quezon", - "H3" => "Negros Occidental"), -"PK" => array( - "01" => "Federally Administered Tribal Areas", - "02" => "Balochistan", - "03" => "North-West Frontier", - "04" => "Punjab", - "05" => "Sindh", - "06" => "Azad Kashmir", - "07" => "Northern Areas", - "08" => "Islamabad"), -"PL" => array( - "72" => "Dolnoslaskie", - "73" => "Kujawsko-Pomorskie", - "74" => "Lodzkie", - "75" => "Lubelskie", - "76" => "Lubuskie", - "77" => "Malopolskie", - "78" => "Mazowieckie", - "79" => "Opolskie", - "80" => "Podkarpackie", - "81" => "Podlaskie", - "82" => "Pomorskie", - "83" => "Slaskie", - "84" => "Swietokrzyskie", - "85" => "Warminsko-Mazurskie", - "86" => "Wielkopolskie", - "87" => "Zachodniopomorskie"), -"PS" => array( - "GZ" => "Gaza", - "WE" => "West Bank"), -"PT" => array( - "02" => "Aveiro", - "03" => "Beja", - "04" => "Braga", - "05" => "Braganca", - "06" => "Castelo Branco", - "07" => "Coimbra", - "08" => "Evora", - "09" => "Faro", - "10" => "Madeira", - "11" => "Guarda", - "13" => "Leiria", - "14" => "Lisboa", - "16" => "Portalegre", - "17" => "Porto", - "18" => "Santarem", - "19" => "Setubal", - "20" => "Viana do Castelo", - "21" => "Vila Real", - "22" => "Viseu", - "23" => "Azores"), -"PY" => array( - "01" => "Alto Parana", - "02" => "Amambay", - "03" => "Boqueron", - "04" => "Caaguazu", - "05" => "Caazapa", - "06" => "Central", - "07" => "Concepcion", - "08" => "Cordillera", - "10" => "Guaira", - "11" => "Itapua", - "12" => "Misiones", - "13" => "Neembucu", - "15" => "Paraguari", - "16" => "Presidente Hayes", - "17" => "San Pedro", - "19" => "Canindeyu", - "20" => "Chaco", - "21" => "Nueva Asuncion", - "23" => "Alto Paraguay"), -"QA" => array( - "01" => "Ad Dawhah", - "02" => "Al Ghuwariyah", - "03" => "Al Jumaliyah", - "04" => "Al Khawr", - "05" => "Al Wakrah Municipality", - "06" => "Ar Rayyan", - "08" => "Madinat ach Shamal", - "09" => "Umm Salal", - "10" => "Al Wakrah", - "11" => "Jariyan al Batnah", - "12" => "Umm Sa'id"), -"RO" => array( - "01" => "Alba", - "02" => "Arad", - "03" => "Arges", - "04" => "Bacau", - "05" => "Bihor", - "06" => "Bistrita-Nasaud", - "07" => "Botosani", - "08" => "Braila", - "09" => "Brasov", - "10" => "Bucuresti", - "11" => "Buzau", - "12" => "Caras-Severin", - "13" => "Cluj", - "14" => "Constanta", - "15" => "Covasna", - "16" => "Dambovita", - "17" => "Dolj", - "18" => "Galati", - "19" => "Gorj", - "20" => "Harghita", - "21" => "Hunedoara", - "22" => "Ialomita", - "23" => "Iasi", - "25" => "Maramures", - "26" => "Mehedinti", - "27" => "Mures", - "28" => "Neamt", - "29" => "Olt", - "30" => "Prahova", - "31" => "Salaj", - "32" => "Satu Mare", - "33" => "Sibiu", - "34" => "Suceava", - "35" => "Teleorman", - "36" => "Timis", - "37" => "Tulcea", - "38" => "Vaslui", - "39" => "Valcea", - "40" => "Vrancea", - "41" => "Calarasi", - "42" => "Giurgiu", - "43" => "Ilfov"), -"RS" => array( - "01" => "Kosovo", - "02" => "Vojvodina"), -"RU" => array( - "01" => "Adygeya, Republic of", - "02" => "Aginsky Buryatsky AO", - "03" => "Gorno-Altay", - "04" => "Altaisky krai", - "05" => "Amur", - "06" => "Arkhangel'sk", - "07" => "Astrakhan'", - "08" => "Bashkortostan", - "09" => "Belgorod", - "10" => "Bryansk", - "11" => "Buryat", - "12" => "Chechnya", - "13" => "Chelyabinsk", - "14" => "Chita", - "15" => "Chukot", - "16" => "Chuvashia", - "17" => "Dagestan", - "18" => "Evenk", - "19" => "Ingush", - "20" => "Irkutsk", - "21" => "Ivanovo", - "22" => "Kabardin-Balkar", - "23" => "Kaliningrad", - "24" => "Kalmyk", - "25" => "Kaluga", - "26" => "Kamchatka", - "27" => "Karachay-Cherkess", - "28" => "Karelia", - "29" => "Kemerovo", - "30" => "Khabarovsk", - "31" => "Khakass", - "32" => "Khanty-Mansiy", - "33" => "Kirov", - "34" => "Komi", - "35" => "Komi-Permyak", - "36" => "Koryak", - "37" => "Kostroma", - "38" => "Krasnodar", - "39" => "Krasnoyarsk", - "40" => "Kurgan", - "41" => "Kursk", - "42" => "Leningrad", - "43" => "Lipetsk", - "44" => "Magadan", - "45" => "Mariy-El", - "46" => "Mordovia", - "47" => "Moskva", - "48" => "Moscow City", - "49" => "Murmansk", - "50" => "Nenets", - "51" => "Nizhegorod", - "52" => "Novgorod", - "53" => "Novosibirsk", - "54" => "Omsk", - "55" => "Orenburg", - "56" => "Orel", - "57" => "Penza", - "58" => "Perm'", - "59" => "Primor'ye", - "60" => "Pskov", - "61" => "Rostov", - "62" => "Ryazan'", - "63" => "Sakha", - "64" => "Sakhalin", - "65" => "Samara", - "66" => "Saint Petersburg City", - "67" => "Saratov", - "68" => "North Ossetia", - "69" => "Smolensk", - "70" => "Stavropol'", - "71" => "Sverdlovsk", - "72" => "Tambovskaya oblast", - "73" => "Tatarstan", - "74" => "Taymyr", - "75" => "Tomsk", - "76" => "Tula", - "77" => "Tver'", - "78" => "Tyumen'", - "79" => "Tuva", - "80" => "Udmurt", - "81" => "Ul'yanovsk", - "82" => "Ust-Orda Buryat", - "83" => "Vladimir", - "84" => "Volgograd", - "85" => "Vologda", - "86" => "Voronezh", - "87" => "Yamal-Nenets", - "88" => "Yaroslavl'", - "89" => "Yevrey", - "90" => "Permskiy Kray", - "91" => "Krasnoyarskiy Kray", - "92" => "Kamchatskiy Kray", - "93" => "Zabaykal'skiy Kray"), -"RW" => array( - "01" => "Butare", - "06" => "Gitarama", - "07" => "Kibungo", - "09" => "Kigali", - "11" => "Est", - "12" => "Kigali", - "13" => "Nord", - "14" => "Ouest", - "15" => "Sud"), -"SA" => array( - "02" => "Al Bahah", - "05" => "Al Madinah", - "06" => "Ash Sharqiyah", - "08" => "Al Qasim", - "10" => "Ar Riyad", - "11" => "Asir Province", - "13" => "Ha'il", - "14" => "Makkah", - "15" => "Al Hudud ash Shamaliyah", - "16" => "Najran", - "17" => "Jizan", - "19" => "Tabuk", - "20" => "Al Jawf"), -"SB" => array( - "03" => "Malaita", - "06" => "Guadalcanal", - "07" => "Isabel", - "08" => "Makira", - "09" => "Temotu", - "10" => "Central", - "11" => "Western", - "12" => "Choiseul", - "13" => "Rennell and Bellona"), -"SC" => array( - "01" => "Anse aux Pins", - "02" => "Anse Boileau", - "03" => "Anse Etoile", - "04" => "Anse Louis", - "05" => "Anse Royale", - "06" => "Baie Lazare", - "07" => "Baie Sainte Anne", - "08" => "Beau Vallon", - "09" => "Bel Air", - "10" => "Bel Ombre", - "11" => "Cascade", - "12" => "Glacis", - "13" => "Grand' Anse", - "14" => "Grand' Anse", - "15" => "La Digue", - "16" => "La Riviere Anglaise", - "17" => "Mont Buxton", - "18" => "Mont Fleuri", - "19" => "Plaisance", - "20" => "Pointe La Rue", - "21" => "Port Glaud", - "22" => "Saint Louis", - "23" => "Takamaka"), -"SD" => array( - "27" => "Al Wusta", - "28" => "Al Istiwa'iyah", - "29" => "Al Khartum", - "30" => "Ash Shamaliyah", - "31" => "Ash Sharqiyah", - "32" => "Bahr al Ghazal", - "33" => "Darfur", - "34" => "Kurdufan", - "35" => "Upper Nile", - "40" => "Al Wahadah State", - "44" => "Central Equatoria State"), -"SE" => array( - "02" => "Blekinge Lan", - "03" => "Gavleborgs Lan", - "05" => "Gotlands Lan", - "06" => "Hallands Lan", - "07" => "Jamtlands Lan", - "08" => "Jonkopings Lan", - "09" => "Kalmar Lan", - "10" => "Dalarnas Lan", - "12" => "Kronobergs Lan", - "14" => "Norrbottens Lan", - "15" => "Orebro Lan", - "16" => "Ostergotlands Lan", - "18" => "Sodermanlands Lan", - "21" => "Uppsala Lan", - "22" => "Varmlands Lan", - "23" => "Vasterbottens Lan", - "24" => "Vasternorrlands Lan", - "25" => "Vastmanlands Lan", - "26" => "Stockholms Lan", - "27" => "Skane Lan", - "28" => "Vastra Gotaland"), -"SH" => array( - "01" => "Ascension", - "02" => "Saint Helena", - "03" => "Tristan da Cunha"), -"SI" => array( - "01" => "Ajdovscina", - "02" => "Beltinci", - "03" => "Bled", - "04" => "Bohinj", - "05" => "Borovnica", - "06" => "Bovec", - "07" => "Brda", - "08" => "Brezice", - "09" => "Brezovica", - "11" => "Celje", - "12" => "Cerklje na Gorenjskem", - "13" => "Cerknica", - "14" => "Cerkno", - "15" => "Crensovci", - "16" => "Crna na Koroskem", - "17" => "Crnomelj", - "19" => "Divaca", - "20" => "Dobrepolje", - "22" => "Dol pri Ljubljani", - "24" => "Dornava", - "25" => "Dravograd", - "26" => "Duplek", - "27" => "Gorenja Vas-Poljane", - "28" => "Gorisnica", - "29" => "Gornja Radgona", - "30" => "Gornji Grad", - "31" => "Gornji Petrovci", - "32" => "Grosuplje", - "34" => "Hrastnik", - "35" => "Hrpelje-Kozina", - "36" => "Idrija", - "37" => "Ig", - "38" => "Ilirska Bistrica", - "39" => "Ivancna Gorica", - "40" => "Izola-Isola", - "42" => "Jursinci", - "44" => "Kanal", - "45" => "Kidricevo", - "46" => "Kobarid", - "47" => "Kobilje", - "49" => "Komen", - "50" => "Koper-Capodistria", - "51" => "Kozje", - "52" => "Kranj", - "53" => "Kranjska Gora", - "54" => "Krsko", - "55" => "Kungota", - "57" => "Lasko", - "61" => "Ljubljana", - "62" => "Ljubno", - "64" => "Logatec", - "66" => "Loski Potok", - "68" => "Lukovica", - "71" => "Medvode", - "72" => "Menges", - "73" => "Metlika", - "74" => "Mezica", - "76" => "Mislinja", - "77" => "Moravce", - "78" => "Moravske Toplice", - "79" => "Mozirje", - "80" => "Murska Sobota", - "81" => "Muta", - "82" => "Naklo", - "83" => "Nazarje", - "84" => "Nova Gorica", - "86" => "Odranci", - "87" => "Ormoz", - "88" => "Osilnica", - "89" => "Pesnica", - "91" => "Pivka", - "92" => "Podcetrtek", - "94" => "Postojna", - "97" => "Puconci", - "98" => "Racam", - "99" => "Radece", - "A1" => "Radenci", - "A2" => "Radlje ob Dravi", - "A3" => "Radovljica", - "A6" => "Rogasovci", - "A7" => "Rogaska Slatina", - "A8" => "Rogatec", - "B1" => "Semic", - "B2" => "Sencur", - "B3" => "Sentilj", - "B4" => "Sentjernej", - "B6" => "Sevnica", - "B7" => "Sezana", - "B8" => "Skocjan", - "B9" => "Skofja Loka", - "C1" => "Skofljica", - "C2" => "Slovenj Gradec", - "C4" => "Slovenske Konjice", - "C5" => "Smarje pri Jelsah", - "C6" => "Smartno ob Paki", - "C7" => "Sostanj", - "C8" => "Starse", - "C9" => "Store", - "D1" => "Sveti Jurij", - "D2" => "Tolmin", - "D3" => "Trbovlje", - "D4" => "Trebnje", - "D5" => "Trzic", - "D6" => "Turnisce", - "D7" => "Velenje", - "D8" => "Velike Lasce", - "E1" => "Vipava", - "E2" => "Vitanje", - "E3" => "Vodice", - "E5" => "Vrhnika", - "E6" => "Vuzenica", - "E7" => "Zagorje ob Savi", - "E9" => "Zavrc", - "F1" => "Zelezniki", - "F2" => "Ziri", - "F3" => "Zrece", - "G4" => "Dobrova-Horjul-Polhov Gradec", - "G7" => "Domzale", - "H4" => "Jesenice", - "H6" => "Kamnik", - "H7" => "Kocevje", - "I2" => "Kuzma", - "I3" => "Lenart", - "I5" => "Litija", - "I6" => "Ljutomer", - "I7" => "Loska Dolina", - "I9" => "Luce", - "J1" => "Majsperk", - "J2" => "Maribor", - "J5" => "Miren-Kostanjevica", - "J7" => "Novo Mesto", - "J9" => "Piran", - "K5" => "Preddvor", - "K7" => "Ptuj", - "L1" => "Ribnica", - "L3" => "Ruse", - "L7" => "Sentjur pri Celju", - "L8" => "Slovenska Bistrica", - "N2" => "Videm", - "N3" => "Vojnik", - "N5" => "Zalec"), -"SK" => array( - "01" => "Banska Bystrica", - "02" => "Bratislava", - "03" => "Kosice", - "04" => "Nitra", - "05" => "Presov", - "06" => "Trencin", - "07" => "Trnava", - "08" => "Zilina"), -"SL" => array( - "01" => "Eastern", - "02" => "Northern", - "03" => "Southern", - "04" => "Western Area"), -"SM" => array( - "01" => "Acquaviva", - "02" => "Chiesanuova", - "03" => "Domagnano", - "04" => "Faetano", - "05" => "Fiorentino", - "06" => "Borgo Maggiore", - "07" => "San Marino", - "08" => "Monte Giardino", - "09" => "Serravalle"), -"SN" => array( - "01" => "Dakar", - "03" => "Diourbel", - "05" => "Tambacounda", - "07" => "Thies", - "09" => "Fatick", - "10" => "Kaolack", - "11" => "Kolda", - "12" => "Ziguinchor", - "13" => "Louga", - "14" => "Saint-Louis", - "15" => "Matam"), -"SO" => array( - "01" => "Bakool", - "02" => "Banaadir", - "03" => "Bari", - "04" => "Bay", - "05" => "Galguduud", - "06" => "Gedo", - "07" => "Hiiraan", - "08" => "Jubbada Dhexe", - "09" => "Jubbada Hoose", - "10" => "Mudug", - "11" => "Nugaal", - "12" => "Sanaag", - "13" => "Shabeellaha Dhexe", - "14" => "Shabeellaha Hoose", - "16" => "Woqooyi Galbeed", - "18" => "Nugaal", - "19" => "Togdheer", - "20" => "Woqooyi Galbeed", - "21" => "Awdal", - "22" => "Sool"), -"SR" => array( - "10" => "Brokopondo", - "11" => "Commewijne", - "12" => "Coronie", - "13" => "Marowijne", - "14" => "Nickerie", - "15" => "Para", - "16" => "Paramaribo", - "17" => "Saramacca", - "18" => "Sipaliwini", - "19" => "Wanica"), -"ST" => array( - "01" => "Principe", - "02" => "Sao Tome"), -"SV" => array( - "01" => "Ahuachapan", - "02" => "Cabanas", - "03" => "Chalatenango", - "04" => "Cuscatlan", - "05" => "La Libertad", - "06" => "La Paz", - "07" => "La Union", - "08" => "Morazan", - "09" => "San Miguel", - "10" => "San Salvador", - "11" => "Santa Ana", - "12" => "San Vicente", - "13" => "Sonsonate", - "14" => "Usulutan"), -"SY" => array( - "01" => "Al Hasakah", - "02" => "Al Ladhiqiyah", - "03" => "Al Qunaytirah", - "04" => "Ar Raqqah", - "05" => "As Suwayda'", - "06" => "Dar", - "07" => "Dayr az Zawr", - "08" => "Rif Dimashq", - "09" => "Halab", - "10" => "Hamah", - "11" => "Hims", - "12" => "Idlib", - "13" => "Dimashq", - "14" => "Tartus"), -"SZ" => array( - "01" => "Hhohho", - "02" => "Lubombo", - "03" => "Manzini", - "04" => "Shiselweni", - "05" => "Praslin"), -"TD" => array( - "01" => "Batha", - "02" => "Biltine", - "03" => "Borkou-Ennedi-Tibesti", - "04" => "Chari-Baguirmi", - "05" => "Guera", - "06" => "Kanem", - "07" => "Lac", - "08" => "Logone Occidental", - "09" => "Logone Oriental", - "10" => "Mayo-Kebbi", - "11" => "Moyen-Chari", - "12" => "Ouaddai", - "13" => "Salamat", - "14" => "Tandjile"), -"TG" => array( - "22" => "Centrale", - "23" => "Kara", - "24" => "Maritime", - "25" => "Plateaux", - "26" => "Savanes"), -"TH" => array( - "01" => "Mae Hong Son", - "02" => "Chiang Mai", - "03" => "Chiang Rai", - "04" => "Nan", - "05" => "Lamphun", - "06" => "Lampang", - "07" => "Phrae", - "08" => "Tak", - "09" => "Sukhothai", - "10" => "Uttaradit", - "11" => "Kamphaeng Phet", - "12" => "Phitsanulok", - "13" => "Phichit", - "14" => "Phetchabun", - "15" => "Uthai Thani", - "16" => "Nakhon Sawan", - "17" => "Nong Khai", - "18" => "Loei", - "20" => "Sakon Nakhon", - "21" => "Nakhon Phanom", - "22" => "Khon Kaen", - "23" => "Kalasin", - "24" => "Maha Sarakham", - "25" => "Roi Et", - "26" => "Chaiyaphum", - "27" => "Nakhon Ratchasima", - "28" => "Buriram", - "29" => "Surin", - "30" => "Sisaket", - "31" => "Narathiwat", - "32" => "Chai Nat", - "33" => "Sing Buri", - "34" => "Lop Buri", - "35" => "Ang Thong", - "36" => "Phra Nakhon Si Ayutthaya", - "37" => "Saraburi", - "38" => "Nonthaburi", - "39" => "Pathum Thani", - "40" => "Krung Thep", - "41" => "Phayao", - "42" => "Samut Prakan", - "43" => "Nakhon Nayok", - "44" => "Chachoengsao", - "45" => "Prachin Buri", - "46" => "Chon Buri", - "47" => "Rayong", - "48" => "Chanthaburi", - "49" => "Trat", - "50" => "Kanchanaburi", - "51" => "Suphan Buri", - "52" => "Ratchaburi", - "53" => "Nakhon Pathom", - "54" => "Samut Songkhram", - "55" => "Samut Sakhon", - "56" => "Phetchaburi", - "57" => "Prachuap Khiri Khan", - "58" => "Chumphon", - "59" => "Ranong", - "60" => "Surat Thani", - "61" => "Phangnga", - "62" => "Phuket", - "63" => "Krabi", - "64" => "Nakhon Si Thammarat", - "65" => "Trang", - "66" => "Phatthalung", - "67" => "Satun", - "68" => "Songkhla", - "69" => "Pattani", - "70" => "Yala", - "71" => "Ubon Ratchathani", - "72" => "Yasothon", - "73" => "Nakhon Phanom", - "75" => "Ubon Ratchathani", - "76" => "Udon Thani", - "77" => "Amnat Charoen", - "78" => "Mukdahan", - "79" => "Nong Bua Lamphu", - "80" => "Sa Kaeo"), -"TJ" => array( - "01" => "Kuhistoni Badakhshon", - "02" => "Khatlon", - "03" => "Sughd"), -"TM" => array( - "01" => "Ahal", - "02" => "Balkan", - "03" => "Dashoguz", - "04" => "Lebap", - "05" => "Mary"), -"TN" => array( - "02" => "Kasserine", - "03" => "Kairouan", - "06" => "Jendouba", - "10" => "Qafsah", - "14" => "El Kef", - "15" => "Al Mahdia", - "16" => "Al Munastir", - "17" => "Bajah", - "18" => "Bizerte", - "19" => "Nabeul", - "22" => "Siliana", - "23" => "Sousse", - "27" => "Ben Arous", - "28" => "Madanin", - "29" => "Gabes", - "31" => "Kebili", - "32" => "Sfax", - "33" => "Sidi Bou Zid", - "34" => "Tataouine", - "35" => "Tozeur", - "36" => "Tunis", - "37" => "Zaghouan", - "38" => "Aiana", - "39" => "Manouba"), -"TO" => array( - "01" => "Ha", - "02" => "Tongatapu", - "03" => "Vava"), -"TR" => array( - "02" => "Adiyaman", - "03" => "Afyonkarahisar", - "04" => "Agri", - "05" => "Amasya", - "07" => "Antalya", - "08" => "Artvin", - "09" => "Aydin", - "10" => "Balikesir", - "11" => "Bilecik", - "12" => "Bingol", - "13" => "Bitlis", - "14" => "Bolu", - "15" => "Burdur", - "16" => "Bursa", - "17" => "Canakkale", - "19" => "Corum", - "20" => "Denizli", - "21" => "Diyarbakir", - "22" => "Edirne", - "23" => "Elazig", - "24" => "Erzincan", - "25" => "Erzurum", - "26" => "Eskisehir", - "28" => "Giresun", - "31" => "Hatay", - "32" => "Mersin", - "33" => "Isparta", - "34" => "Istanbul", - "35" => "Izmir", - "37" => "Kastamonu", - "38" => "Kayseri", - "39" => "Kirklareli", - "40" => "Kirsehir", - "41" => "Kocaeli", - "43" => "Kutahya", - "44" => "Malatya", - "45" => "Manisa", - "46" => "Kahramanmaras", - "48" => "Mugla", - "49" => "Mus", - "50" => "Nevsehir", - "52" => "Ordu", - "53" => "Rize", - "54" => "Sakarya", - "55" => "Samsun", - "57" => "Sinop", - "58" => "Sivas", - "59" => "Tekirdag", - "60" => "Tokat", - "61" => "Trabzon", - "62" => "Tunceli", - "63" => "Sanliurfa", - "64" => "Usak", - "65" => "Van", - "66" => "Yozgat", - "68" => "Ankara", - "69" => "Gumushane", - "70" => "Hakkari", - "71" => "Konya", - "72" => "Mardin", - "73" => "Nigde", - "74" => "Siirt", - "75" => "Aksaray", - "76" => "Batman", - "77" => "Bayburt", - "78" => "Karaman", - "79" => "Kirikkale", - "80" => "Sirnak", - "81" => "Adana", - "82" => "Cankiri", - "83" => "Gaziantep", - "84" => "Kars", - "85" => "Zonguldak", - "86" => "Ardahan", - "87" => "Bartin", - "88" => "Igdir", - "89" => "Karabuk", - "90" => "Kilis", - "91" => "Osmaniye", - "92" => "Yalova", - "93" => "Duzce"), -"TT" => array( - "01" => "Arima", - "02" => "Caroni", - "03" => "Mayaro", - "04" => "Nariva", - "05" => "Port-of-Spain", - "06" => "Saint Andrew", - "07" => "Saint David", - "08" => "Saint George", - "09" => "Saint Patrick", - "10" => "San Fernando", - "11" => "Tobago", - "12" => "Victoria"), -"TW" => array( - "01" => "Fu-chien", - "02" => "Kao-hsiung", - "03" => "T'ai-pei", - "04" => "T'ai-wan"), -"TZ" => array( - "02" => "Pwani", - "03" => "Dodoma", - "04" => "Iringa", - "05" => "Kigoma", - "06" => "Kilimanjaro", - "07" => "Lindi", - "08" => "Mara", - "09" => "Mbeya", - "10" => "Morogoro", - "11" => "Mtwara", - "12" => "Mwanza", - "13" => "Pemba North", - "14" => "Ruvuma", - "15" => "Shinyanga", - "16" => "Singida", - "17" => "Tabora", - "18" => "Tanga", - "19" => "Kagera", - "20" => "Pemba South", - "21" => "Zanzibar Central", - "22" => "Zanzibar North", - "23" => "Dar es Salaam", - "24" => "Rukwa", - "25" => "Zanzibar Urban", - "26" => "Arusha", - "27" => "Manyara"), -"UA" => array( - "01" => "Cherkas'ka Oblast'", - "02" => "Chernihivs'ka Oblast'", - "03" => "Chernivets'ka Oblast'", - "04" => "Dnipropetrovs'ka Oblast'", - "05" => "Donets'ka Oblast'", - "06" => "Ivano-Frankivs'ka Oblast'", - "07" => "Kharkivs'ka Oblast'", - "08" => "Khersons'ka Oblast'", - "09" => "Khmel'nyts'ka Oblast'", - "10" => "Kirovohrads'ka Oblast'", - "11" => "Krym", - "12" => "Kyyiv", - "13" => "Kyyivs'ka Oblast'", - "14" => "Luhans'ka Oblast'", - "15" => "L'vivs'ka Oblast'", - "16" => "Mykolayivs'ka Oblast'", - "17" => "Odes'ka Oblast'", - "18" => "Poltavs'ka Oblast'", - "19" => "Rivnens'ka Oblast'", - "20" => "Sevastopol'", - "21" => "Sums'ka Oblast'", - "22" => "Ternopil's'ka Oblast'", - "23" => "Vinnyts'ka Oblast'", - "24" => "Volyns'ka Oblast'", - "25" => "Zakarpats'ka Oblast'", - "26" => "Zaporiz'ka Oblast'", - "27" => "Zhytomyrs'ka Oblast'"), -"UG" => array( - "26" => "Apac", - "28" => "Bundibugyo", - "29" => "Bushenyi", - "30" => "Gulu", - "31" => "Hoima", - "33" => "Jinja", - "36" => "Kalangala", - "37" => "Kampala", - "38" => "Kamuli", - "39" => "Kapchorwa", - "40" => "Kasese", - "41" => "Kibale", - "42" => "Kiboga", - "43" => "Kisoro", - "45" => "Kotido", - "46" => "Kumi", - "47" => "Lira", - "50" => "Masindi", - "52" => "Mbarara", - "56" => "Mubende", - "58" => "Nebbi", - "59" => "Ntungamo", - "60" => "Pallisa", - "61" => "Rakai", - "65" => "Adjumani", - "66" => "Bugiri", - "67" => "Busia", - "69" => "Katakwi", - "70" => "Luwero", - "71" => "Masaka", - "72" => "Moyo", - "73" => "Nakasongola", - "74" => "Sembabule", - "76" => "Tororo", - "77" => "Arua", - "78" => "Iganga", - "79" => "Kabarole", - "80" => "Kaberamaido", - "81" => "Kamwenge", - "82" => "Kanungu", - "83" => "Kayunga", - "84" => "Kitgum", - "85" => "Kyenjojo", - "86" => "Mayuge", - "87" => "Mbale", - "88" => "Moroto", - "89" => "Mpigi", - "90" => "Mukono", - "91" => "Nakapiripirit", - "92" => "Pader", - "93" => "Rukungiri", - "94" => "Sironko", - "95" => "Soroti", - "96" => "Wakiso", - "97" => "Yumbe"), -"US" => array( - "AA" => "Armed Forces Americas", - "AE" => "Armed Forces Europe, Middle East, & Canada", - "AK" => "Alaska", - "AL" => "Alabama", - "AP" => "Armed Forces Pacific", - "AR" => "Arkansas", - "AS" => "American Samoa", - "AZ" => "Arizona", - "CA" => "California", - "CO" => "Colorado", - "CT" => "Connecticut", - "DC" => "District of Columbia", - "DE" => "Delaware", - "FL" => "Florida", - "FM" => "Federated States of Micronesia", - "GA" => "Georgia", - "GU" => "Guam", - "HI" => "Hawaii", - "IA" => "Iowa", - "ID" => "Idaho", - "IL" => "Illinois", - "IN" => "Indiana", - "KS" => "Kansas", - "KY" => "Kentucky", - "LA" => "Louisiana", - "MA" => "Massachusetts", - "MD" => "Maryland", - "ME" => "Maine", - "MH" => "Marshall Islands", - "MI" => "Michigan", - "MN" => "Minnesota", - "MO" => "Missouri", - "MP" => "Northern Mariana Islands", - "MS" => "Mississippi", - "MT" => "Montana", - "NC" => "North Carolina", - "ND" => "North Dakota", - "NE" => "Nebraska", - "NH" => "New Hampshire", - "NJ" => "New Jersey", - "NM" => "New Mexico", - "NV" => "Nevada", - "NY" => "New York", - "OH" => "Ohio", - "OK" => "Oklahoma", - "OR" => "Oregon", - "PA" => "Pennsylvania", - "PR" => "Puerto Rico", - "PW" => "Palau", - "RI" => "Rhode Island", - "SC" => "South Carolina", - "SD" => "South Dakota", - "TN" => "Tennessee", - "TX" => "Texas", - "UT" => "Utah", - "VA" => "Virginia", - "VI" => "Virgin Islands", - "VT" => "Vermont", - "WA" => "Washington", - "WI" => "Wisconsin", - "WV" => "West Virginia", - "WY" => "Wyoming"), -"UY" => array( - "01" => "Artigas", - "02" => "Canelones", - "03" => "Cerro Largo", - "04" => "Colonia", - "05" => "Durazno", - "06" => "Flores", - "07" => "Florida", - "08" => "Lavalleja", - "09" => "Maldonado", - "10" => "Montevideo", - "11" => "Paysandu", - "12" => "Rio Negro", - "13" => "Rivera", - "14" => "Rocha", - "15" => "Salto", - "16" => "San Jose", - "17" => "Soriano", - "18" => "Tacuarembo", - "19" => "Treinta y Tres"), -"UZ" => array( - "01" => "Andijon", - "02" => "Bukhoro", - "03" => "Farghona", - "04" => "Jizzakh", - "05" => "Khorazm", - "06" => "Namangan", - "07" => "Nawoiy", - "08" => "Qashqadaryo", - "09" => "Qoraqalpoghiston", - "10" => "Samarqand", - "11" => "Sirdaryo", - "12" => "Surkhondaryo", - "13" => "Toshkent", - "14" => "Toshkent"), -"VC" => array( - "01" => "Charlotte", - "02" => "Saint Andrew", - "03" => "Saint David", - "04" => "Saint George", - "05" => "Saint Patrick", - "06" => "Grenadines"), -"VE" => array( - "01" => "Amazonas", - "02" => "Anzoategui", - "03" => "Apure", - "04" => "Aragua", - "05" => "Barinas", - "06" => "Bolivar", - "07" => "Carabobo", - "08" => "Cojedes", - "09" => "Delta Amacuro", - "11" => "Falcon", - "12" => "Guarico", - "13" => "Lara", - "14" => "Merida", - "15" => "Miranda", - "16" => "Monagas", - "17" => "Nueva Esparta", - "18" => "Portuguesa", - "19" => "Sucre", - "20" => "Tachira", - "21" => "Trujillo", - "22" => "Yaracuy", - "23" => "Zulia", - "24" => "Dependencias Federales", - "25" => "Distrito Federal", - "26" => "Vargas"), -"VN" => array( - "01" => "An Giang", - "03" => "Ben Tre", - "05" => "Cao Bang", - "09" => "Dong Thap", - "13" => "Hai Phong", - "20" => "Ho Chi Minh", - "21" => "Kien Giang", - "23" => "Lam Dong", - "24" => "Long An", - "30" => "Quang Ninh", - "32" => "Son La", - "33" => "Tay Ninh", - "34" => "Thanh Hoa", - "35" => "Thai Binh", - "37" => "Tien Giang", - "39" => "Lang Son", - "43" => "An Giang", - "44" => "Dac Lac", - "45" => "Dong Nai", - "46" => "Dong Thap", - "47" => "Kien Giang", - "49" => "Song Be", - "50" => "Vinh Phu", - "51" => "Ha Noi", - "52" => "Ho Chi Minh", - "53" => "Ba Ria-Vung Tau", - "54" => "Binh Dinh", - "55" => "Binh Thuan", - "58" => "Ha Giang", - "59" => "Ha Tay", - "60" => "Ha Tinh", - "61" => "Hoa Binh", - "62" => "Khanh Hoa", - "63" => "Kon Tum", - "64" => "Quang Tri", - "65" => "Nam Ha", - "66" => "Nghe An", - "67" => "Ninh Binh", - "68" => "Ninh Thuan", - "69" => "Phu Yen", - "70" => "Quang Binh", - "71" => "Quang Ngai", - "72" => "Quang Tri", - "73" => "Soc Trang", - "74" => "Thua Thien", - "75" => "Tra Vinh", - "76" => "Tuyen Quang", - "77" => "Vinh Long", - "78" => "Da Nang", - "79" => "Hai Duong", - "80" => "Ha Nam", - "81" => "Hung Yen", - "82" => "Nam Dinh", - "83" => "Phu Tho", - "84" => "Quang Nam", - "85" => "Thai Nguyen", - "86" => "Vinh Puc Province", - "87" => "Can Tho", - "88" => "Dak Lak", - "89" => "Lai Chau", - "90" => "Lao Cai", - "91" => "Dak Nong", - "92" => "Dien Bien", - "93" => "Hau Giang"), -"VU" => array( - "05" => "Ambrym", - "06" => "Aoba", - "07" => "Torba", - "08" => "Efate", - "09" => "Epi", - "10" => "Malakula", - "11" => "Paama", - "12" => "Pentecote", - "13" => "Sanma", - "14" => "Shepherd", - "15" => "Tafea", - "16" => "Malampa", - "17" => "Penama", - "18" => "Shefa"), -"WS" => array( - "02" => "Aiga-i-le-Tai", - "03" => "Atua", - "04" => "Fa", - "05" => "Gaga", - "06" => "Va", - "07" => "Gagaifomauga", - "08" => "Palauli", - "09" => "Satupa", - "10" => "Tuamasaga", - "11" => "Vaisigano"), -"YE" => array( - "01" => "Abyan", - "02" => "Adan", - "03" => "Al Mahrah", - "04" => "Hadramawt", - "05" => "Shabwah", - "06" => "Lahij", - "07" => "Al Bayda'", - "08" => "Al Hudaydah", - "09" => "Al Jawf", - "10" => "Al Mahwit", - "11" => "Dhamar", - "12" => "Hajjah", - "13" => "Ibb", - "14" => "Ma'rib", - "15" => "Sa'dah", - "16" => "San'a'", - "17" => "Taizz", - "18" => "Ad Dali", - "19" => "Amran", - "20" => "Al Bayda'", - "21" => "Al Jawf", - "22" => "Hajjah", - "23" => "Ibb", - "24" => "Lahij", - "25" => "Taizz"), -"ZA" => array( - "01" => "North-Western Province", - "02" => "KwaZulu-Natal", - "03" => "Free State", - "05" => "Eastern Cape", - "06" => "Gauteng", - "07" => "Mpumalanga", - "08" => "Northern Cape", - "09" => "Limpopo", - "10" => "North-West", - "11" => "Western Cape"), -"ZM" => array( - "01" => "Western", - "02" => "Central", - "03" => "Eastern", - "04" => "Luapula", - "05" => "Northern", - "06" => "North-Western", - "07" => "Southern", - "08" => "Copperbelt", - "09" => "Lusaka"), -"ZW" => array( - "01" => "Manicaland", - "02" => "Midlands", - "03" => "Mashonaland Central", - "04" => "Mashonaland East", - "05" => "Mashonaland West", - "06" => "Matabeleland North", - "07" => "Matabeleland South", - "08" => "Masvingo", - "09" => "Bulawayo", - "10" => "Harare") -); diff --git a/tools/geoip/index.php b/tools/geoip/index.php index df55e1000..d9925ba54 100644 --- a/tools/geoip/index.php +++ b/tools/geoip/index.php @@ -1,35 +1,29 @@ -* @copyright 2007-2017 PrestaShop SA -* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) -* International Registered Trademark & Property of PrestaShop SA +* @author Webkul IN +* @copyright 2010-2021 Webkul IN +* @license https://store.webkul.com/license.html */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); + +header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); + +header('Cache-Control: no-store, no-cache, must-revalidate'); +header('Cache-Control: post-check=0, pre-check=0', false); +header('Pragma: no-cache'); + +header('Location: ../'); exit; diff --git a/tools/geoip/maxmind-db/reader/CHANGELOG.md b/tools/geoip/maxmind-db/reader/CHANGELOG.md new file mode 100644 index 000000000..40d89d42e --- /dev/null +++ b/tools/geoip/maxmind-db/reader/CHANGELOG.md @@ -0,0 +1,244 @@ +CHANGELOG +========= + +1.12.0 (2024-11-14) +------------------- + +* Improve the error handling when the user tries to open a directory + with the pure PHP reader. +* Improve the typehints on arrays in the PHPDocs. + +1.11.1 (2023-12-01) +------------------- + +* Resolve warnings when compiling the C extension. +* Fix various type issues detected by PHPStan level. Pull request by + LauraTaylorUK. GitHub #160. + +1.11.0 (2021-10-18) +------------------- + +* Replace runtime define of a constant to facilitate opcache preloading. + Reported by vedadkajtaz. GitHub #134. +* Resolve minor issue found by the Clang static analyzer in the C + extension. + +1.10.1 (2021-04-14) +------------------- + +* Fix a `TypeError` exception in the pure PHP reader when using large + databases on 32-bit PHP builds with the `bcmath` extension. Reported + by dodo1708. GitHub #124. + +1.10.0 (2021-02-09) +------------------- + +* When using the pure PHP reader, unsigned integers up to PHP_MAX_INT + will now be integers in PHP rather than strings. Previously integers + greater than 2^24 on 32-bit platforms and 2^56 on 64-bit platforms + would be strings due to the use of `gmp` or `bcmath` to decode them. + Reported by Alejandro Celaya. GitHub #119. + +1.9.0 (2021-01-07) +------------------ + +* The `maxminddb` extension is now buildable on Windows. Pull request + by Jan Ehrhardt. GitHub #115. + +1.8.0 (2020-10-01) +------------------ + +* Fixes for PHP 8.0. Pull Request by Remi Collet. GitHub #108. + +1.7.0 (2020-08-07) +------------------ + +* IMPORTANT: PHP 7.2 or greater is now required. +* The extension no longer depends on the pure PHP classes in + `maxmind-db/reader`. You can use it independently. +* Type hints have been added to both the pure PHP implementation + and the extension. +* The `metadata` method on the reader now returns a new copy of the + metadata object rather than the actual object used by the reader. +* Work around PHP `is_readable()` bug. Reported by Ben Roberts. GitHub + #92. +* This is the first release of the extension as a PECL package. + GitHub #34. + +1.6.0 (2019-12-19) +------------------ + +* 1.5.0 and 1.5.1 contained a possible memory corruptions when using + `getWithPrefixLen`. This has been fixed. Reported by proton-ab. + GitHub #96. +* The `composer.json` file now conflicts with all versions of the + `maxminddb` C extension less than the Composer version. This is to + reduce the chance of having an older, conflicting version of the + extension installed. You will need to upgrade the extension before + running `composer update`. Pull request by Benoît Burnichon. GitHub + #97. + +1.5.1 (2019-12-12) +------------------ + +* Minor performance improvements. +* Make tests pass with older versions of libmaxminddb. PR by Remi + Collet. GitHub #90. +* Test enhancements. PR by Chun-Sheng, Li. GitHub #91. + +1.5.0 (2019-09-30) +------------------ + +* PHP 5.6 or greater is now required. +* The C extension now supports PHP 8. Pull request by John Boehr. + GitHub #87. +* A new method, `getWithPrefixLen`, was added to the `Reader` class. + This method returns an array containing the record and the prefix + length for that record. GitHub #89. + +1.4.1 (2019-01-04) +------------------ + +* The `maxminddb` extension now returns a string when a `uint32` + value is greater than `LONG_MAX`. Previously, the value would + overflow. This generally only affects 32-bit machines. Reported + by Remi Collet. GitHub #79. +* For `uint64` values, the `maxminddb` extension now returns an + integer rather than a string when the value is less than or equal + to `LONG_MAX`. This more closely matches the behavior of the pure + PHP reader. + +1.4.0 (2018-11-20) +------------------ + +* The `maxminddb` extension now has the arginfo when using reflection. + PR by Remi Collet. GitHub #75. +* The `maxminddb` extension now provides `MINFO()` function that + displays the extension version and the libmaxminddb version. PR by + Remi Collet. GitHub #74. +* The `maxminddb` `configure` script now uses `pkg-config` when + available to get libmaxmindb build info. PR by Remi Collet. + GitHub #73. +* The pure PHP reader now correctly decodes integers on 32-bit platforms. + Previously, large integers would overflow. Reported by Remi Collet. + GitHub #77. +* There are small performance improvements for the pure PHP reader. + +1.3.0 (2018-02-21) +------------------ + +* IMPORTANT: The `maxminddb` extension now obeys `open_basedir`. If + `open_basedir` is set, you _must_ store the database within the + specified directory. Placing the file outside of this directory + will result in an exception. Please test your integration before + upgrading the extension. This does not affect the pure PHP + implementation, which has always had this restriction. Reported + by Benoît Burnichon. GitHub #61. +* A custom `autoload.php` file is provided for installations without + Composer. GitHub #56. + +1.2.0 (2017-10-27) +------------------ + +* PHP 5.4 or greater is now required. +* The `Reader` class for the `maxminddb` extension is no longer final. + This was change to match the behavior of the pure PHP class. + Reported and fixed by venyii. GitHub #52 & #54. + +1.1.3 (2017-01-19) +------------------ + +* Fix incorrect version in `ext/php_maxminddb.h`. GitHub #48. + +1.1.2 (2016-11-22) +------------------ + +* Searching for database metadata only occurs within the last 128KB + (128 * 1024 bytes) of the file, speeding detection of corrupt + datafiles. Reported by Eric Teubert. GitHub #42. +* Suggest relevant extensions when installing with Composer. GitHub #37. + +1.1.1 (2016-09-15) +------------------ + +* Development files were added to the `.gitattributes` as `export-ignore` so + that they are not part of the Composer release. Pull request by Michele + Locati. GitHub #39. + +1.1.0 (2016-01-04) +------------------ + +* The MaxMind DB extension now supports PHP 7. Pull request by John Boehr. + GitHub #27. + +1.0.3 (2015-03-13) +------------------ + +* All uses of `strlen` were removed. This should prevent issues in situations + where the function is overloaded or otherwise broken. + +1.0.2 (2015-01-19) +------------------ + +* Previously the MaxMind DB extension would cause a segfault if the Reader + object's destructor was called without first having called the constructor. + (Reported by Matthias Saou & Juan Peri. GitHub #20.) + +1.0.1 (2015-01-12) +------------------ + +* In the last several releases, the version number in the extension was + incorrect. This release is being done to correct it. No other code changes + are included. + +1.0.0 (2014-09-22) +------------------ + +* First production release. +* In the pure PHP reader, a string length test after `fread()` was replaced + with the difference between the start pointer and the end pointer. This + provided a 15% speed increase. + +0.3.3 (2014-09-15) +------------------ + +* Clarified behavior of 128-bit type in documentation. +* Updated phpunit and fixed some test breakage from the newer version. + +0.3.2 (2014-09-10) +------------------ + +* Fixed invalid reference to global class RuntimeException from namespaced + code. Fixed by Steven Don. GitHub issue #15. +* Additional documentation of `Metadata` class as well as misc. documentation + cleanup. + +0.3.1 (2014-05-01) +------------------ + +* The API now works when `mbstring.func_overload` is set. +* BCMath is no longer required. If the decoder encounters a big integer, + it will try to use GMP and then BCMath. If both of those fail, it will + throw an exception. No databases released by MaxMind currently use big + integers. +* The API now officially supports HHVM when using the pure PHP reader. + +0.3.0 (2014-02-19) +------------------ + +* This API is now licensed under the Apache License, Version 2.0. +* The code for the C extension was cleaned up, fixing several potential + issues. + +0.2.0 (2013-10-21) +------------------ + +* Added optional C extension for using libmaxminddb in place of the pure PHP + reader. +* Significantly improved error handling in pure PHP reader. +* Improved performance for IPv4 lookups in an IPv6 database. + +0.1.0 (2013-07-16) +------------------ + +* Initial release diff --git a/tools/geoip/maxmind-db/reader/LICENSE b/tools/geoip/maxmind-db/reader/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/tools/geoip/maxmind-db/reader/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/tools/geoip/maxmind-db/reader/README.md b/tools/geoip/maxmind-db/reader/README.md new file mode 100644 index 000000000..afefc3fd1 --- /dev/null +++ b/tools/geoip/maxmind-db/reader/README.md @@ -0,0 +1,185 @@ +# MaxMind DB Reader PHP API # + +## Description ## + +This is the PHP API for reading MaxMind DB files. MaxMind DB is a binary file +format that stores data indexed by IP address subnets (IPv4 or IPv6). + +## Installation (Composer) ## + +We recommend installing this package with [Composer](https://getcomposer.org/). + +### Download Composer ### + +To download Composer, run in the root directory of your project: + +```bash +curl -sS https://getcomposer.org/installer | php +``` + +You should now have the file `composer.phar` in your project directory. + +### Install Dependencies ### + +Run in your project root: + +``` +php composer.phar require maxmind-db/reader:~1.0 +``` + +You should now have the files `composer.json` and `composer.lock` as well as +the directory `vendor` in your project directory. If you use a version control +system, `composer.json` should be added to it. + +### Require Autoloader ### + +After installing the dependencies, you need to require the Composer autoloader +from your code: + +```php +require 'vendor/autoload.php'; +``` + +## Installation (Standalone) ## + +If you don't want to use Composer for some reason, a custom +`autoload.php` is provided for you in the project root. To use the +library, simply include that file, + +```php +require('/path/to/MaxMind-DB-Reader-php/autoload.php'); +``` + +and then instantiate the reader class normally: + +```php +use MaxMind\Db\Reader; +$reader = new Reader('example.mmdb'); +``` + +## Installation (RPM) + +RPMs are available in the [official Fedora repository](https://apps.fedoraproject.org/packages/php-maxminddb). + +To install on Fedora, run: + +```bash +dnf install php-maxminddb +``` + +To install on CentOS or RHEL 7, first [enable the EPEL repository](https://fedoraproject.org/wiki/EPEL) +and then run: + +```bash +yum install php-maxminddb +``` + +Please note that these packages are *not* maintained by MaxMind. + +## Usage ## + +## Example ## + +```php +get($ipAddress)); + +// getWithPrefixLen returns an array containing the record and the +// associated prefix length for that record. +print_r($reader->getWithPrefixLen($ipAddress)); + +$reader->close(); +``` + +## Optional PHP C Extension ## + +MaxMind provides an optional C extension that is a drop-in replacement for +`MaxMind\Db\Reader`. In order to use this extension, you must install the +Reader API as described above and install the extension as described below. If +you are using an autoloader, no changes to your code should be necessary. + +### Installing Extension ### + +First install [libmaxminddb](https://github.com/maxmind/libmaxminddb) as +described in its [README.md +file](https://github.com/maxmind/libmaxminddb/blob/main/README.md#installing-from-a-tarball). +After successfully installing libmaxmindb, you may install the extension +from [pecl](https://pecl.php.net/package/maxminddb): + +``` +pecl install maxminddb +``` + +Alternatively, you may install it from the source. To do so, run the following +commands from the top-level directory of this distribution: + +``` +cd ext +phpize +./configure +make +make test +sudo make install +``` + +You then must load your extension. The recommended method is to add the +following to your `php.ini` file: + +``` +extension=maxminddb.so +``` + +Note: You may need to install the PHP development package on your OS such as +php5-dev for Debian-based systems or php-devel for RedHat/Fedora-based ones. + +## 128-bit Integer Support ## + +The MaxMind DB format includes 128-bit unsigned integer as a type. Although +no MaxMind-distributed database currently makes use of this type, both the +pure PHP reader and the C extension support this type. The pure PHP reader +requires gmp or bcmath to read databases with 128-bit unsigned integers. + +The integer is currently returned as a hexadecimal string (prefixed with "0x") +by the C extension and a decimal string (no prefix) by the pure PHP reader. +Any change to make the reader implementations always return either a +hexadecimal or decimal representation of the integer will NOT be considered a +breaking change. + +## Support ## + +Please report all issues with this code using the [GitHub issue tracker](https://github.com/maxmind/MaxMind-DB-Reader-php/issues). + +If you are having an issue with a MaxMind service that is not specific to the +client API, please see [our support page](https://www.maxmind.com/en/support). + +## Requirements ## + +This library requires PHP 7.2 or greater. + +The GMP or BCMath extension may be required to read some databases +using the pure PHP API. + +## Contributing ## + +Patches and pull requests are encouraged. All code should follow the PSR-1 and +PSR-2 style guidelines. Please include unit tests whenever possible. + +## Versioning ## + +The MaxMind DB Reader PHP API uses [Semantic Versioning](https://semver.org/). + +## Copyright and License ## + +This software is Copyright (c) 2014-2024 by MaxMind, Inc. + +This is free software, licensed under the Apache License, Version 2.0. diff --git a/tools/geoip/maxmind-db/reader/autoload.php b/tools/geoip/maxmind-db/reader/autoload.php new file mode 100644 index 000000000..fdd2f1cb3 --- /dev/null +++ b/tools/geoip/maxmind-db/reader/autoload.php @@ -0,0 +1,47 @@ +class. + * + * @param string $class + * the name of the class to load + */ +function mmdb_autoload($class): void +{ + /* + * A project-specific mapping between the namespaces and where + * they're located. By convention, we include the trailing + * slashes. The one-element array here simply makes things easy + * to extend in the future if (for example) the test classes + * begin to use one another. + */ + $namespace_map = ['MaxMind\Db\\' => __DIR__ . '/src/MaxMind/Db/']; + + foreach ($namespace_map as $prefix => $dir) { + // First swap out the namespace prefix with a directory... + $path = str_replace($prefix, $dir, $class); + + // replace the namespace separator with a directory separator... + $path = str_replace('\\', '/', $path); + + // and finally, add the PHP file extension to the result. + $path .= '.php'; + + // $path should now contain the path to a PHP file defining $class + if (file_exists($path)) { + include $path; + } + } +} + +spl_autoload_register('mmdb_autoload'); diff --git a/tools/geoip/maxmind-db/reader/composer.json b/tools/geoip/maxmind-db/reader/composer.json new file mode 100644 index 000000000..c9cc524e2 --- /dev/null +++ b/tools/geoip/maxmind-db/reader/composer.json @@ -0,0 +1,42 @@ +{ + "name": "maxmind-db/reader", + "description": "MaxMind DB Reader API", + "keywords": ["database", "geoip", "geoip2", "geolocation", "maxmind"], + "homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php", + "type": "library", + "license": "Apache-2.0", + "authors": [ + { + "name": "Gregory J. Oschwald", + "email": "goschwald@maxmind.com", + "homepage": "https://www.maxmind.com/" + } + ], + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", + "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", + "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups" + }, + "conflict": { + "ext-maxminddb": "<1.11.1 || >=2.0.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "phpunit/phpunit": ">=8.0.0,<10.0.0", + "squizlabs/php_codesniffer": "3.*", + "phpstan/phpstan": "*" + }, + "autoload": { + "psr-4": { + "MaxMind\\Db\\": "src/MaxMind/Db" + } + }, + "autoload-dev": { + "psr-4": { + "MaxMind\\Db\\Test\\Reader\\": "tests/MaxMind/Db/Test/Reader" + } + } +} diff --git a/tools/geoip/maxmind-db/reader/ext/config.m4 b/tools/geoip/maxmind-db/reader/ext/config.m4 new file mode 100644 index 000000000..c09151e4e --- /dev/null +++ b/tools/geoip/maxmind-db/reader/ext/config.m4 @@ -0,0 +1,40 @@ +PHP_ARG_WITH(maxminddb, + [Whether to enable the MaxMind DB Reader extension], + [ --with-maxminddb Enable MaxMind DB Reader extension support]) + +PHP_ARG_ENABLE(maxminddb-debug, for MaxMind DB debug support, + [ --enable-maxminddb-debug Enable MaxMind DB debug support], no, no) + +if test $PHP_MAXMINDDB != "no"; then + + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + + AC_MSG_CHECKING(for libmaxminddb) + if test -x "$PKG_CONFIG" && $PKG_CONFIG --exists libmaxminddb; then + dnl retrieve build options from pkg-config + if $PKG_CONFIG libmaxminddb --atleast-version 1.0.0; then + LIBMAXMINDDB_INC=`$PKG_CONFIG libmaxminddb --cflags` + LIBMAXMINDDB_LIB=`$PKG_CONFIG libmaxminddb --libs` + LIBMAXMINDDB_VER=`$PKG_CONFIG libmaxminddb --modversion` + AC_MSG_RESULT(found version $LIBMAXMINDDB_VER) + else + AC_MSG_ERROR(system libmaxminddb must be upgraded to version >= 1.0.0) + fi + PHP_EVAL_LIBLINE($LIBMAXMINDDB_LIB, MAXMINDDB_SHARED_LIBADD) + PHP_EVAL_INCLINE($LIBMAXMINDDB_INC) + else + AC_MSG_RESULT(pkg-config information missing) + AC_MSG_WARN(will use libmaxmxinddb from compiler default path) + + PHP_CHECK_LIBRARY(maxminddb, MMDB_open) + PHP_ADD_LIBRARY(maxminddb, 1, MAXMINDDB_SHARED_LIBADD) + fi + + if test $PHP_MAXMINDDB_DEBUG != "no"; then + CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Werror" + fi + + PHP_SUBST(MAXMINDDB_SHARED_LIBADD) + + PHP_NEW_EXTENSION(maxminddb, maxminddb.c, $ext_shared) +fi diff --git a/tools/geoip/maxmind-db/reader/ext/config.w32 b/tools/geoip/maxmind-db/reader/ext/config.w32 new file mode 100644 index 000000000..4eb18f849 --- /dev/null +++ b/tools/geoip/maxmind-db/reader/ext/config.w32 @@ -0,0 +1,10 @@ +ARG_WITH("maxminddb", "Enable MaxMind DB Reader extension support", "no"); + +if (PHP_MAXMINDDB == "yes") { + if (CHECK_HEADER_ADD_INCLUDE("maxminddb.h", "CFLAGS_MAXMINDDB", PHP_MAXMINDDB + ";" + PHP_PHP_BUILD + "\\include\\maxminddb") && + CHECK_LIB("libmaxminddb.lib", "maxminddb", PHP_MAXMINDDB)) { + EXTENSION("maxminddb", "maxminddb.c"); + } else { + WARNING('Could not find maxminddb.h or libmaxminddb.lib; skipping'); + } +} diff --git a/tools/geoip/maxmind-db/reader/ext/maxminddb.c b/tools/geoip/maxmind-db/reader/ext/maxminddb.c new file mode 100644 index 000000000..20e2bbf97 --- /dev/null +++ b/tools/geoip/maxmind-db/reader/ext/maxminddb.c @@ -0,0 +1,811 @@ +/* MaxMind, Inc., licenses this file to you under the Apache License, Version + * 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +#include "php_maxminddb.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "Zend/zend_exceptions.h" +#include "Zend/zend_types.h" +#include "ext/spl/spl_exceptions.h" +#include "ext/standard/info.h" +#include + +#ifdef ZTS +#include +#endif + +#define __STDC_FORMAT_MACROS +#include + +#define PHP_MAXMINDDB_NS ZEND_NS_NAME("MaxMind", "Db") +#define PHP_MAXMINDDB_READER_NS ZEND_NS_NAME(PHP_MAXMINDDB_NS, "Reader") +#define PHP_MAXMINDDB_METADATA_NS \ + ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "Metadata") +#define PHP_MAXMINDDB_READER_EX_NS \ + ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "InvalidDatabaseException") + +#define Z_MAXMINDDB_P(zv) php_maxminddb_fetch_object(Z_OBJ_P(zv)) +typedef size_t strsize_t; +typedef zend_object free_obj_t; + +/* For PHP 8 compatibility */ +#if PHP_VERSION_ID < 80000 + +#define PROP_OBJ(zv) (zv) + +#else + +#define PROP_OBJ(zv) Z_OBJ_P(zv) + +#define TSRMLS_C +#define TSRMLS_CC +#define TSRMLS_DC + +/* End PHP 8 compatibility */ +#endif + +#ifndef ZEND_ACC_CTOR +#define ZEND_ACC_CTOR 0 +#endif + +/* IS_MIXED was added in 2020 */ +#ifndef IS_MIXED +#define IS_MIXED IS_UNDEF +#endif + +/* ZEND_THIS was added in 7.4 */ +#ifndef ZEND_THIS +#define ZEND_THIS (&EX(This)) +#endif + +typedef struct _maxminddb_obj { + MMDB_s *mmdb; + zend_object std; +} maxminddb_obj; + +PHP_FUNCTION(maxminddb); + +static int +get_record(INTERNAL_FUNCTION_PARAMETERS, zval *record, int *prefix_len); +static const MMDB_entry_data_list_s * +handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list, + zval *z_value TSRMLS_DC); +static const MMDB_entry_data_list_s * +handle_array(const MMDB_entry_data_list_s *entry_data_list, + zval *z_value TSRMLS_DC); +static const MMDB_entry_data_list_s * +handle_map(const MMDB_entry_data_list_s *entry_data_list, + zval *z_value TSRMLS_DC); +static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list, + zval *z_value TSRMLS_DC); +static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list, + zval *z_value TSRMLS_DC); +static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list, + zval *z_value TSRMLS_DC); + +#define CHECK_ALLOCATED(val) \ + if (!val) { \ + zend_error(E_ERROR, "Out of memory"); \ + return; \ + } + +static zend_object_handlers maxminddb_obj_handlers; +static zend_class_entry *maxminddb_ce, *maxminddb_exception_ce, *metadata_ce; + +static inline maxminddb_obj * +php_maxminddb_fetch_object(zend_object *obj TSRMLS_DC) { + return (maxminddb_obj *)((char *)(obj)-XtOffsetOf(maxminddb_obj, std)); +} + +ZEND_BEGIN_ARG_INFO_EX(arginfo_maxminddbreader_construct, 0, 0, 1) +ZEND_ARG_TYPE_INFO(0, db_file, IS_STRING, 0) +ZEND_END_ARG_INFO() + +PHP_METHOD(MaxMind_Db_Reader, __construct) { + char *db_file = NULL; + strsize_t name_len; + zval *_this_zval = NULL; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + getThis(), + "Os", + &_this_zval, + maxminddb_ce, + &db_file, + &name_len) == FAILURE) { + return; + } + + if (0 != php_check_open_basedir(db_file TSRMLS_CC) || + 0 != access(db_file, R_OK)) { + zend_throw_exception_ex( + spl_ce_InvalidArgumentException, + 0 TSRMLS_CC, + "The file \"%s\" does not exist or is not readable.", + db_file); + return; + } + + MMDB_s *mmdb = (MMDB_s *)ecalloc(1, sizeof(MMDB_s)); + int const status = MMDB_open(db_file, MMDB_MODE_MMAP, mmdb); + + if (MMDB_SUCCESS != status) { + zend_throw_exception_ex( + maxminddb_exception_ce, + 0 TSRMLS_CC, + "Error opening database file (%s). Is this a valid " + "MaxMind DB file?", + db_file); + efree(mmdb); + return; + } + + maxminddb_obj *mmdb_obj = Z_MAXMINDDB_P(ZEND_THIS); + mmdb_obj->mmdb = mmdb; +} + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX( + arginfo_maxminddbreader_get, 0, 1, IS_MIXED, 1) +ZEND_ARG_TYPE_INFO(0, ip_address, IS_STRING, 0) +ZEND_END_ARG_INFO() + +PHP_METHOD(MaxMind_Db_Reader, get) { + int prefix_len = 0; + get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, return_value, &prefix_len); +} + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX( + arginfo_maxminddbreader_getWithPrefixLen, 0, 1, IS_ARRAY, 1) +ZEND_ARG_TYPE_INFO(0, ip_address, IS_STRING, 0) +ZEND_END_ARG_INFO() + +PHP_METHOD(MaxMind_Db_Reader, getWithPrefixLen) { + zval record, z_prefix_len; + + int prefix_len = 0; + if (get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, &record, &prefix_len) == + FAILURE) { + return; + } + + array_init(return_value); + add_next_index_zval(return_value, &record); + + ZVAL_LONG(&z_prefix_len, prefix_len); + add_next_index_zval(return_value, &z_prefix_len); +} + +static int +get_record(INTERNAL_FUNCTION_PARAMETERS, zval *record, int *prefix_len) { + char *ip_address = NULL; + strsize_t name_len; + zval *this_zval = NULL; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + getThis(), + "Os", + &this_zval, + maxminddb_ce, + &ip_address, + &name_len) == FAILURE) { + return FAILURE; + } + + const maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(ZEND_THIS); + + MMDB_s *mmdb = mmdb_obj->mmdb; + + if (NULL == mmdb) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, + 0 TSRMLS_CC, + "Attempt to read from a closed MaxMind DB."); + return FAILURE; + } + + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_flags = AI_NUMERICHOST, + /* We set ai_socktype so that we only get one result back */ + .ai_socktype = SOCK_STREAM}; + + struct addrinfo *addresses = NULL; + int gai_status = getaddrinfo(ip_address, NULL, &hints, &addresses); + if (gai_status) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, + 0 TSRMLS_CC, + "The value \"%s\" is not a valid IP address.", + ip_address); + return FAILURE; + } + if (!addresses || !addresses->ai_addr) { + zend_throw_exception_ex( + spl_ce_InvalidArgumentException, + 0 TSRMLS_CC, + "getaddrinfo was successful but failed to set the addrinfo"); + return FAILURE; + } + + int sa_family = addresses->ai_addr->sa_family; + + int mmdb_error = MMDB_SUCCESS; + MMDB_lookup_result_s result = + MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, &mmdb_error); + + freeaddrinfo(addresses); + + if (MMDB_SUCCESS != mmdb_error) { + zend_class_entry *ex; + if (MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR == mmdb_error) { + ex = spl_ce_InvalidArgumentException; + } else { + ex = maxminddb_exception_ce; + } + zend_throw_exception_ex(ex, + 0 TSRMLS_CC, + "Error looking up %s. %s", + ip_address, + MMDB_strerror(mmdb_error)); + return FAILURE; + } + + *prefix_len = result.netmask; + + if (sa_family == AF_INET && mmdb->metadata.ip_version == 6) { + /* We return the prefix length given the IPv4 address. If there is + no IPv4 subtree, we return a prefix length of 0. */ + *prefix_len = *prefix_len >= 96 ? *prefix_len - 96 : 0; + } + + if (!result.found_entry) { + ZVAL_NULL(record); + return SUCCESS; + } + + MMDB_entry_data_list_s *entry_data_list = NULL; + int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list); + + if (MMDB_SUCCESS != status) { + zend_throw_exception_ex(maxminddb_exception_ce, + 0 TSRMLS_CC, + "Error while looking up data for %s. %s", + ip_address, + MMDB_strerror(status)); + MMDB_free_entry_data_list(entry_data_list); + return FAILURE; + } else if (NULL == entry_data_list) { + zend_throw_exception_ex( + maxminddb_exception_ce, + 0 TSRMLS_CC, + "Error while looking up data for %s. Your database may " + "be corrupt or you have found a bug in libmaxminddb.", + ip_address); + return FAILURE; + } + + const MMDB_entry_data_list_s *rv = + handle_entry_data_list(entry_data_list, record TSRMLS_CC); + if (rv == NULL) { + /* We should have already thrown the exception in handle_entry_data_list + */ + return FAILURE; + } + MMDB_free_entry_data_list(entry_data_list); + return SUCCESS; +} + +ZEND_BEGIN_ARG_INFO_EX(arginfo_maxminddbreader_void, 0, 0, 0) +ZEND_END_ARG_INFO() + +PHP_METHOD(MaxMind_Db_Reader, metadata) { + zval *this_zval = NULL; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + getThis(), + "O", + &this_zval, + maxminddb_ce) == FAILURE) { + return; + } + + const maxminddb_obj *const mmdb_obj = + (maxminddb_obj *)Z_MAXMINDDB_P(this_zval); + + if (NULL == mmdb_obj->mmdb) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, + 0 TSRMLS_CC, + "Attempt to read from a closed MaxMind DB."); + return; + } + + object_init_ex(return_value, metadata_ce); + + MMDB_entry_data_list_s *entry_data_list; + MMDB_get_metadata_as_entry_data_list(mmdb_obj->mmdb, &entry_data_list); + + zval metadata_array; + const MMDB_entry_data_list_s *rv = + handle_entry_data_list(entry_data_list, &metadata_array TSRMLS_CC); + if (rv == NULL) { + return; + } + MMDB_free_entry_data_list(entry_data_list); + zend_call_method_with_1_params(PROP_OBJ(return_value), + metadata_ce, + &metadata_ce->constructor, + ZEND_CONSTRUCTOR_FUNC_NAME, + NULL, + &metadata_array); + zval_ptr_dtor(&metadata_array); +} + +PHP_METHOD(MaxMind_Db_Reader, close) { + zval *this_zval = NULL; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + getThis(), + "O", + &this_zval, + maxminddb_ce) == FAILURE) { + return; + } + + maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(this_zval); + + if (NULL == mmdb_obj->mmdb) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, + 0 TSRMLS_CC, + "Attempt to close a closed MaxMind DB."); + return; + } + MMDB_close(mmdb_obj->mmdb); + efree(mmdb_obj->mmdb); + mmdb_obj->mmdb = NULL; +} + +static const MMDB_entry_data_list_s * +handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list, + zval *z_value TSRMLS_DC) { + switch (entry_data_list->entry_data.type) { + case MMDB_DATA_TYPE_MAP: + return handle_map(entry_data_list, z_value TSRMLS_CC); + case MMDB_DATA_TYPE_ARRAY: + return handle_array(entry_data_list, z_value TSRMLS_CC); + case MMDB_DATA_TYPE_UTF8_STRING: + ZVAL_STRINGL(z_value, + entry_data_list->entry_data.utf8_string, + entry_data_list->entry_data.data_size); + break; + case MMDB_DATA_TYPE_BYTES: + ZVAL_STRINGL(z_value, + (char const *)entry_data_list->entry_data.bytes, + entry_data_list->entry_data.data_size); + break; + case MMDB_DATA_TYPE_DOUBLE: + ZVAL_DOUBLE(z_value, entry_data_list->entry_data.double_value); + break; + case MMDB_DATA_TYPE_FLOAT: + ZVAL_DOUBLE(z_value, entry_data_list->entry_data.float_value); + break; + case MMDB_DATA_TYPE_UINT16: + ZVAL_LONG(z_value, entry_data_list->entry_data.uint16); + break; + case MMDB_DATA_TYPE_UINT32: + handle_uint32(entry_data_list, z_value TSRMLS_CC); + break; + case MMDB_DATA_TYPE_BOOLEAN: + ZVAL_BOOL(z_value, entry_data_list->entry_data.boolean); + break; + case MMDB_DATA_TYPE_UINT64: + handle_uint64(entry_data_list, z_value TSRMLS_CC); + break; + case MMDB_DATA_TYPE_UINT128: + handle_uint128(entry_data_list, z_value TSRMLS_CC); + break; + case MMDB_DATA_TYPE_INT32: + ZVAL_LONG(z_value, entry_data_list->entry_data.int32); + break; + default: + zend_throw_exception_ex(maxminddb_exception_ce, + 0 TSRMLS_CC, + "Invalid data type arguments: %d", + entry_data_list->entry_data.type); + return NULL; + } + return entry_data_list; +} + +static const MMDB_entry_data_list_s * +handle_map(const MMDB_entry_data_list_s *entry_data_list, + zval *z_value TSRMLS_DC) { + array_init(z_value); + const uint32_t map_size = entry_data_list->entry_data.data_size; + + uint32_t i; + for (i = 0; i < map_size && entry_data_list; i++) { + entry_data_list = entry_data_list->next; + + char *key = estrndup(entry_data_list->entry_data.utf8_string, + entry_data_list->entry_data.data_size); + if (NULL == key) { + zend_throw_exception_ex(maxminddb_exception_ce, + 0 TSRMLS_CC, + "Invalid data type arguments"); + return NULL; + } + + entry_data_list = entry_data_list->next; + zval new_value; + entry_data_list = + handle_entry_data_list(entry_data_list, &new_value TSRMLS_CC); + if (entry_data_list != NULL) { + add_assoc_zval(z_value, key, &new_value); + } + efree(key); + } + return entry_data_list; +} + +static const MMDB_entry_data_list_s * +handle_array(const MMDB_entry_data_list_s *entry_data_list, + zval *z_value TSRMLS_DC) { + const uint32_t size = entry_data_list->entry_data.data_size; + + array_init(z_value); + + uint32_t i; + for (i = 0; i < size && entry_data_list; i++) { + entry_data_list = entry_data_list->next; + zval new_value; + entry_data_list = + handle_entry_data_list(entry_data_list, &new_value TSRMLS_CC); + if (entry_data_list != NULL) { + add_next_index_zval(z_value, &new_value); + } + } + return entry_data_list; +} + +static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list, + zval *z_value TSRMLS_DC) { + uint64_t high = 0; + uint64_t low = 0; +#if MMDB_UINT128_IS_BYTE_ARRAY + int i; + for (i = 0; i < 8; i++) { + high = (high << 8) | entry_data_list->entry_data.uint128[i]; + } + + for (i = 8; i < 16; i++) { + low = (low << 8) | entry_data_list->entry_data.uint128[i]; + } +#else + high = entry_data_list->entry_data.uint128 >> 64; + low = (uint64_t)entry_data_list->entry_data.uint128; +#endif + + char *num_str; + spprintf(&num_str, 0, "0x%016" PRIX64 "%016" PRIX64, high, low); + CHECK_ALLOCATED(num_str); + + ZVAL_STRING(z_value, num_str); + efree(num_str); +} + +static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list, + zval *z_value TSRMLS_DC) { + uint32_t val = entry_data_list->entry_data.uint32; + +#if LONG_MAX >= UINT32_MAX + ZVAL_LONG(z_value, val); + return; +#else + if (val <= LONG_MAX) { + ZVAL_LONG(z_value, val); + return; + } + + char *int_str; + spprintf(&int_str, 0, "%" PRIu32, val); + CHECK_ALLOCATED(int_str); + + ZVAL_STRING(z_value, int_str); + efree(int_str); +#endif +} + +static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list, + zval *z_value TSRMLS_DC) { + uint64_t val = entry_data_list->entry_data.uint64; + +#if LONG_MAX >= UINT64_MAX + ZVAL_LONG(z_value, val); + return; +#else + if (val <= LONG_MAX) { + ZVAL_LONG(z_value, val); + return; + } + + char *int_str; + spprintf(&int_str, 0, "%" PRIu64, val); + CHECK_ALLOCATED(int_str); + + ZVAL_STRING(z_value, int_str); + efree(int_str); +#endif +} + +static void maxminddb_free_storage(free_obj_t *object TSRMLS_DC) { + maxminddb_obj *obj = + php_maxminddb_fetch_object((zend_object *)object TSRMLS_CC); + if (obj->mmdb != NULL) { + MMDB_close(obj->mmdb); + efree(obj->mmdb); + } + + zend_object_std_dtor(&obj->std TSRMLS_CC); +} + +static zend_object *maxminddb_create_handler(zend_class_entry *type TSRMLS_DC) { + maxminddb_obj *obj = (maxminddb_obj *)ecalloc(1, sizeof(maxminddb_obj)); + zend_object_std_init(&obj->std, type TSRMLS_CC); + object_properties_init(&(obj->std), type); + + obj->std.handlers = &maxminddb_obj_handlers; + + return &obj->std; +} + +/* clang-format off */ +static zend_function_entry maxminddb_methods[] = { + PHP_ME(MaxMind_Db_Reader, __construct, arginfo_maxminddbreader_construct, + ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) + PHP_ME(MaxMind_Db_Reader, close, arginfo_maxminddbreader_void, ZEND_ACC_PUBLIC) + PHP_ME(MaxMind_Db_Reader, get, arginfo_maxminddbreader_get, ZEND_ACC_PUBLIC) + PHP_ME(MaxMind_Db_Reader, getWithPrefixLen, arginfo_maxminddbreader_getWithPrefixLen, ZEND_ACC_PUBLIC) + PHP_ME(MaxMind_Db_Reader, metadata, arginfo_maxminddbreader_void, ZEND_ACC_PUBLIC) + { NULL, NULL, NULL } +}; +/* clang-format on */ + +ZEND_BEGIN_ARG_INFO_EX(arginfo_metadata_construct, 0, 0, 1) +ZEND_ARG_TYPE_INFO(0, metadata, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + +PHP_METHOD(MaxMind_Db_Reader_Metadata, __construct) { + zval *object = NULL; + zval *metadata_array = NULL; + zend_long node_count = 0; + zend_long record_size = 0; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + getThis(), + "Oa", + &object, + metadata_ce, + &metadata_array) == FAILURE) { + return; + } + + zval *tmp = NULL; + if ((tmp = zend_hash_str_find(HASH_OF(metadata_array), + "binary_format_major_version", + sizeof("binary_format_major_version") - 1))) { + zend_update_property(metadata_ce, + PROP_OBJ(object), + "binaryFormatMajorVersion", + sizeof("binaryFormatMajorVersion") - 1, + tmp); + } + + if ((tmp = zend_hash_str_find(HASH_OF(metadata_array), + "binary_format_minor_version", + sizeof("binary_format_minor_version") - 1))) { + zend_update_property(metadata_ce, + PROP_OBJ(object), + "binaryFormatMinorVersion", + sizeof("binaryFormatMinorVersion") - 1, + tmp); + } + + if ((tmp = zend_hash_str_find(HASH_OF(metadata_array), + "build_epoch", + sizeof("build_epoch") - 1))) { + zend_update_property(metadata_ce, + PROP_OBJ(object), + "buildEpoch", + sizeof("buildEpoch") - 1, + tmp); + } + + if ((tmp = zend_hash_str_find(HASH_OF(metadata_array), + "database_type", + sizeof("database_type") - 1))) { + zend_update_property(metadata_ce, + PROP_OBJ(object), + "databaseType", + sizeof("databaseType") - 1, + tmp); + } + + if ((tmp = zend_hash_str_find(HASH_OF(metadata_array), + "description", + sizeof("description") - 1))) { + zend_update_property(metadata_ce, + PROP_OBJ(object), + "description", + sizeof("description") - 1, + tmp); + } + + if ((tmp = zend_hash_str_find(HASH_OF(metadata_array), + "ip_version", + sizeof("ip_version") - 1))) { + zend_update_property(metadata_ce, + PROP_OBJ(object), + "ipVersion", + sizeof("ipVersion") - 1, + tmp); + } + + if ((tmp = zend_hash_str_find( + HASH_OF(metadata_array), "languages", sizeof("languages") - 1))) { + zend_update_property(metadata_ce, + PROP_OBJ(object), + "languages", + sizeof("languages") - 1, + tmp); + } + + if ((tmp = zend_hash_str_find(HASH_OF(metadata_array), + "record_size", + sizeof("record_size") - 1))) { + zend_update_property(metadata_ce, + PROP_OBJ(object), + "recordSize", + sizeof("recordSize") - 1, + tmp); + if (Z_TYPE_P(tmp) == IS_LONG) { + record_size = Z_LVAL_P(tmp); + } + } + + if (record_size != 0) { + zend_update_property_long(metadata_ce, + PROP_OBJ(object), + "nodeByteSize", + sizeof("nodeByteSize") - 1, + record_size / 4); + } + + if ((tmp = zend_hash_str_find(HASH_OF(metadata_array), + "node_count", + sizeof("node_count") - 1))) { + zend_update_property(metadata_ce, + PROP_OBJ(object), + "nodeCount", + sizeof("nodeCount") - 1, + tmp); + if (Z_TYPE_P(tmp) == IS_LONG) { + node_count = Z_LVAL_P(tmp); + } + } + + if (record_size != 0) { + zend_update_property_long(metadata_ce, + PROP_OBJ(object), + "searchTreeSize", + sizeof("searchTreeSize") - 1, + record_size * node_count / 4); + } +} + +// clang-format off +static zend_function_entry metadata_methods[] = { + PHP_ME(MaxMind_Db_Reader_Metadata, __construct, arginfo_metadata_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) + {NULL, NULL, NULL} +}; +// clang-format on + +PHP_MINIT_FUNCTION(maxminddb) { + zend_class_entry ce; + + INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_READER_EX_NS, NULL); + maxminddb_exception_ce = + zend_register_internal_class_ex(&ce, zend_ce_exception); + + INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_READER_NS, maxminddb_methods); + maxminddb_ce = zend_register_internal_class(&ce TSRMLS_CC); + maxminddb_ce->create_object = maxminddb_create_handler; + + INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_METADATA_NS, metadata_methods); + metadata_ce = zend_register_internal_class(&ce TSRMLS_CC); + zend_declare_property_null(metadata_ce, + "binaryFormatMajorVersion", + sizeof("binaryFormatMajorVersion") - 1, + ZEND_ACC_PUBLIC); + zend_declare_property_null(metadata_ce, + "binaryFormatMinorVersion", + sizeof("binaryFormatMinorVersion") - 1, + ZEND_ACC_PUBLIC); + zend_declare_property_null( + metadata_ce, "buildEpoch", sizeof("buildEpoch") - 1, ZEND_ACC_PUBLIC); + zend_declare_property_null(metadata_ce, + "databaseType", + sizeof("databaseType") - 1, + ZEND_ACC_PUBLIC); + zend_declare_property_null( + metadata_ce, "description", sizeof("description") - 1, ZEND_ACC_PUBLIC); + zend_declare_property_null( + metadata_ce, "ipVersion", sizeof("ipVersion") - 1, ZEND_ACC_PUBLIC); + zend_declare_property_null( + metadata_ce, "languages", sizeof("languages") - 1, ZEND_ACC_PUBLIC); + zend_declare_property_null(metadata_ce, + "nodeByteSize", + sizeof("nodeByteSize") - 1, + ZEND_ACC_PUBLIC); + zend_declare_property_null( + metadata_ce, "nodeCount", sizeof("nodeCount") - 1, ZEND_ACC_PUBLIC); + zend_declare_property_null( + metadata_ce, "recordSize", sizeof("recordSize") - 1, ZEND_ACC_PUBLIC); + zend_declare_property_null(metadata_ce, + "searchTreeSize", + sizeof("searchTreeSize") - 1, + ZEND_ACC_PUBLIC); + + memcpy(&maxminddb_obj_handlers, + zend_get_std_object_handlers(), + sizeof(zend_object_handlers)); + maxminddb_obj_handlers.clone_obj = NULL; + maxminddb_obj_handlers.offset = XtOffsetOf(maxminddb_obj, std); + maxminddb_obj_handlers.free_obj = maxminddb_free_storage; + zend_declare_class_constant_string(maxminddb_ce, + "MMDB_LIB_VERSION", + sizeof("MMDB_LIB_VERSION") - 1, + MMDB_lib_version() TSRMLS_CC); + + return SUCCESS; +} + +static PHP_MINFO_FUNCTION(maxminddb) { + php_info_print_table_start(); + + php_info_print_table_row(2, "MaxMind DB Reader", "enabled"); + php_info_print_table_row( + 2, "maxminddb extension version", PHP_MAXMINDDB_VERSION); + php_info_print_table_row( + 2, "libmaxminddb library version", MMDB_lib_version()); + + php_info_print_table_end(); +} + +zend_module_entry maxminddb_module_entry = {STANDARD_MODULE_HEADER, + PHP_MAXMINDDB_EXTNAME, + NULL, + PHP_MINIT(maxminddb), + NULL, + NULL, + NULL, + PHP_MINFO(maxminddb), + PHP_MAXMINDDB_VERSION, + STANDARD_MODULE_PROPERTIES}; + +#ifdef COMPILE_DL_MAXMINDDB +ZEND_GET_MODULE(maxminddb) +#endif diff --git a/tools/geoip/maxmind-db/reader/ext/php_maxminddb.h b/tools/geoip/maxmind-db/reader/ext/php_maxminddb.h new file mode 100644 index 000000000..b5261b8d9 --- /dev/null +++ b/tools/geoip/maxmind-db/reader/ext/php_maxminddb.h @@ -0,0 +1,24 @@ +/* MaxMind, Inc., licenses this file to you under the Apache License, Version + * 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +#include + +#ifndef PHP_MAXMINDDB_H +#define PHP_MAXMINDDB_H 1 +#define PHP_MAXMINDDB_VERSION "1.12.0" +#define PHP_MAXMINDDB_EXTNAME "maxminddb" + +extern zend_module_entry maxminddb_module_entry; +#define phpext_maxminddb_ptr &maxminddb_module_entry + +#endif diff --git a/tools/geoip/maxmind-db/reader/ext/tests/001-load.phpt b/tools/geoip/maxmind-db/reader/ext/tests/001-load.phpt new file mode 100644 index 000000000..09810eec4 --- /dev/null +++ b/tools/geoip/maxmind-db/reader/ext/tests/001-load.phpt @@ -0,0 +1,12 @@ +--TEST-- +Check for maxminddb presence +--SKIPIF-- + +--FILE-- + +--EXPECT-- +maxminddb extension is available diff --git a/tools/geoip/maxmind-db/reader/ext/tests/002-final.phpt b/tools/geoip/maxmind-db/reader/ext/tests/002-final.phpt new file mode 100644 index 000000000..d91b7d0ff --- /dev/null +++ b/tools/geoip/maxmind-db/reader/ext/tests/002-final.phpt @@ -0,0 +1,13 @@ +--TEST-- +Check that Reader class is not final +--SKIPIF-- + +--FILE-- +isFinal()); +?> +--EXPECT-- +bool(false) diff --git a/tools/geoip/maxmind-db/reader/ext/tests/003-open-basedir.phpt b/tools/geoip/maxmind-db/reader/ext/tests/003-open-basedir.phpt new file mode 100644 index 000000000..26e978193 --- /dev/null +++ b/tools/geoip/maxmind-db/reader/ext/tests/003-open-basedir.phpt @@ -0,0 +1,12 @@ +--TEST-- +openbase_dir is followed +--INI-- +open_basedir=/--dne-- +--FILE-- + +--EXPECTREGEX-- +.*open_basedir restriction in effect.* diff --git a/tools/geoip/maxmind-db/reader/package.xml b/tools/geoip/maxmind-db/reader/package.xml new file mode 100644 index 000000000..5fe5cb847 --- /dev/null +++ b/tools/geoip/maxmind-db/reader/package.xml @@ -0,0 +1,63 @@ + + + + maxminddb + pecl.php.net + Reader for the MaxMind DB file format + This is the PHP extension for reading MaxMind DB files. MaxMind DB is a binary file format that stores data indexed by IP address subnets (IPv4 or IPv6). + + Greg Oschwald + oschwald + goschwald@maxmind.com + yes + + 2024-11-14 + + 1.12.0 + 1.12.0 + + + stable + stable + + Apache License 2.0 + * Improve the error handling when the user tries to open a directory + with the pure PHP reader. +* Improve the typehints on arrays in the PHPDocs. + + + + + + + + + + + + + + + + + + + + + + + + + 7.2.0 + + + 1.10.0 + + + + maxminddb + + diff --git a/tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader.php b/tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader.php new file mode 100644 index 000000000..12c6b0950 --- /dev/null +++ b/tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader.php @@ -0,0 +1,410 @@ + + */ + private static $METADATA_START_MARKER_LENGTH = 14; + + /** + * @var int + */ + private static $METADATA_MAX_SIZE = 131072; // 128 * 1024 = 128KiB + + /** + * @var Decoder + */ + private $decoder; + + /** + * @var resource + */ + private $fileHandle; + + /** + * @var int + */ + private $fileSize; + + /** + * @var int + */ + private $ipV4Start; + + /** + * @var Metadata + */ + private $metadata; + + /** + * Constructs a Reader for the MaxMind DB format. The file passed to it must + * be a valid MaxMind DB file such as a GeoIp2 database file. + * + * @param string $database the MaxMind DB file to use + * + * @throws \InvalidArgumentException for invalid database path or unknown arguments + * @throws InvalidDatabaseException + * if the database is invalid or there is an error reading + * from it + */ + public function __construct(string $database) + { + if (\func_num_args() !== 1) { + throw new \ArgumentCountError( + \sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()) + ); + } + + if (is_dir($database)) { + // This matches the error that the C extension throws. + throw new InvalidDatabaseException( + "Error opening database file ($database). Is this a valid MaxMind DB file?" + ); + } + + $fileHandle = @fopen($database, 'rb'); + if ($fileHandle === false) { + throw new \InvalidArgumentException( + "The file \"$database\" does not exist or is not readable." + ); + } + $this->fileHandle = $fileHandle; + + $fileSize = @filesize($database); + if ($fileSize === false) { + throw new \UnexpectedValueException( + "Error determining the size of \"$database\"." + ); + } + $this->fileSize = $fileSize; + + $start = $this->findMetadataStart($database); + $metadataDecoder = new Decoder($this->fileHandle, $start); + [$metadataArray] = $metadataDecoder->decode($start); + $this->metadata = new Metadata($metadataArray); + $this->decoder = new Decoder( + $this->fileHandle, + $this->metadata->searchTreeSize + self::$DATA_SECTION_SEPARATOR_SIZE + ); + $this->ipV4Start = $this->ipV4StartNode(); + } + + /** + * Retrieves the record for the IP address. + * + * @param string $ipAddress the IP address to look up + * + * @throws \BadMethodCallException if this method is called on a closed database + * @throws \InvalidArgumentException if something other than a single IP address is passed to the method + * @throws InvalidDatabaseException + * if the database is invalid or there is an error reading + * from it + * + * @return mixed the record for the IP address + */ + public function get(string $ipAddress) + { + if (\func_num_args() !== 1) { + throw new \ArgumentCountError( + \sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()) + ); + } + [$record] = $this->getWithPrefixLen($ipAddress); + + return $record; + } + + /** + * Retrieves the record for the IP address and its associated network prefix length. + * + * @param string $ipAddress the IP address to look up + * + * @throws \BadMethodCallException if this method is called on a closed database + * @throws \InvalidArgumentException if something other than a single IP address is passed to the method + * @throws InvalidDatabaseException + * if the database is invalid or there is an error reading + * from it + * + * @return array{0:mixed, 1:int} an array where the first element is the record and the + * second the network prefix length for the record + */ + public function getWithPrefixLen(string $ipAddress): array + { + if (\func_num_args() !== 1) { + throw new \ArgumentCountError( + \sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()) + ); + } + + if (!\is_resource($this->fileHandle)) { + throw new \BadMethodCallException( + 'Attempt to read from a closed MaxMind DB.' + ); + } + + [$pointer, $prefixLen] = $this->findAddressInTree($ipAddress); + if ($pointer === 0) { + return [null, $prefixLen]; + } + + return [$this->resolveDataPointer($pointer), $prefixLen]; + } + + /** + * @return array{0:int, 1:int} + */ + private function findAddressInTree(string $ipAddress): array + { + $packedAddr = @inet_pton($ipAddress); + if ($packedAddr === false) { + throw new \InvalidArgumentException( + "The value \"$ipAddress\" is not a valid IP address." + ); + } + + $rawAddress = unpack('C*', $packedAddr); + if ($rawAddress === false) { + throw new InvalidDatabaseException( + 'Could not unpack the unsigned char of the packed in_addr representation.' + ); + } + + $bitCount = \count($rawAddress) * 8; + + // The first node of the tree is always node 0, at the beginning of the + // value + $node = 0; + + $metadata = $this->metadata; + + // Check if we are looking up an IPv4 address in an IPv6 tree. If this + // is the case, we can skip over the first 96 nodes. + if ($metadata->ipVersion === 6) { + if ($bitCount === 32) { + $node = $this->ipV4Start; + } + } elseif ($metadata->ipVersion === 4 && $bitCount === 128) { + throw new \InvalidArgumentException( + "Error looking up $ipAddress. You attempted to look up an" + . ' IPv6 address in an IPv4-only database.' + ); + } + + $nodeCount = $metadata->nodeCount; + + for ($i = 0; $i < $bitCount && $node < $nodeCount; ++$i) { + $tempBit = 0xFF & $rawAddress[($i >> 3) + 1]; + $bit = 1 & ($tempBit >> 7 - ($i % 8)); + + $node = $this->readNode($node, $bit); + } + if ($node === $nodeCount) { + // Record is empty + return [0, $i]; + } + if ($node > $nodeCount) { + // Record is a data pointer + return [$node, $i]; + } + + throw new InvalidDatabaseException( + 'Invalid or corrupt database. Maximum search depth reached without finding a leaf node' + ); + } + + private function ipV4StartNode(): int + { + // If we have an IPv4 database, the start node is the first node + if ($this->metadata->ipVersion === 4) { + return 0; + } + + $node = 0; + + for ($i = 0; $i < 96 && $node < $this->metadata->nodeCount; ++$i) { + $node = $this->readNode($node, 0); + } + + return $node; + } + + private function readNode(int $nodeNumber, int $index): int + { + $baseOffset = $nodeNumber * $this->metadata->nodeByteSize; + + switch ($this->metadata->recordSize) { + case 24: + $bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3); + $rc = unpack('N', "\x00" . $bytes); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack the unsigned long of the node.' + ); + } + [, $node] = $rc; + + return $node; + + case 28: + $bytes = Util::read($this->fileHandle, $baseOffset + 3 * $index, 4); + if ($index === 0) { + $middle = (0xF0 & \ord($bytes[3])) >> 4; + } else { + $middle = 0x0F & \ord($bytes[0]); + } + $rc = unpack('N', \chr($middle) . substr($bytes, $index, 3)); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack the unsigned long of the node.' + ); + } + [, $node] = $rc; + + return $node; + + case 32: + $bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4); + $rc = unpack('N', $bytes); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack the unsigned long of the node.' + ); + } + [, $node] = $rc; + + return $node; + + default: + throw new InvalidDatabaseException( + 'Unknown record size: ' + . $this->metadata->recordSize + ); + } + } + + /** + * @return mixed + */ + private function resolveDataPointer(int $pointer) + { + $resolved = $pointer - $this->metadata->nodeCount + + $this->metadata->searchTreeSize; + if ($resolved >= $this->fileSize) { + throw new InvalidDatabaseException( + "The MaxMind DB file's search tree is corrupt" + ); + } + + [$data] = $this->decoder->decode($resolved); + + return $data; + } + + /* + * This is an extremely naive but reasonably readable implementation. There + * are much faster algorithms (e.g., Boyer-Moore) for this if speed is ever + * an issue, but I suspect it won't be. + */ + private function findMetadataStart(string $filename): int + { + $handle = $this->fileHandle; + $fstat = fstat($handle); + if ($fstat === false) { + throw new InvalidDatabaseException( + "Error getting file information ($filename)." + ); + } + $fileSize = $fstat['size']; + $marker = self::$METADATA_START_MARKER; + $markerLength = self::$METADATA_START_MARKER_LENGTH; + + $minStart = $fileSize - min(self::$METADATA_MAX_SIZE, $fileSize); + + for ($offset = $fileSize - $markerLength; $offset >= $minStart; --$offset) { + if (fseek($handle, $offset) !== 0) { + break; + } + + $value = fread($handle, $markerLength); + if ($value === $marker) { + return $offset + $markerLength; + } + } + + throw new InvalidDatabaseException( + "Error opening database file ($filename). " . + 'Is this a valid MaxMind DB file?' + ); + } + + /** + * @throws \InvalidArgumentException if arguments are passed to the method + * @throws \BadMethodCallException if the database has been closed + * + * @return Metadata object for the database + */ + public function metadata(): Metadata + { + if (\func_num_args()) { + throw new \ArgumentCountError( + \sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args()) + ); + } + + // Not technically required, but this makes it consistent with + // C extension and it allows us to change our implementation later. + if (!\is_resource($this->fileHandle)) { + throw new \BadMethodCallException( + 'Attempt to read from a closed MaxMind DB.' + ); + } + + return clone $this->metadata; + } + + /** + * Closes the MaxMind DB and returns resources to the system. + * + * @throws \Exception + * if an I/O error occurs + */ + public function close(): void + { + if (\func_num_args()) { + throw new \ArgumentCountError( + \sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args()) + ); + } + + if (!\is_resource($this->fileHandle)) { + throw new \BadMethodCallException( + 'Attempt to close a closed MaxMind DB.' + ); + } + fclose($this->fileHandle); + } +} diff --git a/tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php b/tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php new file mode 100644 index 000000000..1bb673167 --- /dev/null +++ b/tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php @@ -0,0 +1,452 @@ +fileStream = $fileStream; + $this->pointerBase = $pointerBase; + + $this->pointerTestHack = $pointerTestHack; + + $this->switchByteOrder = $this->isPlatformLittleEndian(); + } + + /** + * @return array + */ + public function decode(int $offset): array + { + $ctrlByte = \ord(Util::read($this->fileStream, $offset, 1)); + ++$offset; + + $type = $ctrlByte >> 5; + + // Pointers are a special case, we don't read the next $size bytes, we + // use the size to determine the length of the pointer and then follow + // it. + if ($type === self::_POINTER) { + [$pointer, $offset] = $this->decodePointer($ctrlByte, $offset); + + // for unit testing + if ($this->pointerTestHack) { + return [$pointer]; + } + + [$result] = $this->decode($pointer); + + return [$result, $offset]; + } + + if ($type === self::_EXTENDED) { + $nextByte = \ord(Util::read($this->fileStream, $offset, 1)); + + $type = $nextByte + 7; + + if ($type < 8) { + throw new InvalidDatabaseException( + 'Something went horribly wrong in the decoder. An extended type ' + . 'resolved to a type number < 8 (' + . $type + . ')' + ); + } + + ++$offset; + } + + [$size, $offset] = $this->sizeFromCtrlByte($ctrlByte, $offset); + + return $this->decodeByType($type, $offset, $size); + } + + /** + * @param int<0, max> $size + * + * @return array{0:mixed, 1:int} + */ + private function decodeByType(int $type, int $offset, int $size): array + { + switch ($type) { + case self::_MAP: + return $this->decodeMap($size, $offset); + + case self::_ARRAY: + return $this->decodeArray($size, $offset); + + case self::_BOOLEAN: + return [$this->decodeBoolean($size), $offset]; + } + + $newOffset = $offset + $size; + $bytes = Util::read($this->fileStream, $offset, $size); + + switch ($type) { + case self::_BYTES: + case self::_UTF8_STRING: + return [$bytes, $newOffset]; + + case self::_DOUBLE: + $this->verifySize(8, $size); + + return [$this->decodeDouble($bytes), $newOffset]; + + case self::_FLOAT: + $this->verifySize(4, $size); + + return [$this->decodeFloat($bytes), $newOffset]; + + case self::_INT32: + return [$this->decodeInt32($bytes, $size), $newOffset]; + + case self::_UINT16: + case self::_UINT32: + case self::_UINT64: + case self::_UINT128: + return [$this->decodeUint($bytes, $size), $newOffset]; + + default: + throw new InvalidDatabaseException( + 'Unknown or unexpected type: ' . $type + ); + } + } + + private function verifySize(int $expected, int $actual): void + { + if ($expected !== $actual) { + throw new InvalidDatabaseException( + "The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)" + ); + } + } + + /** + * @return array{0:array, 1:int} + */ + private function decodeArray(int $size, int $offset): array + { + $array = []; + + for ($i = 0; $i < $size; ++$i) { + [$value, $offset] = $this->decode($offset); + $array[] = $value; + } + + return [$array, $offset]; + } + + private function decodeBoolean(int $size): bool + { + return $size !== 0; + } + + private function decodeDouble(string $bytes): float + { + // This assumes IEEE 754 doubles, but most (all?) modern platforms + // use them. + $rc = unpack('E', $bytes); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack a double value from the given bytes.' + ); + } + [, $double] = $rc; + + return $double; + } + + private function decodeFloat(string $bytes): float + { + // This assumes IEEE 754 floats, but most (all?) modern platforms + // use them. + $rc = unpack('G', $bytes); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack a float value from the given bytes.' + ); + } + [, $float] = $rc; + + return $float; + } + + private function decodeInt32(string $bytes, int $size): int + { + switch ($size) { + case 0: + return 0; + + case 1: + case 2: + case 3: + $bytes = str_pad($bytes, 4, "\x00", \STR_PAD_LEFT); + + break; + + case 4: + break; + + default: + throw new InvalidDatabaseException( + "The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)" + ); + } + + $rc = unpack('l', $this->maybeSwitchByteOrder($bytes)); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack a 32bit integer value from the given bytes.' + ); + } + [, $int] = $rc; + + return $int; + } + + /** + * @return array{0:array, 1:int} + */ + private function decodeMap(int $size, int $offset): array + { + $map = []; + + for ($i = 0; $i < $size; ++$i) { + [$key, $offset] = $this->decode($offset); + [$value, $offset] = $this->decode($offset); + $map[$key] = $value; + } + + return [$map, $offset]; + } + + /** + * @return array{0:int, 1:int} + */ + private function decodePointer(int $ctrlByte, int $offset): array + { + $pointerSize = (($ctrlByte >> 3) & 0x3) + 1; + + $buffer = Util::read($this->fileStream, $offset, $pointerSize); + $offset += $pointerSize; + + switch ($pointerSize) { + case 1: + $packed = \chr($ctrlByte & 0x7) . $buffer; + $rc = unpack('n', $packed); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack an unsigned short value from the given bytes (pointerSize is 1).' + ); + } + [, $pointer] = $rc; + $pointer += $this->pointerBase; + + break; + + case 2: + $packed = "\x00" . \chr($ctrlByte & 0x7) . $buffer; + $rc = unpack('N', $packed); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack an unsigned long value from the given bytes (pointerSize is 2).' + ); + } + [, $pointer] = $rc; + $pointer += $this->pointerBase + 2048; + + break; + + case 3: + $packed = \chr($ctrlByte & 0x7) . $buffer; + + // It is safe to use 'N' here, even on 32 bit machines as the + // first bit is 0. + $rc = unpack('N', $packed); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack an unsigned long value from the given bytes (pointerSize is 3).' + ); + } + [, $pointer] = $rc; + $pointer += $this->pointerBase + 526336; + + break; + + case 4: + // We cannot use unpack here as we might overflow on 32 bit + // machines + $pointerOffset = $this->decodeUint($buffer, $pointerSize); + + $pointerBase = $this->pointerBase; + + if (\PHP_INT_MAX - $pointerBase >= $pointerOffset) { + $pointer = $pointerOffset + $pointerBase; + } else { + throw new \RuntimeException( + 'The database offset is too large to be represented on your platform.' + ); + } + + break; + + default: + throw new InvalidDatabaseException( + 'Unexpected pointer size ' . $pointerSize + ); + } + + return [$pointer, $offset]; + } + + // @phpstan-ignore-next-line + private function decodeUint(string $bytes, int $byteLength) + { + if ($byteLength === 0) { + return 0; + } + + // PHP integers are signed. PHP_INT_SIZE - 1 is the number of + // complete bytes that can be converted to an integer. However, + // we can convert another byte if the leading bit is zero. + $useRealInts = $byteLength <= \PHP_INT_SIZE - 1 + || ($byteLength === \PHP_INT_SIZE && (\ord($bytes[0]) & 0x80) === 0); + + if ($useRealInts) { + $integer = 0; + for ($i = 0; $i < $byteLength; ++$i) { + $part = \ord($bytes[$i]); + $integer = ($integer << 8) + $part; + } + + return $integer; + } + + // We only use gmp or bcmath if the final value is too big + $integerAsString = '0'; + for ($i = 0; $i < $byteLength; ++$i) { + $part = \ord($bytes[$i]); + + if (\extension_loaded('gmp')) { + $integerAsString = gmp_strval(gmp_add(gmp_mul($integerAsString, '256'), $part)); + } elseif (\extension_loaded('bcmath')) { + $integerAsString = bcadd(bcmul($integerAsString, '256'), (string) $part); + } else { + throw new \RuntimeException( + 'The gmp or bcmath extension must be installed to read this database.' + ); + } + } + + return $integerAsString; + } + + /** + * @return array{0:int, 1:int} + */ + private function sizeFromCtrlByte(int $ctrlByte, int $offset): array + { + $size = $ctrlByte & 0x1F; + + if ($size < 29) { + return [$size, $offset]; + } + + $bytesToRead = $size - 28; + $bytes = Util::read($this->fileStream, $offset, $bytesToRead); + + if ($size === 29) { + $size = 29 + \ord($bytes); + } elseif ($size === 30) { + $rc = unpack('n', $bytes); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack an unsigned short value from the given bytes.' + ); + } + [, $adjust] = $rc; + $size = 285 + $adjust; + } else { + $rc = unpack('N', "\x00" . $bytes); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack an unsigned long value from the given bytes.' + ); + } + [, $adjust] = $rc; + $size = $adjust + 65821; + } + + return [$size, $offset + $bytesToRead]; + } + + private function maybeSwitchByteOrder(string $bytes): string + { + return $this->switchByteOrder ? strrev($bytes) : $bytes; + } + + private function isPlatformLittleEndian(): bool + { + $testint = 0x00FF; + $packed = pack('S', $testint); + $rc = unpack('v', $packed); + if ($rc === false) { + throw new InvalidDatabaseException( + 'Could not unpack an unsigned short value from the given bytes.' + ); + } + + return $testint === current($rc); + } +} diff --git a/tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php b/tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php new file mode 100644 index 000000000..b1da1ed24 --- /dev/null +++ b/tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php @@ -0,0 +1,11 @@ + + */ + public $description; + + /** + * This is an unsigned 16-bit integer which is always 4 or 6. It indicates + * whether the database contains IPv4 or IPv6 address data. + * + * @var int + */ + public $ipVersion; + + /** + * An array of strings, each of which is a language code. A given record + * may contain data items that have been localized to some or all of + * these languages. This may be undefined. + * + * @var array + */ + public $languages; + + /** + * @var int + */ + public $nodeByteSize; + + /** + * This is an unsigned 32-bit integer indicating the number of nodes in + * the search tree. + * + * @var int + */ + public $nodeCount; + + /** + * This is an unsigned 16-bit integer. It indicates the number of bits in a + * record in the search tree. Note that each node consists of two records. + * + * @var int + */ + public $recordSize; + + /** + * @var int + */ + public $searchTreeSize; + + /** + * @param array $metadata + */ + public function __construct(array $metadata) + { + if (\func_num_args() !== 1) { + throw new \ArgumentCountError( + \sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()) + ); + } + + $this->binaryFormatMajorVersion = + $metadata['binary_format_major_version']; + $this->binaryFormatMinorVersion = + $metadata['binary_format_minor_version']; + $this->buildEpoch = $metadata['build_epoch']; + $this->databaseType = $metadata['database_type']; + $this->languages = $metadata['languages']; + $this->description = $metadata['description']; + $this->ipVersion = $metadata['ip_version']; + $this->nodeCount = $metadata['node_count']; + $this->recordSize = $metadata['record_size']; + $this->nodeByteSize = $this->recordSize / 4; + $this->searchTreeSize = $this->nodeCount * $this->nodeByteSize; + } +} diff --git a/tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php b/tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php new file mode 100644 index 000000000..c2c3212d9 --- /dev/null +++ b/tools/geoip/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php @@ -0,0 +1,33 @@ + $numberOfBytes + */ + public static function read($stream, int $offset, int $numberOfBytes): string + { + if ($numberOfBytes === 0) { + return ''; + } + if (fseek($stream, $offset) === 0) { + $value = fread($stream, $numberOfBytes); + + // We check that the number of bytes read is equal to the number + // asked for. We use ftell as getting the length of $value is + // much slower. + if ($value !== false && ftell($stream) - $offset === $numberOfBytes) { + return $value; + } + } + + throw new InvalidDatabaseException( + 'The MaxMind DB file contains bad data' + ); + } +} diff --git a/tools/geoip/maxmind/web-service-common/CHANGELOG.md b/tools/geoip/maxmind/web-service-common/CHANGELOG.md new file mode 100644 index 000000000..712b4d668 --- /dev/null +++ b/tools/geoip/maxmind/web-service-common/CHANGELOG.md @@ -0,0 +1,117 @@ +CHANGELOG +========= + +0.10.0 (2024-11-14) +------------------- + +* PHP 8.1 or greater is now required. +* Type hints for PHPStan have been improved. + +0.9.0 (2022-03-28) +------------------ + +* Improved internal type hint usage. + +0.8.1 (2020-11-02) +------------------ + +* We now correctly handle responses without a `Content-Type` header. In 0.8.0, + such responses could lead to a type error. In particular, this affected the + minFraud Report Transaction endpoint, which returns a response with no + content. Reported by Dmitry Malashko. GitHub #99 on + `maxmind/minfraud-api-php`. + +0.8.0 (2020-10-01) +------------------ + +* PHP 7.2 or greater is now required. +* Added additional type hints. + +0.7.0 (2020-05-06) +------------------ + +* Responses with a 204 status code are accepted as successes. + +0.6.0 (2019-12-12) +------------------ + +* Curl handles are now reused across requests. Pull request by Willem + Stuursma-Ruwen. GitHub #24. +* PHP 5.6 is now required. + +0.5.0 (2018-02-12) +------------------ + +* Refer to account IDs using the terminology "account" rather than "user". + +0.4.0 (2017-07-10) +------------------ + +* PHP 5.4 is now required. + +0.3.1 (2016-08-10) +------------------ + +* On Mac OS X when using a curl built against SecureTransport, the certs + in the system's keychain will now be used instead of the CA bundle on + the file system. + +0.3.0 (2016-08-09) +------------------ + +* This package now uses `composer/ca-bundle` by default rather than a CA + bundle distributed with this package. `composer/ca-bundle` will first try + to use the system CA bundle and will fall back to the Mozilla CA bundle + when no system bundle is available. You may still specify your own bundle + using the `caBundle` option. + +0.2.1 (2016-06-13) +------------------ + +* Fix typo in code to copy cert to temp directory. + +0.2.0 (2016-06-10) +------------------ + +* Added handling of additional error codes that the web service may return. +* A `USER_ID_UNKNOWN` error will now throw a + `MaxMind\Exception\AuthenticationException`. +* Added support for `proxy` option. Closes #6. + +0.1.0 (2016-05-23) +------------------ + +* A `PERMISSION_REQUIRED` error will now throw a `PermissionRequiredException` + exception. +* Added a `.gitattributes` file to exclude tests from Composer releases. + GitHub #7. +* Updated included cert bundle. + +0.0.4 (2015-07-21) +------------------ + +* Added extremely basic tests for the curl calls. +* Fixed broken POSTs. + +0.0.3 (2015-06-30) +------------------ + +* Floats now work with the `timeout` and `connectTimeout` options. Fix by + Benjamin Pick. GitHub PR #2. +* `curl_error` is now used instead of `curl_strerror`. The latter is only + available for PHP 5.5 or later. Fix by Benjamin Pick. GitHub PR #1. + + +0.0.2 (2015-06-09) +------------------ + +* An exception is now immediately thrown curl error rather than letting later + status code checks throw an exception. This improves the exception message + greatly. +* If this library is inside a phar archive, the CA certs are copied out of the + archive to a temporary file so that curl can use them. + +0.0.1 (2015-06-01) +------------------ + +* Initial release. diff --git a/tools/geoip/maxmind/web-service-common/LICENSE b/tools/geoip/maxmind/web-service-common/LICENSE new file mode 100644 index 000000000..62589edd1 --- /dev/null +++ b/tools/geoip/maxmind/web-service-common/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/tools/geoip/maxmind/web-service-common/README.md b/tools/geoip/maxmind/web-service-common/README.md new file mode 100644 index 000000000..4344ec601 --- /dev/null +++ b/tools/geoip/maxmind/web-service-common/README.md @@ -0,0 +1,25 @@ +# Common Code for MaxMind Web Service Clients # + +This is _not_ intended for direct use by third parties. Rather, it is for +shared code between MaxMind's various web service client APIs. + +## Requirements ## + +The library requires PHP 8.1 or greater. + +There are several other dependencies as defined in the `composer.json` file. + +## Contributing ## + +Patches and pull requests are encouraged. All code should follow the PSR-2 +style guidelines. Please include unit tests whenever possible. + +## Versioning ## + +This API uses [Semantic Versioning](https://semver.org/). + +## Copyright and License ## + +This software is Copyright (c) 2015-2024 by MaxMind, Inc. + +This is free software, licensed under the Apache License, Version 2.0. diff --git a/tools/geoip/maxmind/web-service-common/composer.json b/tools/geoip/maxmind/web-service-common/composer.json new file mode 100644 index 000000000..c91d42d5a --- /dev/null +++ b/tools/geoip/maxmind/web-service-common/composer.json @@ -0,0 +1,32 @@ +{ + "name": "maxmind/web-service-common", + "description": "Internal MaxMind Web Service API", + "minimum-stability": "stable", + "homepage": "https://github.com/maxmind/web-service-common-php", + "type": "library", + "license": "Apache-2.0", + "authors": [ + { + "name": "Gregory Oschwald", + "email": "goschwald@maxmind.com" + } + ], + "require": { + "php": ">=8.1", + "composer/ca-bundle": "^1.0.3", + "ext-curl": "*", + "ext-json": "*" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "phpunit/phpunit": "^8.0 || ^9.0", + "squizlabs/php_codesniffer": "3.*", + "phpstan/phpstan": "*" + }, + "autoload": { + "psr-4": { + "MaxMind\\Exception\\": "src/Exception", + "MaxMind\\WebService\\": "src/WebService" + } + } +} diff --git a/tools/geoip/maxmind/web-service-common/dev-bin/release.sh b/tools/geoip/maxmind/web-service-common/dev-bin/release.sh new file mode 100755 index 000000000..96c41607d --- /dev/null +++ b/tools/geoip/maxmind/web-service-common/dev-bin/release.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +set -eu -o pipefail + + +changelog=$(cat CHANGELOG.md) + +regex=' +([0-9]+\.[0-9]+\.[0-9]+) \(([0-9]{4}-[0-9]{2}-[0-9]{2})\) +-* + +((.| +)*) +' + +if [[ ! $changelog =~ $regex ]]; then + echo "Could not find date line in change log!" + exit 1 +fi + +version="${BASH_REMATCH[1]}" +date="${BASH_REMATCH[2]}" +notes="$(echo "${BASH_REMATCH[3]}" | sed -n -E '/^[0-9]+\.[0-9]+\.[0-9]+/,$!p')" + +if [[ "$date" != $(date +"%Y-%m-%d") ]]; then + echo "$date is not today!" + exit 1 +fi + +tag="v$version" + +if [ -n "$(git status --porcelain)" ]; then + echo ". is not clean." >&2 + exit 1 +fi + +php composer.phar self-update +php composer.phar update + +./vendor/bin/phpunit + +echo "Release notes for $tag:" +echo "$notes" + +read -e -p "Commit changes and push to origin? " should_push + +if [ "$should_push" != "y" ]; then + echo "Aborting" + exit 1 +fi + +git push + +gh release create --target "$(git branch --show-current)" -t "$version" -n "$notes" "$tag" + +git push --tags diff --git a/tools/geoip/maxmind/web-service-common/phpstan.neon b/tools/geoip/maxmind/web-service-common/phpstan.neon new file mode 100644 index 000000000..d8a2bce7a --- /dev/null +++ b/tools/geoip/maxmind/web-service-common/phpstan.neon @@ -0,0 +1,6 @@ +parameters: + level: 6 + paths: + - src + - tests + diff --git a/tools/geoip/maxmind/web-service-common/src/Exception/AuthenticationException.php b/tools/geoip/maxmind/web-service-common/src/Exception/AuthenticationException.php new file mode 100644 index 000000000..9e045d2ec --- /dev/null +++ b/tools/geoip/maxmind/web-service-common/src/Exception/AuthenticationException.php @@ -0,0 +1,11 @@ +uri = $uri; + parent::__construct($message, $httpStatus, $previous); + } + + public function getUri(): string + { + return $this->uri; + } + + public function getStatusCode(): int + { + return $this->getCode(); + } +} diff --git a/tools/geoip/maxmind/web-service-common/src/Exception/InsufficientFundsException.php b/tools/geoip/maxmind/web-service-common/src/Exception/InsufficientFundsException.php new file mode 100644 index 000000000..a29da89f3 --- /dev/null +++ b/tools/geoip/maxmind/web-service-common/src/Exception/InsufficientFundsException.php @@ -0,0 +1,11 @@ +error = $error; + parent::__construct($message, $httpStatus, $uri, $previous); + } + + public function getErrorCode(): string + { + return $this->error; + } +} diff --git a/tools/geoip/maxmind/web-service-common/src/Exception/IpAddressNotFoundException.php b/tools/geoip/maxmind/web-service-common/src/Exception/IpAddressNotFoundException.php new file mode 100644 index 000000000..b3bf84d59 --- /dev/null +++ b/tools/geoip/maxmind/web-service-common/src/Exception/IpAddressNotFoundException.php @@ -0,0 +1,8 @@ + $options an array of options. Possible keys: + * * `host` - The host to use when connecting to the web service. + * * `useHttps` - Set to false to disable HTTPS. + * * `userAgent` - The prefix of the User-Agent to use in the request. + * * `caBundle` - The bundle of CA root certificates to use in the request. + * * `connectTimeout` - The connect timeout to use for the request. + * * `timeout` - The timeout to use for the request. + * * `proxy` - The HTTP proxy to use. May include a schema, port, + * username, and password, e.g., `http://username:password@127.0.0.1:10`. + */ + public function __construct( + int $accountId, + string $licenseKey, + array $options = [] + ) { + $this->accountId = $accountId; + $this->licenseKey = $licenseKey; + + $this->httpRequestFactory = isset($options['httpRequestFactory']) + ? $options['httpRequestFactory'] + : new RequestFactory(); + + if (isset($options['host'])) { + $this->host = $options['host']; + } + if (isset($options['useHttps'])) { + $this->useHttps = $options['useHttps']; + } + if (isset($options['userAgent'])) { + $this->userAgentPrefix = $options['userAgent'] . ' '; + } + + $this->caBundle = isset($options['caBundle']) ? + $this->caBundle = $options['caBundle'] : $this->getCaBundle(); + + if (isset($options['connectTimeout'])) { + $this->connectTimeout = $options['connectTimeout']; + } + if (isset($options['timeout'])) { + $this->timeout = $options['timeout']; + } + + if (isset($options['proxy'])) { + $this->proxy = $options['proxy']; + } + } + + /** + * @param string $service name of the service querying + * @param string $path the URI path to use + * @param array $input the data to be posted as JSON + * + * @throws InvalidInputException when the request has missing or invalid + * data + * @throws AuthenticationException when there is an issue authenticating the + * request + * @throws InsufficientFundsException when your account is out of funds + * @throws InvalidRequestException when the request is invalid for some + * other reason, e.g., invalid JSON in the POST. + * @throws HttpException when an unexpected HTTP error occurs + * @throws WebServiceException when some other error occurs. This also + * serves as the base class for the above exceptions. + * + * @return array|null The decoded content of a successful response + */ + public function post(string $service, string $path, array $input): ?array + { + $requestBody = json_encode($input); + if ($requestBody === false) { + throw new InvalidInputException( + 'Error encoding input as JSON: ' + . $this->jsonErrorDescription() + ); + } + + $request = $this->createRequest( + $path, + ['Content-Type: application/json'] + ); + + [$statusCode, $contentType, $responseBody] = $request->post($requestBody); + + return $this->handleResponse( + $statusCode, + $contentType, + $responseBody, + $service, + $path + ); + } + + /** + * @return array|null + */ + public function get(string $service, string $path): ?array + { + $request = $this->createRequest( + $path + ); + + [$statusCode, $contentType, $responseBody] = $request->get(); + + return $this->handleResponse( + $statusCode, + $contentType, + $responseBody, + $service, + $path + ); + } + + private function userAgent(): string + { + $curlVersion = curl_version(); + + return $this->userAgentPrefix . 'MaxMind-WS-API/' . self::VERSION . ' PHP/' . \PHP_VERSION . + ' curl/' . $curlVersion['version']; + } + + /** + * @param array $headers + */ + private function createRequest(string $path, array $headers = []): Http\Request + { + array_push( + $headers, + 'Authorization: Basic ' + . base64_encode($this->accountId . ':' . $this->licenseKey), + 'Accept: application/json' + ); + + return $this->httpRequestFactory->request( + $this->urlFor($path), + [ + 'caBundle' => $this->caBundle, + 'connectTimeout' => $this->connectTimeout, + 'headers' => $headers, + 'proxy' => $this->proxy, + 'timeout' => $this->timeout, + 'userAgent' => $this->userAgent(), + ] + ); + } + + /** + * @param int $statusCode the HTTP status code of the response + * @param string|null $contentType the Content-Type of the response + * @param string|null $responseBody the response body + * @param string $service the name of the service + * @param string $path the path used in the request + * + * @throws AuthenticationException when there is an issue authenticating the + * request + * @throws InsufficientFundsException when your account is out of funds + * @throws InvalidRequestException when the request is invalid for some + * other reason, e.g., invalid JSON in the POST. + * @throws HttpException when an unexpected HTTP error occurs + * @throws WebServiceException when some other error occurs. This also + * serves as the base class for the above exceptions + * + * @return array|null The decoded content of a successful response + */ + private function handleResponse( + int $statusCode, + ?string $contentType, + ?string $responseBody, + string $service, + string $path + ): ?array { + if ($statusCode >= 400 && $statusCode <= 499) { + $this->handle4xx($statusCode, $contentType, $responseBody, $service, $path); + } elseif ($statusCode >= 500) { + $this->handle5xx($statusCode, $service, $path); + } elseif ($statusCode !== 200 && $statusCode !== 204) { + $this->handleUnexpectedStatus($statusCode, $service, $path); + } + + return $this->handleSuccess($statusCode, $responseBody, $service); + } + + /** + * @return string describing the JSON error + */ + private function jsonErrorDescription(): string + { + $errno = json_last_error(); + + switch ($errno) { + case \JSON_ERROR_DEPTH: + return 'The maximum stack depth has been exceeded.'; + + case \JSON_ERROR_STATE_MISMATCH: + return 'Invalid or malformed JSON.'; + + case \JSON_ERROR_CTRL_CHAR: + return 'Control character error.'; + + case \JSON_ERROR_SYNTAX: + return 'Syntax error.'; + + case \JSON_ERROR_UTF8: + return 'Malformed UTF-8 characters.'; + + default: + return "Other JSON error ($errno)."; + } + } + + /** + * @param string $path the path to use in the URL + * + * @return string the constructed URL + */ + private function urlFor(string $path): string + { + return ($this->useHttps ? 'https://' : 'http://') . $this->host . $path; + } + + /** + * @param int $statusCode the HTTP status code + * @param string|null $contentType the response content-type + * @param string|null $body the response body + * @param string $service the service name + * @param string $path the path used in the request + * + * @throws AuthenticationException + * @throws HttpException + * @throws InsufficientFundsException + * @throws InvalidRequestException + */ + private function handle4xx( + int $statusCode, + ?string $contentType, + ?string $body, + string $service, + string $path + ): void { + if ($body === null || $body === '') { + throw new HttpException( + "Received a $statusCode error for $service with no body", + $statusCode, + $this->urlFor($path) + ); + } + if ($contentType === null || !strstr($contentType, 'json')) { + throw new HttpException( + "Received a $statusCode error for $service with " . + 'the following body: ' . $body, + $statusCode, + $this->urlFor($path) + ); + } + + $message = json_decode($body, true); + if ($message === null) { + throw new HttpException( + "Received a $statusCode error for $service but could " . + 'not decode the response as JSON: ' + . $this->jsonErrorDescription() . ' Body: ' . $body, + $statusCode, + $this->urlFor($path) + ); + } + + if (!isset($message['code']) || !isset($message['error'])) { + throw new HttpException( + 'Error response contains JSON but it does not ' . + 'specify code or error keys: ' . $body, + $statusCode, + $this->urlFor($path) + ); + } + + $this->handleWebServiceError( + $message['error'], + $message['code'], + $statusCode, + $path + ); + } + + /** + * @param string $message the error message from the web service + * @param string $code the error code from the web service + * @param int $statusCode the HTTP status code + * @param string $path the path used in the request + * + * @throws AuthenticationException + * @throws InvalidRequestException + * @throws InsufficientFundsException + */ + private function handleWebServiceError( + string $message, + string $code, + int $statusCode, + string $path + ): void { + switch ($code) { + case 'IP_ADDRESS_NOT_FOUND': + case 'IP_ADDRESS_RESERVED': + throw new IpAddressNotFoundException( + $message, + $code, + $statusCode, + $this->urlFor($path) + ); + + case 'ACCOUNT_ID_REQUIRED': + case 'ACCOUNT_ID_UNKNOWN': + case 'AUTHORIZATION_INVALID': + case 'LICENSE_KEY_REQUIRED': + case 'USER_ID_REQUIRED': + case 'USER_ID_UNKNOWN': + throw new AuthenticationException( + $message, + $code, + $statusCode, + $this->urlFor($path) + ); + + case 'OUT_OF_QUERIES': + case 'INSUFFICIENT_FUNDS': + throw new InsufficientFundsException( + $message, + $code, + $statusCode, + $this->urlFor($path) + ); + + case 'PERMISSION_REQUIRED': + throw new PermissionRequiredException( + $message, + $code, + $statusCode, + $this->urlFor($path) + ); + + default: + throw new InvalidRequestException( + $message, + $code, + $statusCode, + $this->urlFor($path) + ); + } + } + + /** + * @param int $statusCode the HTTP status code + * @param string $service the service name + * @param string $path the URI path used in the request + * + * @throws HttpException + */ + private function handle5xx(int $statusCode, string $service, string $path): void + { + throw new HttpException( + "Received a server error ($statusCode) for $service", + $statusCode, + $this->urlFor($path) + ); + } + + /** + * @param int $statusCode the HTTP status code + * @param string $service the service name + * @param string $path the URI path used in the request + * + * @throws HttpException + */ + private function handleUnexpectedStatus(int $statusCode, string $service, string $path): void + { + throw new HttpException( + 'Received an unexpected HTTP status ' . + "($statusCode) for $service", + $statusCode, + $this->urlFor($path) + ); + } + + /** + * @param int $statusCode the HTTP status code + * @param string|null $body the successful request body + * @param string $service the service name + * + * @throws WebServiceException if a response body is included but not + * expected, or is not expected but not + * included, or is expected and included + * but cannot be decoded as JSON + * + * @return array|null the decoded request body + */ + private function handleSuccess(int $statusCode, ?string $body, string $service): ?array + { + // A 204 should have no response body + if ($statusCode === 204) { + if ($body !== null && $body !== '') { + throw new WebServiceException( + "Received a 204 response for $service along with an " . + "unexpected HTTP body: $body" + ); + } + + return null; + } + + // A 200 should have a valid JSON body + if ($body === null || $body === '') { + throw new WebServiceException( + "Received a 200 response for $service but did not " . + 'receive a HTTP body.' + ); + } + + $decodedContent = json_decode($body, true); + if ($decodedContent === null) { + throw new WebServiceException( + "Received a 200 response for $service but could " . + 'not decode the response as JSON: ' + . $this->jsonErrorDescription() . ' Body: ' . $body + ); + } + + return $decodedContent; + } + + private function getCaBundle(): ?string + { + $curlVersion = curl_version(); + + // On OS X, when the SSL version is "SecureTransport", the system's + // keychain will be used. + if ($curlVersion['ssl_version'] === 'SecureTransport') { + return null; + } + $cert = CaBundle::getSystemCaRootBundlePath(); + + // Check if the cert is inside a phar. If so, we need to copy the cert + // to a temp file so that curl can see it. + if (substr($cert, 0, 7) === 'phar://') { + $tempDir = sys_get_temp_dir(); + $newCert = tempnam($tempDir, 'geoip2-'); + if ($newCert === false) { + throw new \RuntimeException( + "Unable to create temporary file in $tempDir" + ); + } + if (!copy($cert, $newCert)) { + throw new \RuntimeException( + "Could not copy $cert to $newCert: " + . var_export(error_get_last(), true) + ); + } + + // We use a shutdown function rather than the destructor as the + // destructor isn't called on a fatal error such as an uncaught + // exception. + register_shutdown_function( + function () use ($newCert) { + unlink($newCert); + } + ); + $cert = $newCert; + } + if (!file_exists($cert)) { + throw new \RuntimeException("CA cert does not exist at $cert"); + } + + return $cert; + } +} diff --git a/tools/geoip/maxmind/web-service-common/src/WebService/Http/CurlRequest.php b/tools/geoip/maxmind/web-service-common/src/WebService/Http/CurlRequest.php new file mode 100644 index 000000000..73b551fbe --- /dev/null +++ b/tools/geoip/maxmind/web-service-common/src/WebService/Http/CurlRequest.php @@ -0,0 +1,146 @@ + + */ + private $options; + + /** + * @param array $options + */ + public function __construct(string $url, array $options) + { + $this->url = $url; + $this->options = $options; + $this->ch = $options['curlHandle']; + } + + /** + * @throws HttpException + * + * @return array{0:int, 1:string|null, 2:string|null} + */ + public function post(string $body): array + { + $curl = $this->createCurl(); + + curl_setopt($curl, \CURLOPT_POST, true); + curl_setopt($curl, \CURLOPT_POSTFIELDS, $body); + + return $this->execute($curl); + } + + /** + * @return array{0:int, 1:string|null, 2:string|null} + */ + public function get(): array + { + $curl = $this->createCurl(); + + curl_setopt($curl, \CURLOPT_HTTPGET, true); + + return $this->execute($curl); + } + + /** + * @return \CurlHandle + */ + private function createCurl() + { + curl_reset($this->ch); + + $opts = []; + $opts[\CURLOPT_URL] = $this->url; + + if (!empty($this->options['caBundle'])) { + $opts[\CURLOPT_CAINFO] = $this->options['caBundle']; + } + + $opts[\CURLOPT_ENCODING] = ''; + $opts[\CURLOPT_SSL_VERIFYHOST] = 2; + $opts[\CURLOPT_FOLLOWLOCATION] = false; + $opts[\CURLOPT_SSL_VERIFYPEER] = true; + $opts[\CURLOPT_RETURNTRANSFER] = true; + + $opts[\CURLOPT_HTTPHEADER] = $this->options['headers']; + $opts[\CURLOPT_USERAGENT] = $this->options['userAgent']; + $opts[\CURLOPT_PROXY] = $this->options['proxy']; + + // The defined()s are here as the *_MS opts are not available on older + // cURL versions + $connectTimeout = $this->options['connectTimeout']; + if (\defined('CURLOPT_CONNECTTIMEOUT_MS')) { + $opts[\CURLOPT_CONNECTTIMEOUT_MS] = ceil($connectTimeout * 1000); + } else { + $opts[\CURLOPT_CONNECTTIMEOUT] = ceil($connectTimeout); + } + + $timeout = $this->options['timeout']; + if (\defined('CURLOPT_TIMEOUT_MS')) { + $opts[\CURLOPT_TIMEOUT_MS] = ceil($timeout * 1000); + } else { + $opts[\CURLOPT_TIMEOUT] = ceil($timeout); + } + + curl_setopt_array($this->ch, $opts); + + return $this->ch; + } + + /** + * @param \CurlHandle $curl + * + * @throws HttpException + * + * @return array{0:int, 1:string|null, 2:string|null} + */ + private function execute($curl): array + { + $body = curl_exec($curl); + if ($errno = curl_errno($curl)) { + $errorMessage = curl_error($curl); + + throw new HttpException( + "cURL error ({$errno}): {$errorMessage}", + 0, + $this->url + ); + } + + $statusCode = curl_getinfo($curl, \CURLINFO_HTTP_CODE); + $contentType = curl_getinfo($curl, \CURLINFO_CONTENT_TYPE); + + return [ + $statusCode, + // The PHP docs say "Content-Type: of the requested document. NULL + // indicates server did not send valid Content-Type: header" for + // CURLINFO_CONTENT_TYPE. However, it will return FALSE if no header + // is set. To keep our types simple, we return null in this case. + $contentType === false ? null : $contentType, + $body, + ]; + } +} diff --git a/tools/geoip/maxmind/web-service-common/src/WebService/Http/Request.php b/tools/geoip/maxmind/web-service-common/src/WebService/Http/Request.php new file mode 100644 index 000000000..9a03e5fac --- /dev/null +++ b/tools/geoip/maxmind/web-service-common/src/WebService/Http/Request.php @@ -0,0 +1,28 @@ + $options + */ + public function __construct(string $url, array $options); + + /** + * @return array{0:int, 1:string|null, 2:string|null} + */ + public function post(string $body): array; + + /** + * @return array{0:int, 1:string|null, 2:string|null} + */ + public function get(): array; +} diff --git a/tools/geoip/maxmind/web-service-common/src/WebService/Http/RequestFactory.php b/tools/geoip/maxmind/web-service-common/src/WebService/Http/RequestFactory.php new file mode 100644 index 000000000..12b0421f9 --- /dev/null +++ b/tools/geoip/maxmind/web-service-common/src/WebService/Http/RequestFactory.php @@ -0,0 +1,51 @@ +ch)) { + curl_close($this->ch); + } + } + + /** + * @return \CurlHandle + */ + private function getCurlHandle() + { + if (empty($this->ch)) { + $this->ch = curl_init(); + } + + return $this->ch; + } + + /** + * @param array $options + */ + public function request(string $url, array $options): Request + { + $options['curlHandle'] = $this->getCurlHandle(); + + return new CurlRequest($url, $options); + } +} diff --git a/tools/htmlpurifier/HTMLPurifier.autoload-legacy.php b/tools/htmlpurifier/HTMLPurifier.autoload-legacy.php index c271cd158..0a17ee4ad 100644 --- a/tools/htmlpurifier/HTMLPurifier.autoload-legacy.php +++ b/tools/htmlpurifier/HTMLPurifier.autoload-legacy.php @@ -4,12 +4,11 @@ * @file * Legacy autoloader for systems lacking spl_autoload_register * - * Must be separate to prevent deprecation warning on PHP 7.2 */ -function __autoload($class) +spl_autoload_register(function($class) { - return HTMLPurifier_Bootstrap::autoload($class); -} + return HTMLPurifier_Bootstrap::autoload($class); +}); // vim: et sw=4 sts=4 diff --git a/tools/htmlpurifier/HTMLPurifier.autoload.php b/tools/htmlpurifier/HTMLPurifier.autoload.php index 9d8d29926..7a691132f 100644 --- a/tools/htmlpurifier/HTMLPurifier.autoload.php +++ b/tools/htmlpurifier/HTMLPurifier.autoload.php @@ -17,6 +17,7 @@ if (function_exists('spl_autoload_register') && function_exists('spl_autoload_un require dirname(__FILE__) . '/HTMLPurifier.autoload-legacy.php'; } +// phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.zend_ze1_compatibility_modeRemoved if (ini_get('zend.ze1_compatibility_mode')) { trigger_error("HTML Purifier is not compatible with zend.ze1_compatibility_mode; please turn it off", E_USER_ERROR); } diff --git a/tools/htmlpurifier/HTMLPurifier.includes.php b/tools/htmlpurifier/HTMLPurifier.includes.php index 151e6752d..4c713a33a 100644 --- a/tools/htmlpurifier/HTMLPurifier.includes.php +++ b/tools/htmlpurifier/HTMLPurifier.includes.php @@ -7,7 +7,7 @@ * primary concern and you are using an opcode cache. PLEASE DO NOT EDIT THIS * FILE, changes will be overwritten the next time the script is run. * - * @version 4.13.0 + * @version 4.18.0 * * @warning * You must *not* include any other HTML Purifier files before this file, @@ -101,12 +101,14 @@ require 'HTMLPurifier/AttrDef/CSS/Length.php'; require 'HTMLPurifier/AttrDef/CSS/ListStyle.php'; require 'HTMLPurifier/AttrDef/CSS/Multiple.php'; require 'HTMLPurifier/AttrDef/CSS/Percentage.php'; +require 'HTMLPurifier/AttrDef/CSS/Ratio.php'; require 'HTMLPurifier/AttrDef/CSS/TextDecoration.php'; require 'HTMLPurifier/AttrDef/CSS/URI.php'; require 'HTMLPurifier/AttrDef/HTML/Bool.php'; require 'HTMLPurifier/AttrDef/HTML/Nmtokens.php'; require 'HTMLPurifier/AttrDef/HTML/Class.php'; require 'HTMLPurifier/AttrDef/HTML/Color.php'; +require 'HTMLPurifier/AttrDef/HTML/ContentEditable.php'; require 'HTMLPurifier/AttrDef/HTML/FrameTarget.php'; require 'HTMLPurifier/AttrDef/HTML/ID.php'; require 'HTMLPurifier/AttrDef/HTML/Pixels.php'; diff --git a/tools/htmlpurifier/HTMLPurifier.php b/tools/htmlpurifier/HTMLPurifier.php index 3c0f8a0ec..e3bca8a22 100644 --- a/tools/htmlpurifier/HTMLPurifier.php +++ b/tools/htmlpurifier/HTMLPurifier.php @@ -19,7 +19,7 @@ */ /* - HTML Purifier 4.13.0 - Standards Compliant HTML Filtering + HTML Purifier 4.18.0 - Standards Compliant HTML Filtering Copyright (C) 2006-2008 Edward Z. Yang This library is free software; you can redistribute it and/or @@ -58,12 +58,12 @@ class HTMLPurifier * Version of HTML Purifier. * @type string */ - public $version = '4.13.0'; + public $version = '4.18.0'; /** * Constant with version of HTML Purifier. */ - const VERSION = '4.13.0'; + const VERSION = '4.18.0'; /** * Global configuration object. diff --git a/tools/htmlpurifier/HTMLPurifier.safe-includes.php b/tools/htmlpurifier/HTMLPurifier.safe-includes.php index a3261f8a3..8a417d246 100644 --- a/tools/htmlpurifier/HTMLPurifier.safe-includes.php +++ b/tools/htmlpurifier/HTMLPurifier.safe-includes.php @@ -95,12 +95,14 @@ require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Length.php'; require_once $__dir . '/HTMLPurifier/AttrDef/CSS/ListStyle.php'; require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Multiple.php'; require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Percentage.php'; +require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Ratio.php'; require_once $__dir . '/HTMLPurifier/AttrDef/CSS/TextDecoration.php'; require_once $__dir . '/HTMLPurifier/AttrDef/CSS/URI.php'; require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Bool.php'; require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Nmtokens.php'; require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Class.php'; require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Color.php'; +require_once $__dir . '/HTMLPurifier/AttrDef/HTML/ContentEditable.php'; require_once $__dir . '/HTMLPurifier/AttrDef/HTML/FrameTarget.php'; require_once $__dir . '/HTMLPurifier/AttrDef/HTML/ID.php'; require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Pixels.php'; diff --git a/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS.php b/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS.php index ad2cb90ad..af6b8a05d 100644 --- a/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS.php +++ b/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS.php @@ -27,6 +27,13 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef $definition = $config->getCSSDefinition(); $allow_duplicates = $config->get("CSS.AllowDuplicates"); + $universal_attrdef = new HTMLPurifier_AttrDef_Enum( + array( + 'initial', + 'inherit', + 'unset', + ) + ); // According to the CSS2.1 spec, the places where a // non-delimiting semicolon can appear are in strings @@ -96,16 +103,13 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef if (!$ok) { continue; } - // inefficient call, since the validator will do this again - if (strtolower(trim($value)) !== 'inherit') { - // inherit works for everything (but only on the base property) + $result = $universal_attrdef->validate($value, $config, $context); + if ($result === false) { $result = $definition->info[$property]->validate( $value, $config, $context ); - } else { - $result = 'inherit'; } if ($result === false) { continue; diff --git a/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/Background.php b/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/Background.php index 7f1ea3b0f..28c49883a 100644 --- a/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/Background.php +++ b/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/Background.php @@ -25,6 +25,7 @@ class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef $this->info['background-repeat'] = $def->info['background-repeat']; $this->info['background-attachment'] = $def->info['background-attachment']; $this->info['background-position'] = $def->info['background-position']; + $this->info['background-size'] = $def->info['background-size']; } /** @@ -53,6 +54,7 @@ class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef $caught['repeat'] = false; $caught['attachment'] = false; $caught['position'] = false; + $caught['size'] = false; $i = 0; // number of catches diff --git a/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php b/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php index 74e24c881..f1ff11636 100644 --- a/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php +++ b/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/FontFamily.php @@ -10,23 +10,21 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef public function __construct() { - $this->mask = '_- '; - for ($c = 'a'; $c <= 'z'; $c++) { - $this->mask .= $c; - } - for ($c = 'A'; $c <= 'Z'; $c++) { - $this->mask .= $c; - } - for ($c = '0'; $c <= '9'; $c++) { - $this->mask .= $c; - } // cast-y, but should be fine - // special bytes used by UTF-8 - for ($i = 0x80; $i <= 0xFF; $i++) { - // We don't bother excluding invalid bytes in this range, - // because the our restriction of well-formed UTF-8 will - // prevent these from ever occurring. - $this->mask .= chr($i); - } + // Lowercase letters + $l = range('a', 'z'); + // Uppercase letters + $u = range('A', 'Z'); + // Digits + $d = range('0', '9'); + // Special bytes used by UTF-8 + $b = array_map('chr', range(0x80, 0xFF)); + // All valid characters for the mask + $c = array_merge($l, $u, $d, $b); + // Concatenate all valid characters into a string + // Use '_- ' as an initial value + $this->mask = array_reduce($c, function ($carry, $value) { + return $carry . $value; + }, '_- '); /* PHP's internal strcspn implementation is diff --git a/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/Ratio.php b/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/Ratio.php new file mode 100644 index 000000000..e08e2c496 --- /dev/null +++ b/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/Ratio.php @@ -0,0 +1,46 @@ +parseCDATA($ratio); + + $parts = explode('/', $ratio, 2); + $length = count($parts); + + if ($length < 1 || $length > 2) { + return false; + } + + $num = new \HTMLPurifier_AttrDef_CSS_Number(); + + if ($length === 1) { + return $num->validate($parts[0], $config, $context); + } + + $num1 = $num->validate($parts[0], $config, $context); + $num2 = $num->validate($parts[1], $config, $context); + + if ($num1 === false || $num2 === false) { + return false; + } + + return $num1 . '/' . $num2; + } +} + +// vim: et sw=4 sts=4 diff --git a/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/index.php b/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/AttrDef/CSS/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/AttrDef/HTML/ContentEditable.php b/tools/htmlpurifier/HTMLPurifier/AttrDef/HTML/ContentEditable.php new file mode 100644 index 000000000..5b03d3e37 --- /dev/null +++ b/tools/htmlpurifier/HTMLPurifier/AttrDef/HTML/ContentEditable.php @@ -0,0 +1,16 @@ +get('HTML.Trusted')) { + $allowed = array('', 'true', 'false'); + } + + $enum = new HTMLPurifier_AttrDef_Enum($allowed); + + return $enum->validate($string, $config, $context); + } +} diff --git a/tools/htmlpurifier/HTMLPurifier/AttrDef/HTML/index.php b/tools/htmlpurifier/HTMLPurifier/AttrDef/HTML/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/AttrDef/HTML/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/AttrDef/URI/Host.php b/tools/htmlpurifier/HTMLPurifier/AttrDef/URI/Host.php index 1beeaa5d2..17a97c1ec 100644 --- a/tools/htmlpurifier/HTMLPurifier/AttrDef/URI/Host.php +++ b/tools/htmlpurifier/HTMLPurifier/AttrDef/URI/Host.php @@ -63,24 +63,18 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef // This doesn't match I18N domain names, but we don't have proper IRI support, // so force users to insert Punycode. - // There is not a good sense in which underscores should be - // allowed, since it's technically not! (And if you go as - // far to allow everything as specified by the DNS spec... - // well, that's literally everything, modulo some space limits - // for the components and the overall name (which, by the way, - // we are NOT checking!). So we (arbitrarily) decide this: - // let's allow underscores wherever we would have allowed - // hyphens, if they are enabled. This is a pretty good match - // for browser behavior, for example, a large number of browsers - // cannot handle foo_.example.com, but foo_bar.example.com is - // fairly well supported. + // Underscores defined as Unreserved Characters in RFC 3986 are + // allowed in a URI. There are cases where we want to consider a + // URI containing "_" such as "_dmarc.example.com". + // Underscores are not allowed in the default. If you want to + // allow it, set Core.AllowHostnameUnderscore to true. $underscore = $config->get('Core.AllowHostnameUnderscore') ? '_' : ''; // Based off of RFC 1738, but amended so that // as per RFC 3696, the top label need only not be all numeric. // The productions describing this are: $a = '[a-z]'; // alpha - $an = '[a-z0-9]'; // alphanum + $an = "[a-z0-9$underscore]"; // alphanum $and = "[a-z0-9-$underscore]"; // alphanum | "-" // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum $domainlabel = "$an(?:$and*$an)?"; @@ -106,7 +100,7 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef // If we have Net_IDNA2 support, we can support IRIs by // punycoding them. (This is the most portable thing to do, // since otherwise we have to assume browsers support - } elseif ($config->get('Core.EnableIDNA')) { + } elseif ($config->get('Core.EnableIDNA') && class_exists('Net_IDNA2')) { $idna = new Net_IDNA2(array('encoding' => 'utf8', 'overlong' => false, 'strict' => true)); // we need to encode each period separately $parts = explode('.', $string); diff --git a/tools/htmlpurifier/HTMLPurifier/AttrDef/URI/index.php b/tools/htmlpurifier/HTMLPurifier/AttrDef/URI/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/AttrDef/URI/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/AttrDef/index.php b/tools/htmlpurifier/HTMLPurifier/AttrDef/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/AttrDef/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/AttrTransform/NameSync.php b/tools/htmlpurifier/HTMLPurifier/AttrTransform/NameSync.php index 36079b786..5a1fdbbfc 100644 --- a/tools/htmlpurifier/HTMLPurifier/AttrTransform/NameSync.php +++ b/tools/htmlpurifier/HTMLPurifier/AttrTransform/NameSync.php @@ -8,6 +8,11 @@ class HTMLPurifier_AttrTransform_NameSync extends HTMLPurifier_AttrTransform { + /** + * @type HTMLPurifier_AttrDef_HTML_ID + */ + public $idDef; + public function __construct() { $this->idDef = new HTMLPurifier_AttrDef_HTML_ID(); diff --git a/tools/htmlpurifier/HTMLPurifier/AttrTransform/SafeParam.php b/tools/htmlpurifier/HTMLPurifier/AttrTransform/SafeParam.php index 1143b4b49..1033106b3 100644 --- a/tools/htmlpurifier/HTMLPurifier/AttrTransform/SafeParam.php +++ b/tools/htmlpurifier/HTMLPurifier/AttrTransform/SafeParam.php @@ -24,6 +24,11 @@ class HTMLPurifier_AttrTransform_SafeParam extends HTMLPurifier_AttrTransform */ private $uri; + /** + * @type HTMLPurifier_AttrDef_Enum + */ + public $wmode; + public function __construct() { $this->uri = new HTMLPurifier_AttrDef_URI(true); // embedded diff --git a/tools/htmlpurifier/HTMLPurifier/AttrTransform/TargetBlank.php b/tools/htmlpurifier/HTMLPurifier/AttrTransform/TargetBlank.php index dd63ea89c..cc30ab8c3 100644 --- a/tools/htmlpurifier/HTMLPurifier/AttrTransform/TargetBlank.php +++ b/tools/htmlpurifier/HTMLPurifier/AttrTransform/TargetBlank.php @@ -33,7 +33,11 @@ class HTMLPurifier_AttrTransform_TargetBlank extends HTMLPurifier_AttrTransform // XXX Kind of inefficient $url = $this->parser->parse($attr['href']); - $scheme = $url->getSchemeObj($config, $context); + + // Ignore invalid schemes (e.g. `javascript:`) + if (!($scheme = $url->getSchemeObj($config, $context))) { + return $attr; + } if ($scheme->browsable && !$url->isBenign($config, $context)) { $attr['target'] = '_blank'; diff --git a/tools/htmlpurifier/HTMLPurifier/AttrTransform/index.php b/tools/htmlpurifier/HTMLPurifier/AttrTransform/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/AttrTransform/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/AttrTypes.php b/tools/htmlpurifier/HTMLPurifier/AttrTypes.php index 3b70520b6..e4429e86d 100644 --- a/tools/htmlpurifier/HTMLPurifier/AttrTypes.php +++ b/tools/htmlpurifier/HTMLPurifier/AttrTypes.php @@ -41,6 +41,7 @@ class HTMLPurifier_AttrTypes $this->info['IAlign'] = self::makeEnum('top,middle,bottom,left,right'); $this->info['LAlign'] = self::makeEnum('top,bottom,left,right'); $this->info['FrameTarget'] = new HTMLPurifier_AttrDef_HTML_FrameTarget(); + $this->info['ContentEditable'] = new HTMLPurifier_AttrDef_HTML_ContentEditable(); // unimplemented aliases $this->info['ContentType'] = new HTMLPurifier_AttrDef_Text(); diff --git a/tools/htmlpurifier/HTMLPurifier/Bootstrap.php b/tools/htmlpurifier/HTMLPurifier/Bootstrap.php index 707122bb2..bd8f9984f 100644 --- a/tools/htmlpurifier/HTMLPurifier/Bootstrap.php +++ b/tools/htmlpurifier/HTMLPurifier/Bootstrap.php @@ -79,44 +79,11 @@ class HTMLPurifier_Bootstrap public static function registerAutoload() { $autoload = array('HTMLPurifier_Bootstrap', 'autoload'); - if (($funcs = spl_autoload_functions()) === false) { + if (spl_autoload_functions() === false) { spl_autoload_register($autoload); - } elseif (function_exists('spl_autoload_unregister')) { - if (version_compare(PHP_VERSION, '5.3.0', '>=')) { - // prepend flag exists, no need for shenanigans - spl_autoload_register($autoload, true, true); - } else { - $buggy = version_compare(PHP_VERSION, '5.2.11', '<'); - $compat = version_compare(PHP_VERSION, '5.1.2', '<=') && - version_compare(PHP_VERSION, '5.1.0', '>='); - foreach ($funcs as $func) { - if ($buggy && is_array($func)) { - // :TRICKY: There are some compatibility issues and some - // places where we need to error out - $reflector = new ReflectionMethod($func[0], $func[1]); - if (!$reflector->isStatic()) { - throw new Exception( - 'HTML Purifier autoloader registrar is not compatible - with non-static object methods due to PHP Bug #44144; - Please do not use HTMLPurifier.autoload.php (or any - file that includes this file); instead, place the code: - spl_autoload_register(array(\'HTMLPurifier_Bootstrap\', \'autoload\')) - after your own autoloaders.' - ); - } - // Suprisingly, spl_autoload_register supports the - // Class::staticMethod callback format, although call_user_func doesn't - if ($compat) { - $func = implode('::', $func); - } - } - spl_autoload_unregister($func); - } - spl_autoload_register($autoload); - foreach ($funcs as $func) { - spl_autoload_register($func); - } - } + } else { + // prepend flag exists, no need for shenanigans + spl_autoload_register($autoload, true, true); } } } diff --git a/tools/htmlpurifier/HTMLPurifier/CSSDefinition.php b/tools/htmlpurifier/HTMLPurifier/CSSDefinition.php index 21f1a5899..3732c076a 100644 --- a/tools/htmlpurifier/HTMLPurifier/CSSDefinition.php +++ b/tools/htmlpurifier/HTMLPurifier/CSSDefinition.php @@ -13,7 +13,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition * Assoc array of attribute name to definition object. * @type HTMLPurifier_AttrDef[] */ - public $info = array(); + public $info = []; /** * Constructs the info array. The meat of this class. @@ -22,7 +22,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition protected function doSetup($config) { $this->info['text-align'] = new HTMLPurifier_AttrDef_Enum( - array('left', 'right', 'center', 'justify'), + ['left', 'right', 'center', 'justify'], false ); @@ -31,7 +31,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition $this->info['border-right-style'] = $this->info['border-left-style'] = $this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum( - array( + [ 'none', 'hidden', 'dotted', @@ -42,42 +42,42 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition 'ridge', 'inset', 'outset' - ), + ], false ); $this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style); $this->info['clear'] = new HTMLPurifier_AttrDef_Enum( - array('none', 'left', 'right', 'both'), + ['none', 'left', 'right', 'both'], false ); $this->info['float'] = new HTMLPurifier_AttrDef_Enum( - array('none', 'left', 'right'), + ['none', 'left', 'right'], false ); $this->info['font-style'] = new HTMLPurifier_AttrDef_Enum( - array('normal', 'italic', 'oblique'), + ['normal', 'italic', 'oblique'], false ); $this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum( - array('normal', 'small-caps'), + ['normal', 'small-caps'], false ); $uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite( - array( - new HTMLPurifier_AttrDef_Enum(array('none')), + [ + new HTMLPurifier_AttrDef_Enum(['none']), new HTMLPurifier_AttrDef_CSS_URI() - ) + ] ); $this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum( - array('inside', 'outside'), + ['inside', 'outside'], false ); $this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum( - array( + [ 'disc', 'circle', 'square', @@ -87,7 +87,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition 'lower-alpha', 'upper-alpha', 'none' - ), + ], false ); $this->info['list-style-image'] = $uri_or_none; @@ -95,30 +95,44 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition $this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config); $this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum( - array('capitalize', 'uppercase', 'lowercase', 'none'), + ['capitalize', 'uppercase', 'lowercase', 'none'], false ); $this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color(); $this->info['background-image'] = $uri_or_none; $this->info['background-repeat'] = new HTMLPurifier_AttrDef_Enum( - array('repeat', 'repeat-x', 'repeat-y', 'no-repeat') + ['repeat', 'repeat-x', 'repeat-y', 'no-repeat'] ); $this->info['background-attachment'] = new HTMLPurifier_AttrDef_Enum( - array('scroll', 'fixed') + ['scroll', 'fixed'] ); $this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition(); + $this->info['background-size'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum( + [ + 'auto', + 'cover', + 'contain', + ] + ), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_CSS_Length() + ] + ); + $border_color = $this->info['border-top-color'] = $this->info['border-bottom-color'] = $this->info['border-left-color'] = $this->info['border-right-color'] = $this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite( - array( - new HTMLPurifier_AttrDef_Enum(array('transparent')), + [ + new HTMLPurifier_AttrDef_Enum(['transparent']), new HTMLPurifier_AttrDef_CSS_Color() - ) + ] ); $this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config); @@ -130,32 +144,32 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition $this->info['border-bottom-width'] = $this->info['border-left-width'] = $this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite( - array( - new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')), + [ + new HTMLPurifier_AttrDef_Enum(['thin', 'medium', 'thick']), new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative - ) + ] ); $this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width); $this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite( - array( - new HTMLPurifier_AttrDef_Enum(array('normal')), + [ + new HTMLPurifier_AttrDef_Enum(['normal']), new HTMLPurifier_AttrDef_CSS_Length() - ) + ] ); $this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite( - array( - new HTMLPurifier_AttrDef_Enum(array('normal')), + [ + new HTMLPurifier_AttrDef_Enum(['normal']), new HTMLPurifier_AttrDef_CSS_Length() - ) + ] ); $this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite( - array( + [ new HTMLPurifier_AttrDef_Enum( - array( + [ 'xx-small', 'x-small', 'small', @@ -165,20 +179,20 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition 'xx-large', 'larger', 'smaller' - ) + ] ), new HTMLPurifier_AttrDef_CSS_Percentage(), new HTMLPurifier_AttrDef_CSS_Length() - ) + ] ); $this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite( - array( - new HTMLPurifier_AttrDef_Enum(array('normal')), + [ + new HTMLPurifier_AttrDef_Enum(['normal']), new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives new HTMLPurifier_AttrDef_CSS_Length('0'), new HTMLPurifier_AttrDef_CSS_Percentage(true) - ) + ] ); $margin = @@ -186,11 +200,11 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition $this->info['margin-bottom'] = $this->info['margin-left'] = $this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite( - array( + [ new HTMLPurifier_AttrDef_CSS_Length(), new HTMLPurifier_AttrDef_CSS_Percentage(), - new HTMLPurifier_AttrDef_Enum(array('auto')) - ) + new HTMLPurifier_AttrDef_Enum(['auto']) + ] ); $this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin); @@ -201,41 +215,40 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition $this->info['padding-bottom'] = $this->info['padding-left'] = $this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite( - array( + [ new HTMLPurifier_AttrDef_CSS_Length('0'), new HTMLPurifier_AttrDef_CSS_Percentage(true) - ) + ] ); $this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding); $this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite( - array( + [ new HTMLPurifier_AttrDef_CSS_Length(), new HTMLPurifier_AttrDef_CSS_Percentage() - ) + ] ); $trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite( - array( + [ new HTMLPurifier_AttrDef_CSS_Length('0'), new HTMLPurifier_AttrDef_CSS_Percentage(true), - new HTMLPurifier_AttrDef_Enum(array('auto', 'initial', 'inherit')) - ) + new HTMLPurifier_AttrDef_Enum(['auto']) + ] ); $trusted_min_wh = new HTMLPurifier_AttrDef_CSS_Composite( - array( + [ new HTMLPurifier_AttrDef_CSS_Length('0'), new HTMLPurifier_AttrDef_CSS_Percentage(true), - new HTMLPurifier_AttrDef_Enum(array('initial', 'inherit')) - ) + ] ); $trusted_max_wh = new HTMLPurifier_AttrDef_CSS_Composite( - array( + [ new HTMLPurifier_AttrDef_CSS_Length('0'), new HTMLPurifier_AttrDef_CSS_Percentage(true), - new HTMLPurifier_AttrDef_Enum(array('none', 'initial', 'inherit')) - ) + new HTMLPurifier_AttrDef_Enum(['none']) + ] ); $max = $config->get('CSS.MaxImgLength'); @@ -247,10 +260,10 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition 'img', // For img tags: new HTMLPurifier_AttrDef_CSS_Composite( - array( + [ new HTMLPurifier_AttrDef_CSS_Length('0', $max), - new HTMLPurifier_AttrDef_Enum(array('auto')) - ) + new HTMLPurifier_AttrDef_Enum(['auto']) + ] ), // For everyone else: $trusted_wh @@ -262,12 +275,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition new HTMLPurifier_AttrDef_Switch( 'img', // For img tags: - new HTMLPurifier_AttrDef_CSS_Composite( - array( - new HTMLPurifier_AttrDef_CSS_Length('0', $max), - new HTMLPurifier_AttrDef_Enum(array('initial', 'inherit')) - ) - ), + new HTMLPurifier_AttrDef_CSS_Length('0', $max), // For everyone else: $trusted_min_wh ); @@ -279,22 +287,46 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition 'img', // For img tags: new HTMLPurifier_AttrDef_CSS_Composite( - array( + [ new HTMLPurifier_AttrDef_CSS_Length('0', $max), - new HTMLPurifier_AttrDef_Enum(array('none', 'initial', 'inherit')) - ) + new HTMLPurifier_AttrDef_Enum(['none']) + ] ), // For everyone else: $trusted_max_wh ); + $this->info['aspect-ratio'] = new HTMLPurifier_AttrDef_CSS_Multiple( + new HTMLPurifier_AttrDef_CSS_Composite([ + new HTMLPurifier_AttrDef_CSS_Ratio(), + new HTMLPurifier_AttrDef_Enum(['auto']), + ]) + ); + + // text-decoration and related shorthands $this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration(); + $this->info['text-decoration-line'] = new HTMLPurifier_AttrDef_Enum( + ['none', 'underline', 'overline', 'line-through'] + ); + + $this->info['text-decoration-style'] = new HTMLPurifier_AttrDef_Enum( + ['solid', 'double', 'dotted', 'dashed', 'wavy'] + ); + + $this->info['text-decoration-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + + $this->info['text-decoration-thickness'] = new HTMLPurifier_AttrDef_CSS_Composite([ + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_Enum(['auto', 'from-font']) + ]); + $this->info['font-family'] = new HTMLPurifier_AttrDef_CSS_FontFamily(); // this could use specialized code $this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum( - array( + [ 'normal', 'bold', 'bolder', @@ -308,7 +340,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition '700', '800', '900' - ), + ], false ); @@ -324,21 +356,21 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition $this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config); $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum( - array('collapse', 'separate') + ['collapse', 'separate'] ); $this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum( - array('top', 'bottom') + ['top', 'bottom'] ); $this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum( - array('auto', 'fixed') + ['auto', 'fixed'] ); $this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite( - array( + [ new HTMLPurifier_AttrDef_Enum( - array( + [ 'baseline', 'sub', 'super', @@ -347,11 +379,11 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition 'middle', 'bottom', 'text-bottom' - ) + ] ), new HTMLPurifier_AttrDef_CSS_Length(), new HTMLPurifier_AttrDef_CSS_Percentage() - ) + ] ); $this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2); @@ -359,7 +391,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition // These CSS properties don't work on many browsers, but we live // in THE FUTURE! $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum( - array('nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line') + ['nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line'] ); if ($config->get('CSS.Proprietary')) { @@ -406,21 +438,21 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition // more CSS3 $this->info['page-break-after'] = $this->info['page-break-before'] = new HTMLPurifier_AttrDef_Enum( - array( + [ 'auto', 'always', 'avoid', 'left', 'right' - ) + ] ); - $this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(array('auto', 'avoid')); + $this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(['auto', 'avoid']); $border_radius = new HTMLPurifier_AttrDef_CSS_Composite( - array( + [ new HTMLPurifier_AttrDef_CSS_Percentage(true), // disallow negative new HTMLPurifier_AttrDef_CSS_Length('0') // disallow negative - )); + ]); $this->info['border-top-left-radius'] = $this->info['border-top-right-radius'] = @@ -437,7 +469,7 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition protected function doSetupTricky($config) { $this->info['display'] = new HTMLPurifier_AttrDef_Enum( - array( + [ 'inline', 'block', 'list-item', @@ -456,12 +488,12 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition 'table-cell', 'table-caption', 'none' - ) + ] ); $this->info['visibility'] = new HTMLPurifier_AttrDef_Enum( - array('visible', 'hidden', 'collapse') + ['visible', 'hidden', 'collapse'] ); - $this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(array('visible', 'hidden', 'auto', 'scroll')); + $this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(['visible', 'hidden', 'auto', 'scroll']); $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); } @@ -471,23 +503,23 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition protected function doSetupTrusted($config) { $this->info['position'] = new HTMLPurifier_AttrDef_Enum( - array('static', 'relative', 'absolute', 'fixed') + ['static', 'relative', 'absolute', 'fixed'] ); $this->info['top'] = $this->info['left'] = $this->info['right'] = $this->info['bottom'] = new HTMLPurifier_AttrDef_CSS_Composite( - array( + [ new HTMLPurifier_AttrDef_CSS_Length(), new HTMLPurifier_AttrDef_CSS_Percentage(), - new HTMLPurifier_AttrDef_Enum(array('auto')), - ) + new HTMLPurifier_AttrDef_Enum(['auto']), + ] ); $this->info['z-index'] = new HTMLPurifier_AttrDef_CSS_Composite( - array( + [ new HTMLPurifier_AttrDef_Integer(), - new HTMLPurifier_AttrDef_Enum(array('auto')), - ) + new HTMLPurifier_AttrDef_Enum(['auto']), + ] ); } diff --git a/tools/htmlpurifier/HTMLPurifier/ChildDef/List.php b/tools/htmlpurifier/HTMLPurifier/ChildDef/List.php index 4fc70e0ef..3d584e727 100644 --- a/tools/htmlpurifier/HTMLPurifier/ChildDef/List.php +++ b/tools/htmlpurifier/HTMLPurifier/ChildDef/List.php @@ -22,6 +22,8 @@ class HTMLPurifier_ChildDef_List extends HTMLPurifier_ChildDef // XXX: This whole business with 'wrap' is all a bit unsatisfactory public $elements = array('li' => true, 'ul' => true, 'ol' => true); + public $whitespace; + /** * @param array $children * @param HTMLPurifier_Config $config diff --git a/tools/htmlpurifier/HTMLPurifier/ChildDef/Table.php b/tools/htmlpurifier/HTMLPurifier/ChildDef/Table.php index cb6b3e6cd..d92205b32 100644 --- a/tools/htmlpurifier/HTMLPurifier/ChildDef/Table.php +++ b/tools/htmlpurifier/HTMLPurifier/ChildDef/Table.php @@ -164,7 +164,7 @@ class HTMLPurifier_ChildDef_Table extends HTMLPurifier_ChildDef } } - if (empty($content)) { + if (empty($content) && $thead === false && $tfoot === false) { return false; } @@ -190,6 +190,9 @@ class HTMLPurifier_ChildDef_Table extends HTMLPurifier_ChildDef $current_tr_tbody = null; foreach($content as $node) { + if (!isset($node->name)) { + continue; + } switch ($node->name) { case 'tbody': $current_tr_tbody = null; diff --git a/tools/htmlpurifier/HTMLPurifier/ChildDef/index.php b/tools/htmlpurifier/HTMLPurifier/ChildDef/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/ChildDef/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/Config.php b/tools/htmlpurifier/HTMLPurifier/Config.php index 3133d8a4f..e6566e802 100644 --- a/tools/htmlpurifier/HTMLPurifier/Config.php +++ b/tools/htmlpurifier/HTMLPurifier/Config.php @@ -21,7 +21,7 @@ class HTMLPurifier_Config * HTML Purifier's version * @type string */ - public $version = '4.13.0'; + public $version = '4.18.0'; /** * Whether or not to automatically finalize @@ -803,7 +803,7 @@ class HTMLPurifier_Config if ($index !== false) { $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array(); } - $mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc(); + $mq = $mq_fix && version_compare(PHP_VERSION, '7.4.0', '<') && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc(); $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema); $ret = array(); diff --git a/tools/htmlpurifier/HTMLPurifier/ConfigSchema/Builder/index.php b/tools/htmlpurifier/HTMLPurifier/ConfigSchema/Builder/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/ConfigSchema/Builder/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/ConfigSchema/Interchange/index.php b/tools/htmlpurifier/HTMLPurifier/ConfigSchema/Interchange/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/ConfigSchema/Interchange/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/ConfigSchema/index.php b/tools/htmlpurifier/HTMLPurifier/ConfigSchema/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/ConfigSchema/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema.ser b/tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema.ser index a5426c736..3cd756bee 100644 --- a/tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema.ser +++ b/tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema.ser @@ -1 +1 @@ -O:25:"HTMLPurifier_ConfigSchema":3:{s:8:"defaults";a:127:{s:19:"Attr.AllowedClasses";N;s:24:"Attr.AllowedFrameTargets";a:0:{}s:15:"Attr.AllowedRel";a:0:{}s:15:"Attr.AllowedRev";a:0:{}s:18:"Attr.ClassUseCDATA";N;s:20:"Attr.DefaultImageAlt";N;s:24:"Attr.DefaultInvalidImage";s:0:"";s:27:"Attr.DefaultInvalidImageAlt";s:13:"Invalid image";s:19:"Attr.DefaultTextDir";s:3:"ltr";s:13:"Attr.EnableID";b:0;s:21:"Attr.ForbiddenClasses";a:0:{}s:13:"Attr.ID.HTML5";N;s:16:"Attr.IDBlacklist";a:0:{}s:22:"Attr.IDBlacklistRegexp";N;s:13:"Attr.IDPrefix";s:0:"";s:18:"Attr.IDPrefixLocal";s:0:"";s:24:"AutoFormat.AutoParagraph";b:0;s:17:"AutoFormat.Custom";a:0:{}s:25:"AutoFormat.DisplayLinkURI";b:0;s:18:"AutoFormat.Linkify";b:0;s:33:"AutoFormat.PurifierLinkify.DocURL";s:3:"#%s";s:26:"AutoFormat.PurifierLinkify";b:0;s:32:"AutoFormat.RemoveEmpty.Predicate";a:4:{s:8:"colgroup";a:0:{}s:2:"th";a:0:{}s:2:"td";a:0:{}s:6:"iframe";a:1:{i:0;s:3:"src";}}s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";a:2:{s:2:"td";b:1;s:2:"th";b:1;}s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";b:0;s:22:"AutoFormat.RemoveEmpty";b:0;s:39:"AutoFormat.RemoveSpansWithoutAttributes";b:0;s:19:"CSS.AllowDuplicates";b:0;s:18:"CSS.AllowImportant";b:0;s:15:"CSS.AllowTricky";b:0;s:16:"CSS.AllowedFonts";N;s:21:"CSS.AllowedProperties";N;s:17:"CSS.DefinitionRev";i:1;s:23:"CSS.ForbiddenProperties";a:0:{}s:16:"CSS.MaxImgLength";s:6:"1200px";s:15:"CSS.Proprietary";b:0;s:11:"CSS.Trusted";b:0;s:20:"Cache.DefinitionImpl";s:10:"Serializer";s:20:"Cache.SerializerPath";N;s:27:"Cache.SerializerPermissions";i:493;s:22:"Core.AggressivelyFixLt";b:1;s:29:"Core.AggressivelyRemoveScript";b:1;s:28:"Core.AllowHostnameUnderscore";b:0;s:23:"Core.AllowParseManyTags";b:0;s:18:"Core.CollectErrors";b:0;s:18:"Core.ColorKeywords";a:148:{s:9:"aliceblue";s:7:"#F0F8FF";s:12:"antiquewhite";s:7:"#FAEBD7";s:4:"aqua";s:7:"#00FFFF";s:10:"aquamarine";s:7:"#7FFFD4";s:5:"azure";s:7:"#F0FFFF";s:5:"beige";s:7:"#F5F5DC";s:6:"bisque";s:7:"#FFE4C4";s:5:"black";s:7:"#000000";s:14:"blanchedalmond";s:7:"#FFEBCD";s:4:"blue";s:7:"#0000FF";s:10:"blueviolet";s:7:"#8A2BE2";s:5:"brown";s:7:"#A52A2A";s:9:"burlywood";s:7:"#DEB887";s:9:"cadetblue";s:7:"#5F9EA0";s:10:"chartreuse";s:7:"#7FFF00";s:9:"chocolate";s:7:"#D2691E";s:5:"coral";s:7:"#FF7F50";s:14:"cornflowerblue";s:7:"#6495ED";s:8:"cornsilk";s:7:"#FFF8DC";s:7:"crimson";s:7:"#DC143C";s:4:"cyan";s:7:"#00FFFF";s:8:"darkblue";s:7:"#00008B";s:8:"darkcyan";s:7:"#008B8B";s:13:"darkgoldenrod";s:7:"#B8860B";s:8:"darkgray";s:7:"#A9A9A9";s:8:"darkgrey";s:7:"#A9A9A9";s:9:"darkgreen";s:7:"#006400";s:9:"darkkhaki";s:7:"#BDB76B";s:11:"darkmagenta";s:7:"#8B008B";s:14:"darkolivegreen";s:7:"#556B2F";s:10:"darkorange";s:7:"#FF8C00";s:10:"darkorchid";s:7:"#9932CC";s:7:"darkred";s:7:"#8B0000";s:10:"darksalmon";s:7:"#E9967A";s:12:"darkseagreen";s:7:"#8FBC8F";s:13:"darkslateblue";s:7:"#483D8B";s:13:"darkslategray";s:7:"#2F4F4F";s:13:"darkslategrey";s:7:"#2F4F4F";s:13:"darkturquoise";s:7:"#00CED1";s:10:"darkviolet";s:7:"#9400D3";s:8:"deeppink";s:7:"#FF1493";s:11:"deepskyblue";s:7:"#00BFFF";s:7:"dimgray";s:7:"#696969";s:7:"dimgrey";s:7:"#696969";s:10:"dodgerblue";s:7:"#1E90FF";s:9:"firebrick";s:7:"#B22222";s:11:"floralwhite";s:7:"#FFFAF0";s:11:"forestgreen";s:7:"#228B22";s:7:"fuchsia";s:7:"#FF00FF";s:9:"gainsboro";s:7:"#DCDCDC";s:10:"ghostwhite";s:7:"#F8F8FF";s:4:"gold";s:7:"#FFD700";s:9:"goldenrod";s:7:"#DAA520";s:4:"gray";s:7:"#808080";s:4:"grey";s:7:"#808080";s:5:"green";s:7:"#008000";s:11:"greenyellow";s:7:"#ADFF2F";s:8:"honeydew";s:7:"#F0FFF0";s:7:"hotpink";s:7:"#FF69B4";s:9:"indianred";s:7:"#CD5C5C";s:6:"indigo";s:7:"#4B0082";s:5:"ivory";s:7:"#FFFFF0";s:5:"khaki";s:7:"#F0E68C";s:8:"lavender";s:7:"#E6E6FA";s:13:"lavenderblush";s:7:"#FFF0F5";s:9:"lawngreen";s:7:"#7CFC00";s:12:"lemonchiffon";s:7:"#FFFACD";s:9:"lightblue";s:7:"#ADD8E6";s:10:"lightcoral";s:7:"#F08080";s:9:"lightcyan";s:7:"#E0FFFF";s:20:"lightgoldenrodyellow";s:7:"#FAFAD2";s:9:"lightgray";s:7:"#D3D3D3";s:9:"lightgrey";s:7:"#D3D3D3";s:10:"lightgreen";s:7:"#90EE90";s:9:"lightpink";s:7:"#FFB6C1";s:11:"lightsalmon";s:7:"#FFA07A";s:13:"lightseagreen";s:7:"#20B2AA";s:12:"lightskyblue";s:7:"#87CEFA";s:14:"lightslategray";s:7:"#778899";s:14:"lightslategrey";s:7:"#778899";s:14:"lightsteelblue";s:7:"#B0C4DE";s:11:"lightyellow";s:7:"#FFFFE0";s:4:"lime";s:7:"#00FF00";s:9:"limegreen";s:7:"#32CD32";s:5:"linen";s:7:"#FAF0E6";s:7:"magenta";s:7:"#FF00FF";s:6:"maroon";s:7:"#800000";s:16:"mediumaquamarine";s:7:"#66CDAA";s:10:"mediumblue";s:7:"#0000CD";s:12:"mediumorchid";s:7:"#BA55D3";s:12:"mediumpurple";s:7:"#9370DB";s:14:"mediumseagreen";s:7:"#3CB371";s:15:"mediumslateblue";s:7:"#7B68EE";s:17:"mediumspringgreen";s:7:"#00FA9A";s:15:"mediumturquoise";s:7:"#48D1CC";s:15:"mediumvioletred";s:7:"#C71585";s:12:"midnightblue";s:7:"#191970";s:9:"mintcream";s:7:"#F5FFFA";s:9:"mistyrose";s:7:"#FFE4E1";s:8:"moccasin";s:7:"#FFE4B5";s:11:"navajowhite";s:7:"#FFDEAD";s:4:"navy";s:7:"#000080";s:7:"oldlace";s:7:"#FDF5E6";s:5:"olive";s:7:"#808000";s:9:"olivedrab";s:7:"#6B8E23";s:6:"orange";s:7:"#FFA500";s:9:"orangered";s:7:"#FF4500";s:6:"orchid";s:7:"#DA70D6";s:13:"palegoldenrod";s:7:"#EEE8AA";s:9:"palegreen";s:7:"#98FB98";s:13:"paleturquoise";s:7:"#AFEEEE";s:13:"palevioletred";s:7:"#DB7093";s:10:"papayawhip";s:7:"#FFEFD5";s:9:"peachpuff";s:7:"#FFDAB9";s:4:"peru";s:7:"#CD853F";s:4:"pink";s:7:"#FFC0CB";s:4:"plum";s:7:"#DDA0DD";s:10:"powderblue";s:7:"#B0E0E6";s:6:"purple";s:7:"#800080";s:13:"rebeccapurple";s:7:"#663399";s:3:"red";s:7:"#FF0000";s:9:"rosybrown";s:7:"#BC8F8F";s:9:"royalblue";s:7:"#4169E1";s:11:"saddlebrown";s:7:"#8B4513";s:6:"salmon";s:7:"#FA8072";s:10:"sandybrown";s:7:"#F4A460";s:8:"seagreen";s:7:"#2E8B57";s:8:"seashell";s:7:"#FFF5EE";s:6:"sienna";s:7:"#A0522D";s:6:"silver";s:7:"#C0C0C0";s:7:"skyblue";s:7:"#87CEEB";s:9:"slateblue";s:7:"#6A5ACD";s:9:"slategray";s:7:"#708090";s:9:"slategrey";s:7:"#708090";s:4:"snow";s:7:"#FFFAFA";s:11:"springgreen";s:7:"#00FF7F";s:9:"steelblue";s:7:"#4682B4";s:3:"tan";s:7:"#D2B48C";s:4:"teal";s:7:"#008080";s:7:"thistle";s:7:"#D8BFD8";s:6:"tomato";s:7:"#FF6347";s:9:"turquoise";s:7:"#40E0D0";s:6:"violet";s:7:"#EE82EE";s:5:"wheat";s:7:"#F5DEB3";s:5:"white";s:7:"#FFFFFF";s:10:"whitesmoke";s:7:"#F5F5F5";s:6:"yellow";s:7:"#FFFF00";s:11:"yellowgreen";s:7:"#9ACD32";}s:30:"Core.ConvertDocumentToFragment";b:1;s:36:"Core.DirectLexLineNumberSyncInterval";i:0;s:20:"Core.DisableExcludes";b:0;s:15:"Core.EnableIDNA";b:0;s:13:"Core.Encoding";s:5:"utf-8";s:26:"Core.EscapeInvalidChildren";b:0;s:22:"Core.EscapeInvalidTags";b:0;s:29:"Core.EscapeNonASCIICharacters";b:0;s:19:"Core.HiddenElements";a:2:{s:6:"script";b:1;s:5:"style";b:1;}s:13:"Core.Language";s:2:"en";s:24:"Core.LegacyEntityDecoder";b:0;s:14:"Core.LexerImpl";N;s:24:"Core.MaintainLineNumbers";N;s:22:"Core.NormalizeNewlines";b:1;s:21:"Core.RemoveInvalidImg";b:1;s:33:"Core.RemoveProcessingInstructions";b:0;s:25:"Core.RemoveScriptContents";N;s:13:"Filter.Custom";a:0:{}s:34:"Filter.ExtractStyleBlocks.Escaping";b:1;s:31:"Filter.ExtractStyleBlocks.Scope";N;s:34:"Filter.ExtractStyleBlocks.TidyImpl";N;s:25:"Filter.ExtractStyleBlocks";b:0;s:14:"Filter.YouTube";b:0;s:12:"HTML.Allowed";N;s:22:"HTML.AllowedAttributes";N;s:20:"HTML.AllowedComments";a:0:{}s:26:"HTML.AllowedCommentsRegexp";N;s:20:"HTML.AllowedElements";N;s:19:"HTML.AllowedModules";N;s:23:"HTML.Attr.Name.UseCDATA";b:0;s:17:"HTML.BlockWrapper";s:1:"p";s:16:"HTML.CoreModules";a:7:{s:9:"Structure";b:1;s:4:"Text";b:1;s:9:"Hypertext";b:1;s:4:"List";b:1;s:22:"NonXMLCommonAttributes";b:1;s:19:"XMLCommonAttributes";b:1;s:16:"CommonAttributes";b:1;}s:18:"HTML.CustomDoctype";N;s:17:"HTML.DefinitionID";N;s:18:"HTML.DefinitionRev";i:1;s:12:"HTML.Doctype";N;s:25:"HTML.FlashAllowFullScreen";b:0;s:24:"HTML.ForbiddenAttributes";a:0:{}s:22:"HTML.ForbiddenElements";a:0:{}s:10:"HTML.Forms";b:0;s:17:"HTML.MaxImgLength";i:1200;s:13:"HTML.Nofollow";b:0;s:11:"HTML.Parent";s:3:"div";s:16:"HTML.Proprietary";b:0;s:14:"HTML.SafeEmbed";b:0;s:15:"HTML.SafeIframe";b:0;s:15:"HTML.SafeObject";b:0;s:18:"HTML.SafeScripting";a:0:{}s:11:"HTML.Strict";b:0;s:16:"HTML.TargetBlank";b:0;s:19:"HTML.TargetNoopener";b:1;s:21:"HTML.TargetNoreferrer";b:1;s:12:"HTML.TidyAdd";a:0:{}s:14:"HTML.TidyLevel";s:6:"medium";s:15:"HTML.TidyRemove";a:0:{}s:12:"HTML.Trusted";b:0;s:10:"HTML.XHTML";b:1;s:28:"Output.CommentScriptContents";b:1;s:19:"Output.FixInnerHTML";b:1;s:18:"Output.FlashCompat";b:0;s:14:"Output.Newline";N;s:15:"Output.SortAttr";b:0;s:17:"Output.TidyFormat";b:0;s:17:"Test.ForceNoIconv";b:0;s:18:"URI.AllowedSchemes";a:7:{s:4:"http";b:1;s:5:"https";b:1;s:6:"mailto";b:1;s:3:"ftp";b:1;s:4:"nntp";b:1;s:4:"news";b:1;s:3:"tel";b:1;}s:8:"URI.Base";N;s:17:"URI.DefaultScheme";s:4:"http";s:16:"URI.DefinitionID";N;s:17:"URI.DefinitionRev";i:1;s:11:"URI.Disable";b:0;s:19:"URI.DisableExternal";b:0;s:28:"URI.DisableExternalResources";b:0;s:20:"URI.DisableResources";b:0;s:8:"URI.Host";N;s:17:"URI.HostBlacklist";a:0:{}s:16:"URI.MakeAbsolute";b:0;s:9:"URI.Munge";N;s:18:"URI.MungeResources";b:0;s:18:"URI.MungeSecretKey";N;s:26:"URI.OverrideAllowedSchemes";b:1;s:20:"URI.SafeIframeRegexp";N;}s:12:"defaultPlist";O:25:"HTMLPurifier_PropertyList":3:{s:7:"*data";a:127:{s:19:"Attr.AllowedClasses";N;s:24:"Attr.AllowedFrameTargets";a:0:{}s:15:"Attr.AllowedRel";a:0:{}s:15:"Attr.AllowedRev";a:0:{}s:18:"Attr.ClassUseCDATA";N;s:20:"Attr.DefaultImageAlt";N;s:24:"Attr.DefaultInvalidImage";s:0:"";s:27:"Attr.DefaultInvalidImageAlt";s:13:"Invalid image";s:19:"Attr.DefaultTextDir";s:3:"ltr";s:13:"Attr.EnableID";b:0;s:21:"Attr.ForbiddenClasses";a:0:{}s:13:"Attr.ID.HTML5";N;s:16:"Attr.IDBlacklist";a:0:{}s:22:"Attr.IDBlacklistRegexp";N;s:13:"Attr.IDPrefix";s:0:"";s:18:"Attr.IDPrefixLocal";s:0:"";s:24:"AutoFormat.AutoParagraph";b:0;s:17:"AutoFormat.Custom";a:0:{}s:25:"AutoFormat.DisplayLinkURI";b:0;s:18:"AutoFormat.Linkify";b:0;s:33:"AutoFormat.PurifierLinkify.DocURL";s:3:"#%s";s:26:"AutoFormat.PurifierLinkify";b:0;s:32:"AutoFormat.RemoveEmpty.Predicate";a:4:{s:8:"colgroup";a:0:{}s:2:"th";a:0:{}s:2:"td";a:0:{}s:6:"iframe";a:1:{i:0;s:3:"src";}}s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";a:2:{s:2:"td";b:1;s:2:"th";b:1;}s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";b:0;s:22:"AutoFormat.RemoveEmpty";b:0;s:39:"AutoFormat.RemoveSpansWithoutAttributes";b:0;s:19:"CSS.AllowDuplicates";b:0;s:18:"CSS.AllowImportant";b:0;s:15:"CSS.AllowTricky";b:0;s:16:"CSS.AllowedFonts";N;s:21:"CSS.AllowedProperties";N;s:17:"CSS.DefinitionRev";i:1;s:23:"CSS.ForbiddenProperties";a:0:{}s:16:"CSS.MaxImgLength";s:6:"1200px";s:15:"CSS.Proprietary";b:0;s:11:"CSS.Trusted";b:0;s:20:"Cache.DefinitionImpl";s:10:"Serializer";s:20:"Cache.SerializerPath";N;s:27:"Cache.SerializerPermissions";i:493;s:22:"Core.AggressivelyFixLt";b:1;s:29:"Core.AggressivelyRemoveScript";b:1;s:28:"Core.AllowHostnameUnderscore";b:0;s:23:"Core.AllowParseManyTags";b:0;s:18:"Core.CollectErrors";b:0;s:18:"Core.ColorKeywords";a:148:{s:9:"aliceblue";s:7:"#F0F8FF";s:12:"antiquewhite";s:7:"#FAEBD7";s:4:"aqua";s:7:"#00FFFF";s:10:"aquamarine";s:7:"#7FFFD4";s:5:"azure";s:7:"#F0FFFF";s:5:"beige";s:7:"#F5F5DC";s:6:"bisque";s:7:"#FFE4C4";s:5:"black";s:7:"#000000";s:14:"blanchedalmond";s:7:"#FFEBCD";s:4:"blue";s:7:"#0000FF";s:10:"blueviolet";s:7:"#8A2BE2";s:5:"brown";s:7:"#A52A2A";s:9:"burlywood";s:7:"#DEB887";s:9:"cadetblue";s:7:"#5F9EA0";s:10:"chartreuse";s:7:"#7FFF00";s:9:"chocolate";s:7:"#D2691E";s:5:"coral";s:7:"#FF7F50";s:14:"cornflowerblue";s:7:"#6495ED";s:8:"cornsilk";s:7:"#FFF8DC";s:7:"crimson";s:7:"#DC143C";s:4:"cyan";s:7:"#00FFFF";s:8:"darkblue";s:7:"#00008B";s:8:"darkcyan";s:7:"#008B8B";s:13:"darkgoldenrod";s:7:"#B8860B";s:8:"darkgray";s:7:"#A9A9A9";s:8:"darkgrey";s:7:"#A9A9A9";s:9:"darkgreen";s:7:"#006400";s:9:"darkkhaki";s:7:"#BDB76B";s:11:"darkmagenta";s:7:"#8B008B";s:14:"darkolivegreen";s:7:"#556B2F";s:10:"darkorange";s:7:"#FF8C00";s:10:"darkorchid";s:7:"#9932CC";s:7:"darkred";s:7:"#8B0000";s:10:"darksalmon";s:7:"#E9967A";s:12:"darkseagreen";s:7:"#8FBC8F";s:13:"darkslateblue";s:7:"#483D8B";s:13:"darkslategray";s:7:"#2F4F4F";s:13:"darkslategrey";s:7:"#2F4F4F";s:13:"darkturquoise";s:7:"#00CED1";s:10:"darkviolet";s:7:"#9400D3";s:8:"deeppink";s:7:"#FF1493";s:11:"deepskyblue";s:7:"#00BFFF";s:7:"dimgray";s:7:"#696969";s:7:"dimgrey";s:7:"#696969";s:10:"dodgerblue";s:7:"#1E90FF";s:9:"firebrick";s:7:"#B22222";s:11:"floralwhite";s:7:"#FFFAF0";s:11:"forestgreen";s:7:"#228B22";s:7:"fuchsia";s:7:"#FF00FF";s:9:"gainsboro";s:7:"#DCDCDC";s:10:"ghostwhite";s:7:"#F8F8FF";s:4:"gold";s:7:"#FFD700";s:9:"goldenrod";s:7:"#DAA520";s:4:"gray";s:7:"#808080";s:4:"grey";s:7:"#808080";s:5:"green";s:7:"#008000";s:11:"greenyellow";s:7:"#ADFF2F";s:8:"honeydew";s:7:"#F0FFF0";s:7:"hotpink";s:7:"#FF69B4";s:9:"indianred";s:7:"#CD5C5C";s:6:"indigo";s:7:"#4B0082";s:5:"ivory";s:7:"#FFFFF0";s:5:"khaki";s:7:"#F0E68C";s:8:"lavender";s:7:"#E6E6FA";s:13:"lavenderblush";s:7:"#FFF0F5";s:9:"lawngreen";s:7:"#7CFC00";s:12:"lemonchiffon";s:7:"#FFFACD";s:9:"lightblue";s:7:"#ADD8E6";s:10:"lightcoral";s:7:"#F08080";s:9:"lightcyan";s:7:"#E0FFFF";s:20:"lightgoldenrodyellow";s:7:"#FAFAD2";s:9:"lightgray";s:7:"#D3D3D3";s:9:"lightgrey";s:7:"#D3D3D3";s:10:"lightgreen";s:7:"#90EE90";s:9:"lightpink";s:7:"#FFB6C1";s:11:"lightsalmon";s:7:"#FFA07A";s:13:"lightseagreen";s:7:"#20B2AA";s:12:"lightskyblue";s:7:"#87CEFA";s:14:"lightslategray";s:7:"#778899";s:14:"lightslategrey";s:7:"#778899";s:14:"lightsteelblue";s:7:"#B0C4DE";s:11:"lightyellow";s:7:"#FFFFE0";s:4:"lime";s:7:"#00FF00";s:9:"limegreen";s:7:"#32CD32";s:5:"linen";s:7:"#FAF0E6";s:7:"magenta";s:7:"#FF00FF";s:6:"maroon";s:7:"#800000";s:16:"mediumaquamarine";s:7:"#66CDAA";s:10:"mediumblue";s:7:"#0000CD";s:12:"mediumorchid";s:7:"#BA55D3";s:12:"mediumpurple";s:7:"#9370DB";s:14:"mediumseagreen";s:7:"#3CB371";s:15:"mediumslateblue";s:7:"#7B68EE";s:17:"mediumspringgreen";s:7:"#00FA9A";s:15:"mediumturquoise";s:7:"#48D1CC";s:15:"mediumvioletred";s:7:"#C71585";s:12:"midnightblue";s:7:"#191970";s:9:"mintcream";s:7:"#F5FFFA";s:9:"mistyrose";s:7:"#FFE4E1";s:8:"moccasin";s:7:"#FFE4B5";s:11:"navajowhite";s:7:"#FFDEAD";s:4:"navy";s:7:"#000080";s:7:"oldlace";s:7:"#FDF5E6";s:5:"olive";s:7:"#808000";s:9:"olivedrab";s:7:"#6B8E23";s:6:"orange";s:7:"#FFA500";s:9:"orangered";s:7:"#FF4500";s:6:"orchid";s:7:"#DA70D6";s:13:"palegoldenrod";s:7:"#EEE8AA";s:9:"palegreen";s:7:"#98FB98";s:13:"paleturquoise";s:7:"#AFEEEE";s:13:"palevioletred";s:7:"#DB7093";s:10:"papayawhip";s:7:"#FFEFD5";s:9:"peachpuff";s:7:"#FFDAB9";s:4:"peru";s:7:"#CD853F";s:4:"pink";s:7:"#FFC0CB";s:4:"plum";s:7:"#DDA0DD";s:10:"powderblue";s:7:"#B0E0E6";s:6:"purple";s:7:"#800080";s:13:"rebeccapurple";s:7:"#663399";s:3:"red";s:7:"#FF0000";s:9:"rosybrown";s:7:"#BC8F8F";s:9:"royalblue";s:7:"#4169E1";s:11:"saddlebrown";s:7:"#8B4513";s:6:"salmon";s:7:"#FA8072";s:10:"sandybrown";s:7:"#F4A460";s:8:"seagreen";s:7:"#2E8B57";s:8:"seashell";s:7:"#FFF5EE";s:6:"sienna";s:7:"#A0522D";s:6:"silver";s:7:"#C0C0C0";s:7:"skyblue";s:7:"#87CEEB";s:9:"slateblue";s:7:"#6A5ACD";s:9:"slategray";s:7:"#708090";s:9:"slategrey";s:7:"#708090";s:4:"snow";s:7:"#FFFAFA";s:11:"springgreen";s:7:"#00FF7F";s:9:"steelblue";s:7:"#4682B4";s:3:"tan";s:7:"#D2B48C";s:4:"teal";s:7:"#008080";s:7:"thistle";s:7:"#D8BFD8";s:6:"tomato";s:7:"#FF6347";s:9:"turquoise";s:7:"#40E0D0";s:6:"violet";s:7:"#EE82EE";s:5:"wheat";s:7:"#F5DEB3";s:5:"white";s:7:"#FFFFFF";s:10:"whitesmoke";s:7:"#F5F5F5";s:6:"yellow";s:7:"#FFFF00";s:11:"yellowgreen";s:7:"#9ACD32";}s:30:"Core.ConvertDocumentToFragment";b:1;s:36:"Core.DirectLexLineNumberSyncInterval";i:0;s:20:"Core.DisableExcludes";b:0;s:15:"Core.EnableIDNA";b:0;s:13:"Core.Encoding";s:5:"utf-8";s:26:"Core.EscapeInvalidChildren";b:0;s:22:"Core.EscapeInvalidTags";b:0;s:29:"Core.EscapeNonASCIICharacters";b:0;s:19:"Core.HiddenElements";a:2:{s:6:"script";b:1;s:5:"style";b:1;}s:13:"Core.Language";s:2:"en";s:24:"Core.LegacyEntityDecoder";b:0;s:14:"Core.LexerImpl";N;s:24:"Core.MaintainLineNumbers";N;s:22:"Core.NormalizeNewlines";b:1;s:21:"Core.RemoveInvalidImg";b:1;s:33:"Core.RemoveProcessingInstructions";b:0;s:25:"Core.RemoveScriptContents";N;s:13:"Filter.Custom";a:0:{}s:34:"Filter.ExtractStyleBlocks.Escaping";b:1;s:31:"Filter.ExtractStyleBlocks.Scope";N;s:34:"Filter.ExtractStyleBlocks.TidyImpl";N;s:25:"Filter.ExtractStyleBlocks";b:0;s:14:"Filter.YouTube";b:0;s:12:"HTML.Allowed";N;s:22:"HTML.AllowedAttributes";N;s:20:"HTML.AllowedComments";a:0:{}s:26:"HTML.AllowedCommentsRegexp";N;s:20:"HTML.AllowedElements";N;s:19:"HTML.AllowedModules";N;s:23:"HTML.Attr.Name.UseCDATA";b:0;s:17:"HTML.BlockWrapper";s:1:"p";s:16:"HTML.CoreModules";a:7:{s:9:"Structure";b:1;s:4:"Text";b:1;s:9:"Hypertext";b:1;s:4:"List";b:1;s:22:"NonXMLCommonAttributes";b:1;s:19:"XMLCommonAttributes";b:1;s:16:"CommonAttributes";b:1;}s:18:"HTML.CustomDoctype";N;s:17:"HTML.DefinitionID";N;s:18:"HTML.DefinitionRev";i:1;s:12:"HTML.Doctype";N;s:25:"HTML.FlashAllowFullScreen";b:0;s:24:"HTML.ForbiddenAttributes";a:0:{}s:22:"HTML.ForbiddenElements";a:0:{}s:10:"HTML.Forms";b:0;s:17:"HTML.MaxImgLength";i:1200;s:13:"HTML.Nofollow";b:0;s:11:"HTML.Parent";s:3:"div";s:16:"HTML.Proprietary";b:0;s:14:"HTML.SafeEmbed";b:0;s:15:"HTML.SafeIframe";b:0;s:15:"HTML.SafeObject";b:0;s:18:"HTML.SafeScripting";a:0:{}s:11:"HTML.Strict";b:0;s:16:"HTML.TargetBlank";b:0;s:19:"HTML.TargetNoopener";b:1;s:21:"HTML.TargetNoreferrer";b:1;s:12:"HTML.TidyAdd";a:0:{}s:14:"HTML.TidyLevel";s:6:"medium";s:15:"HTML.TidyRemove";a:0:{}s:12:"HTML.Trusted";b:0;s:10:"HTML.XHTML";b:1;s:28:"Output.CommentScriptContents";b:1;s:19:"Output.FixInnerHTML";b:1;s:18:"Output.FlashCompat";b:0;s:14:"Output.Newline";N;s:15:"Output.SortAttr";b:0;s:17:"Output.TidyFormat";b:0;s:17:"Test.ForceNoIconv";b:0;s:18:"URI.AllowedSchemes";a:7:{s:4:"http";b:1;s:5:"https";b:1;s:6:"mailto";b:1;s:3:"ftp";b:1;s:4:"nntp";b:1;s:4:"news";b:1;s:3:"tel";b:1;}s:8:"URI.Base";N;s:17:"URI.DefaultScheme";s:4:"http";s:16:"URI.DefinitionID";N;s:17:"URI.DefinitionRev";i:1;s:11:"URI.Disable";b:0;s:19:"URI.DisableExternal";b:0;s:28:"URI.DisableExternalResources";b:0;s:20:"URI.DisableResources";b:0;s:8:"URI.Host";N;s:17:"URI.HostBlacklist";a:0:{}s:16:"URI.MakeAbsolute";b:0;s:9:"URI.Munge";N;s:18:"URI.MungeResources";b:0;s:18:"URI.MungeSecretKey";N;s:26:"URI.OverrideAllowedSchemes";b:1;s:20:"URI.SafeIframeRegexp";N;}s:9:"*parent";N;s:8:"*cache";N;}s:4:"info";a:140:{s:19:"Attr.AllowedClasses";i:-8;s:24:"Attr.AllowedFrameTargets";i:8;s:15:"Attr.AllowedRel";i:8;s:15:"Attr.AllowedRev";i:8;s:18:"Attr.ClassUseCDATA";i:-7;s:20:"Attr.DefaultImageAlt";i:-1;s:24:"Attr.DefaultInvalidImage";i:1;s:27:"Attr.DefaultInvalidImageAlt";i:1;s:19:"Attr.DefaultTextDir";O:8:"stdClass":2:{s:4:"type";i:1;s:7:"allowed";a:2:{s:3:"ltr";b:1;s:3:"rtl";b:1;}}s:13:"Attr.EnableID";i:7;s:17:"HTML.EnableAttrID";O:8:"stdClass":2:{s:3:"key";s:13:"Attr.EnableID";s:7:"isAlias";b:1;}s:21:"Attr.ForbiddenClasses";i:8;s:13:"Attr.ID.HTML5";i:-7;s:16:"Attr.IDBlacklist";i:9;s:22:"Attr.IDBlacklistRegexp";i:-1;s:13:"Attr.IDPrefix";i:1;s:18:"Attr.IDPrefixLocal";i:1;s:24:"AutoFormat.AutoParagraph";i:7;s:17:"AutoFormat.Custom";i:9;s:25:"AutoFormat.DisplayLinkURI";i:7;s:18:"AutoFormat.Linkify";i:7;s:33:"AutoFormat.PurifierLinkify.DocURL";i:1;s:37:"AutoFormatParam.PurifierLinkifyDocURL";O:8:"stdClass":2:{s:3:"key";s:33:"AutoFormat.PurifierLinkify.DocURL";s:7:"isAlias";b:1;}s:26:"AutoFormat.PurifierLinkify";i:7;s:32:"AutoFormat.RemoveEmpty.Predicate";i:10;s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";i:8;s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";i:7;s:22:"AutoFormat.RemoveEmpty";i:7;s:39:"AutoFormat.RemoveSpansWithoutAttributes";i:7;s:19:"CSS.AllowDuplicates";i:7;s:18:"CSS.AllowImportant";i:7;s:15:"CSS.AllowTricky";i:7;s:16:"CSS.AllowedFonts";i:-8;s:21:"CSS.AllowedProperties";i:-8;s:17:"CSS.DefinitionRev";i:5;s:23:"CSS.ForbiddenProperties";i:8;s:16:"CSS.MaxImgLength";i:-1;s:15:"CSS.Proprietary";i:7;s:11:"CSS.Trusted";i:7;s:20:"Cache.DefinitionImpl";i:-1;s:20:"Core.DefinitionCache";O:8:"stdClass":2:{s:3:"key";s:20:"Cache.DefinitionImpl";s:7:"isAlias";b:1;}s:20:"Cache.SerializerPath";i:-1;s:27:"Cache.SerializerPermissions";i:-5;s:22:"Core.AggressivelyFixLt";i:7;s:29:"Core.AggressivelyRemoveScript";i:7;s:28:"Core.AllowHostnameUnderscore";i:7;s:23:"Core.AllowParseManyTags";i:7;s:18:"Core.CollectErrors";i:7;s:18:"Core.ColorKeywords";i:10;s:30:"Core.ConvertDocumentToFragment";i:7;s:24:"Core.AcceptFullDocuments";O:8:"stdClass":2:{s:3:"key";s:30:"Core.ConvertDocumentToFragment";s:7:"isAlias";b:1;}s:36:"Core.DirectLexLineNumberSyncInterval";i:5;s:20:"Core.DisableExcludes";i:7;s:15:"Core.EnableIDNA";i:7;s:13:"Core.Encoding";i:2;s:26:"Core.EscapeInvalidChildren";i:7;s:22:"Core.EscapeInvalidTags";i:7;s:29:"Core.EscapeNonASCIICharacters";i:7;s:19:"Core.HiddenElements";i:8;s:13:"Core.Language";i:1;s:24:"Core.LegacyEntityDecoder";i:7;s:14:"Core.LexerImpl";i:-11;s:24:"Core.MaintainLineNumbers";i:-7;s:22:"Core.NormalizeNewlines";i:7;s:21:"Core.RemoveInvalidImg";i:7;s:33:"Core.RemoveProcessingInstructions";i:7;s:25:"Core.RemoveScriptContents";i:-7;s:13:"Filter.Custom";i:9;s:34:"Filter.ExtractStyleBlocks.Escaping";i:7;s:33:"Filter.ExtractStyleBlocksEscaping";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.Escaping";s:7:"isAlias";b:1;}s:38:"FilterParam.ExtractStyleBlocksEscaping";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.Escaping";s:7:"isAlias";b:1;}s:31:"Filter.ExtractStyleBlocks.Scope";i:-1;s:30:"Filter.ExtractStyleBlocksScope";O:8:"stdClass":2:{s:3:"key";s:31:"Filter.ExtractStyleBlocks.Scope";s:7:"isAlias";b:1;}s:35:"FilterParam.ExtractStyleBlocksScope";O:8:"stdClass":2:{s:3:"key";s:31:"Filter.ExtractStyleBlocks.Scope";s:7:"isAlias";b:1;}s:34:"Filter.ExtractStyleBlocks.TidyImpl";i:-11;s:38:"FilterParam.ExtractStyleBlocksTidyImpl";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.TidyImpl";s:7:"isAlias";b:1;}s:25:"Filter.ExtractStyleBlocks";i:7;s:14:"Filter.YouTube";i:7;s:12:"HTML.Allowed";i:-4;s:22:"HTML.AllowedAttributes";i:-8;s:20:"HTML.AllowedComments";i:8;s:26:"HTML.AllowedCommentsRegexp";i:-1;s:20:"HTML.AllowedElements";i:-8;s:19:"HTML.AllowedModules";i:-8;s:23:"HTML.Attr.Name.UseCDATA";i:7;s:17:"HTML.BlockWrapper";i:1;s:16:"HTML.CoreModules";i:8;s:18:"HTML.CustomDoctype";i:-1;s:17:"HTML.DefinitionID";i:-1;s:18:"HTML.DefinitionRev";i:5;s:12:"HTML.Doctype";O:8:"stdClass":3:{s:4:"type";i:1;s:10:"allow_null";b:1;s:7:"allowed";a:5:{s:22:"HTML 4.01 Transitional";b:1;s:16:"HTML 4.01 Strict";b:1;s:22:"XHTML 1.0 Transitional";b:1;s:16:"XHTML 1.0 Strict";b:1;s:9:"XHTML 1.1";b:1;}}s:25:"HTML.FlashAllowFullScreen";i:7;s:24:"HTML.ForbiddenAttributes";i:8;s:22:"HTML.ForbiddenElements";i:8;s:10:"HTML.Forms";i:7;s:17:"HTML.MaxImgLength";i:-5;s:13:"HTML.Nofollow";i:7;s:11:"HTML.Parent";i:1;s:16:"HTML.Proprietary";i:7;s:14:"HTML.SafeEmbed";i:7;s:15:"HTML.SafeIframe";i:7;s:15:"HTML.SafeObject";i:7;s:18:"HTML.SafeScripting";i:8;s:11:"HTML.Strict";i:7;s:16:"HTML.TargetBlank";i:7;s:19:"HTML.TargetNoopener";i:7;s:21:"HTML.TargetNoreferrer";i:7;s:12:"HTML.TidyAdd";i:8;s:14:"HTML.TidyLevel";O:8:"stdClass":2:{s:4:"type";i:1;s:7:"allowed";a:4:{s:4:"none";b:1;s:5:"light";b:1;s:6:"medium";b:1;s:5:"heavy";b:1;}}s:15:"HTML.TidyRemove";i:8;s:12:"HTML.Trusted";i:7;s:10:"HTML.XHTML";i:7;s:10:"Core.XHTML";O:8:"stdClass":2:{s:3:"key";s:10:"HTML.XHTML";s:7:"isAlias";b:1;}s:28:"Output.CommentScriptContents";i:7;s:26:"Core.CommentScriptContents";O:8:"stdClass":2:{s:3:"key";s:28:"Output.CommentScriptContents";s:7:"isAlias";b:1;}s:19:"Output.FixInnerHTML";i:7;s:18:"Output.FlashCompat";i:7;s:14:"Output.Newline";i:-1;s:15:"Output.SortAttr";i:7;s:17:"Output.TidyFormat";i:7;s:15:"Core.TidyFormat";O:8:"stdClass":2:{s:3:"key";s:17:"Output.TidyFormat";s:7:"isAlias";b:1;}s:17:"Test.ForceNoIconv";i:7;s:18:"URI.AllowedSchemes";i:8;s:8:"URI.Base";i:-1;s:17:"URI.DefaultScheme";i:-1;s:16:"URI.DefinitionID";i:-1;s:17:"URI.DefinitionRev";i:5;s:11:"URI.Disable";i:7;s:15:"Attr.DisableURI";O:8:"stdClass":2:{s:3:"key";s:11:"URI.Disable";s:7:"isAlias";b:1;}s:19:"URI.DisableExternal";i:7;s:28:"URI.DisableExternalResources";i:7;s:20:"URI.DisableResources";i:7;s:8:"URI.Host";i:-1;s:17:"URI.HostBlacklist";i:9;s:16:"URI.MakeAbsolute";i:7;s:9:"URI.Munge";i:-1;s:18:"URI.MungeResources";i:7;s:18:"URI.MungeSecretKey";i:-1;s:26:"URI.OverrideAllowedSchemes";i:7;s:20:"URI.SafeIframeRegexp";i:-1;}} \ No newline at end of file +O:25:"HTMLPurifier_ConfigSchema":3:{s:8:"defaults";a:128:{s:19:"Attr.AllowedClasses";N;s:24:"Attr.AllowedFrameTargets";a:0:{}s:15:"Attr.AllowedRel";a:0:{}s:15:"Attr.AllowedRev";a:0:{}s:18:"Attr.ClassUseCDATA";N;s:20:"Attr.DefaultImageAlt";N;s:24:"Attr.DefaultInvalidImage";s:0:"";s:27:"Attr.DefaultInvalidImageAlt";s:13:"Invalid image";s:19:"Attr.DefaultTextDir";s:3:"ltr";s:13:"Attr.EnableID";b:0;s:21:"Attr.ForbiddenClasses";a:0:{}s:13:"Attr.ID.HTML5";N;s:16:"Attr.IDBlacklist";a:0:{}s:22:"Attr.IDBlacklistRegexp";N;s:13:"Attr.IDPrefix";s:0:"";s:18:"Attr.IDPrefixLocal";s:0:"";s:24:"AutoFormat.AutoParagraph";b:0;s:17:"AutoFormat.Custom";a:0:{}s:25:"AutoFormat.DisplayLinkURI";b:0;s:18:"AutoFormat.Linkify";b:0;s:33:"AutoFormat.PurifierLinkify.DocURL";s:3:"#%s";s:26:"AutoFormat.PurifierLinkify";b:0;s:32:"AutoFormat.RemoveEmpty.Predicate";a:4:{s:8:"colgroup";a:0:{}s:2:"th";a:0:{}s:2:"td";a:0:{}s:6:"iframe";a:1:{i:0;s:3:"src";}}s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";a:2:{s:2:"td";b:1;s:2:"th";b:1;}s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";b:0;s:22:"AutoFormat.RemoveEmpty";b:0;s:39:"AutoFormat.RemoveSpansWithoutAttributes";b:0;s:19:"CSS.AllowDuplicates";b:0;s:18:"CSS.AllowImportant";b:0;s:15:"CSS.AllowTricky";b:0;s:16:"CSS.AllowedFonts";N;s:21:"CSS.AllowedProperties";N;s:17:"CSS.DefinitionRev";i:1;s:23:"CSS.ForbiddenProperties";a:0:{}s:16:"CSS.MaxImgLength";s:6:"1200px";s:15:"CSS.Proprietary";b:0;s:11:"CSS.Trusted";b:0;s:20:"Cache.DefinitionImpl";s:10:"Serializer";s:20:"Cache.SerializerPath";N;s:27:"Cache.SerializerPermissions";i:493;s:22:"Core.AggressivelyFixLt";b:1;s:29:"Core.AggressivelyRemoveScript";b:1;s:28:"Core.AllowHostnameUnderscore";b:0;s:23:"Core.AllowParseManyTags";b:0;s:18:"Core.CollectErrors";b:0;s:18:"Core.ColorKeywords";a:148:{s:9:"aliceblue";s:7:"#F0F8FF";s:12:"antiquewhite";s:7:"#FAEBD7";s:4:"aqua";s:7:"#00FFFF";s:10:"aquamarine";s:7:"#7FFFD4";s:5:"azure";s:7:"#F0FFFF";s:5:"beige";s:7:"#F5F5DC";s:6:"bisque";s:7:"#FFE4C4";s:5:"black";s:7:"#000000";s:14:"blanchedalmond";s:7:"#FFEBCD";s:4:"blue";s:7:"#0000FF";s:10:"blueviolet";s:7:"#8A2BE2";s:5:"brown";s:7:"#A52A2A";s:9:"burlywood";s:7:"#DEB887";s:9:"cadetblue";s:7:"#5F9EA0";s:10:"chartreuse";s:7:"#7FFF00";s:9:"chocolate";s:7:"#D2691E";s:5:"coral";s:7:"#FF7F50";s:14:"cornflowerblue";s:7:"#6495ED";s:8:"cornsilk";s:7:"#FFF8DC";s:7:"crimson";s:7:"#DC143C";s:4:"cyan";s:7:"#00FFFF";s:8:"darkblue";s:7:"#00008B";s:8:"darkcyan";s:7:"#008B8B";s:13:"darkgoldenrod";s:7:"#B8860B";s:8:"darkgray";s:7:"#A9A9A9";s:8:"darkgrey";s:7:"#A9A9A9";s:9:"darkgreen";s:7:"#006400";s:9:"darkkhaki";s:7:"#BDB76B";s:11:"darkmagenta";s:7:"#8B008B";s:14:"darkolivegreen";s:7:"#556B2F";s:10:"darkorange";s:7:"#FF8C00";s:10:"darkorchid";s:7:"#9932CC";s:7:"darkred";s:7:"#8B0000";s:10:"darksalmon";s:7:"#E9967A";s:12:"darkseagreen";s:7:"#8FBC8F";s:13:"darkslateblue";s:7:"#483D8B";s:13:"darkslategray";s:7:"#2F4F4F";s:13:"darkslategrey";s:7:"#2F4F4F";s:13:"darkturquoise";s:7:"#00CED1";s:10:"darkviolet";s:7:"#9400D3";s:8:"deeppink";s:7:"#FF1493";s:11:"deepskyblue";s:7:"#00BFFF";s:7:"dimgray";s:7:"#696969";s:7:"dimgrey";s:7:"#696969";s:10:"dodgerblue";s:7:"#1E90FF";s:9:"firebrick";s:7:"#B22222";s:11:"floralwhite";s:7:"#FFFAF0";s:11:"forestgreen";s:7:"#228B22";s:7:"fuchsia";s:7:"#FF00FF";s:9:"gainsboro";s:7:"#DCDCDC";s:10:"ghostwhite";s:7:"#F8F8FF";s:4:"gold";s:7:"#FFD700";s:9:"goldenrod";s:7:"#DAA520";s:4:"gray";s:7:"#808080";s:4:"grey";s:7:"#808080";s:5:"green";s:7:"#008000";s:11:"greenyellow";s:7:"#ADFF2F";s:8:"honeydew";s:7:"#F0FFF0";s:7:"hotpink";s:7:"#FF69B4";s:9:"indianred";s:7:"#CD5C5C";s:6:"indigo";s:7:"#4B0082";s:5:"ivory";s:7:"#FFFFF0";s:5:"khaki";s:7:"#F0E68C";s:8:"lavender";s:7:"#E6E6FA";s:13:"lavenderblush";s:7:"#FFF0F5";s:9:"lawngreen";s:7:"#7CFC00";s:12:"lemonchiffon";s:7:"#FFFACD";s:9:"lightblue";s:7:"#ADD8E6";s:10:"lightcoral";s:7:"#F08080";s:9:"lightcyan";s:7:"#E0FFFF";s:20:"lightgoldenrodyellow";s:7:"#FAFAD2";s:9:"lightgray";s:7:"#D3D3D3";s:9:"lightgrey";s:7:"#D3D3D3";s:10:"lightgreen";s:7:"#90EE90";s:9:"lightpink";s:7:"#FFB6C1";s:11:"lightsalmon";s:7:"#FFA07A";s:13:"lightseagreen";s:7:"#20B2AA";s:12:"lightskyblue";s:7:"#87CEFA";s:14:"lightslategray";s:7:"#778899";s:14:"lightslategrey";s:7:"#778899";s:14:"lightsteelblue";s:7:"#B0C4DE";s:11:"lightyellow";s:7:"#FFFFE0";s:4:"lime";s:7:"#00FF00";s:9:"limegreen";s:7:"#32CD32";s:5:"linen";s:7:"#FAF0E6";s:7:"magenta";s:7:"#FF00FF";s:6:"maroon";s:7:"#800000";s:16:"mediumaquamarine";s:7:"#66CDAA";s:10:"mediumblue";s:7:"#0000CD";s:12:"mediumorchid";s:7:"#BA55D3";s:12:"mediumpurple";s:7:"#9370DB";s:14:"mediumseagreen";s:7:"#3CB371";s:15:"mediumslateblue";s:7:"#7B68EE";s:17:"mediumspringgreen";s:7:"#00FA9A";s:15:"mediumturquoise";s:7:"#48D1CC";s:15:"mediumvioletred";s:7:"#C71585";s:12:"midnightblue";s:7:"#191970";s:9:"mintcream";s:7:"#F5FFFA";s:9:"mistyrose";s:7:"#FFE4E1";s:8:"moccasin";s:7:"#FFE4B5";s:11:"navajowhite";s:7:"#FFDEAD";s:4:"navy";s:7:"#000080";s:7:"oldlace";s:7:"#FDF5E6";s:5:"olive";s:7:"#808000";s:9:"olivedrab";s:7:"#6B8E23";s:6:"orange";s:7:"#FFA500";s:9:"orangered";s:7:"#FF4500";s:6:"orchid";s:7:"#DA70D6";s:13:"palegoldenrod";s:7:"#EEE8AA";s:9:"palegreen";s:7:"#98FB98";s:13:"paleturquoise";s:7:"#AFEEEE";s:13:"palevioletred";s:7:"#DB7093";s:10:"papayawhip";s:7:"#FFEFD5";s:9:"peachpuff";s:7:"#FFDAB9";s:4:"peru";s:7:"#CD853F";s:4:"pink";s:7:"#FFC0CB";s:4:"plum";s:7:"#DDA0DD";s:10:"powderblue";s:7:"#B0E0E6";s:6:"purple";s:7:"#800080";s:13:"rebeccapurple";s:7:"#663399";s:3:"red";s:7:"#FF0000";s:9:"rosybrown";s:7:"#BC8F8F";s:9:"royalblue";s:7:"#4169E1";s:11:"saddlebrown";s:7:"#8B4513";s:6:"salmon";s:7:"#FA8072";s:10:"sandybrown";s:7:"#F4A460";s:8:"seagreen";s:7:"#2E8B57";s:8:"seashell";s:7:"#FFF5EE";s:6:"sienna";s:7:"#A0522D";s:6:"silver";s:7:"#C0C0C0";s:7:"skyblue";s:7:"#87CEEB";s:9:"slateblue";s:7:"#6A5ACD";s:9:"slategray";s:7:"#708090";s:9:"slategrey";s:7:"#708090";s:4:"snow";s:7:"#FFFAFA";s:11:"springgreen";s:7:"#00FF7F";s:9:"steelblue";s:7:"#4682B4";s:3:"tan";s:7:"#D2B48C";s:4:"teal";s:7:"#008080";s:7:"thistle";s:7:"#D8BFD8";s:6:"tomato";s:7:"#FF6347";s:9:"turquoise";s:7:"#40E0D0";s:6:"violet";s:7:"#EE82EE";s:5:"wheat";s:7:"#F5DEB3";s:5:"white";s:7:"#FFFFFF";s:10:"whitesmoke";s:7:"#F5F5F5";s:6:"yellow";s:7:"#FFFF00";s:11:"yellowgreen";s:7:"#9ACD32";}s:30:"Core.ConvertDocumentToFragment";b:1;s:36:"Core.DirectLexLineNumberSyncInterval";i:0;s:20:"Core.DisableExcludes";b:0;s:15:"Core.EnableIDNA";b:0;s:13:"Core.Encoding";s:5:"utf-8";s:26:"Core.EscapeInvalidChildren";b:0;s:22:"Core.EscapeInvalidTags";b:0;s:29:"Core.EscapeNonASCIICharacters";b:0;s:19:"Core.HiddenElements";a:2:{s:6:"script";b:1;s:5:"style";b:1;}s:13:"Core.Language";s:2:"en";s:24:"Core.LegacyEntityDecoder";b:0;s:14:"Core.LexerImpl";N;s:24:"Core.MaintainLineNumbers";N;s:22:"Core.NormalizeNewlines";b:1;s:17:"Core.RemoveBlanks";b:0;s:21:"Core.RemoveInvalidImg";b:1;s:33:"Core.RemoveProcessingInstructions";b:0;s:25:"Core.RemoveScriptContents";N;s:13:"Filter.Custom";a:0:{}s:34:"Filter.ExtractStyleBlocks.Escaping";b:1;s:31:"Filter.ExtractStyleBlocks.Scope";N;s:34:"Filter.ExtractStyleBlocks.TidyImpl";N;s:25:"Filter.ExtractStyleBlocks";b:0;s:14:"Filter.YouTube";b:0;s:12:"HTML.Allowed";N;s:22:"HTML.AllowedAttributes";N;s:20:"HTML.AllowedComments";a:0:{}s:26:"HTML.AllowedCommentsRegexp";N;s:20:"HTML.AllowedElements";N;s:19:"HTML.AllowedModules";N;s:23:"HTML.Attr.Name.UseCDATA";b:0;s:17:"HTML.BlockWrapper";s:1:"p";s:16:"HTML.CoreModules";a:7:{s:9:"Structure";b:1;s:4:"Text";b:1;s:9:"Hypertext";b:1;s:4:"List";b:1;s:22:"NonXMLCommonAttributes";b:1;s:19:"XMLCommonAttributes";b:1;s:16:"CommonAttributes";b:1;}s:18:"HTML.CustomDoctype";N;s:17:"HTML.DefinitionID";N;s:18:"HTML.DefinitionRev";i:1;s:12:"HTML.Doctype";N;s:25:"HTML.FlashAllowFullScreen";b:0;s:24:"HTML.ForbiddenAttributes";a:0:{}s:22:"HTML.ForbiddenElements";a:0:{}s:10:"HTML.Forms";b:0;s:17:"HTML.MaxImgLength";i:1200;s:13:"HTML.Nofollow";b:0;s:11:"HTML.Parent";s:3:"div";s:16:"HTML.Proprietary";b:0;s:14:"HTML.SafeEmbed";b:0;s:15:"HTML.SafeIframe";b:0;s:15:"HTML.SafeObject";b:0;s:18:"HTML.SafeScripting";a:0:{}s:11:"HTML.Strict";b:0;s:16:"HTML.TargetBlank";b:0;s:19:"HTML.TargetNoopener";b:1;s:21:"HTML.TargetNoreferrer";b:1;s:12:"HTML.TidyAdd";a:0:{}s:14:"HTML.TidyLevel";s:6:"medium";s:15:"HTML.TidyRemove";a:0:{}s:12:"HTML.Trusted";b:0;s:10:"HTML.XHTML";b:1;s:28:"Output.CommentScriptContents";b:1;s:19:"Output.FixInnerHTML";b:1;s:18:"Output.FlashCompat";b:0;s:14:"Output.Newline";N;s:15:"Output.SortAttr";b:0;s:17:"Output.TidyFormat";b:0;s:17:"Test.ForceNoIconv";b:0;s:18:"URI.AllowedSchemes";a:7:{s:4:"http";b:1;s:5:"https";b:1;s:6:"mailto";b:1;s:3:"ftp";b:1;s:4:"nntp";b:1;s:4:"news";b:1;s:3:"tel";b:1;}s:8:"URI.Base";N;s:17:"URI.DefaultScheme";s:4:"http";s:16:"URI.DefinitionID";N;s:17:"URI.DefinitionRev";i:1;s:11:"URI.Disable";b:0;s:19:"URI.DisableExternal";b:0;s:28:"URI.DisableExternalResources";b:0;s:20:"URI.DisableResources";b:0;s:8:"URI.Host";N;s:17:"URI.HostBlacklist";a:0:{}s:16:"URI.MakeAbsolute";b:0;s:9:"URI.Munge";N;s:18:"URI.MungeResources";b:0;s:18:"URI.MungeSecretKey";N;s:26:"URI.OverrideAllowedSchemes";b:1;s:20:"URI.SafeIframeRegexp";N;}s:12:"defaultPlist";O:25:"HTMLPurifier_PropertyList":3:{s:7:"*data";a:128:{s:19:"Attr.AllowedClasses";N;s:24:"Attr.AllowedFrameTargets";a:0:{}s:15:"Attr.AllowedRel";a:0:{}s:15:"Attr.AllowedRev";a:0:{}s:18:"Attr.ClassUseCDATA";N;s:20:"Attr.DefaultImageAlt";N;s:24:"Attr.DefaultInvalidImage";s:0:"";s:27:"Attr.DefaultInvalidImageAlt";s:13:"Invalid image";s:19:"Attr.DefaultTextDir";s:3:"ltr";s:13:"Attr.EnableID";b:0;s:21:"Attr.ForbiddenClasses";a:0:{}s:13:"Attr.ID.HTML5";N;s:16:"Attr.IDBlacklist";a:0:{}s:22:"Attr.IDBlacklistRegexp";N;s:13:"Attr.IDPrefix";s:0:"";s:18:"Attr.IDPrefixLocal";s:0:"";s:24:"AutoFormat.AutoParagraph";b:0;s:17:"AutoFormat.Custom";a:0:{}s:25:"AutoFormat.DisplayLinkURI";b:0;s:18:"AutoFormat.Linkify";b:0;s:33:"AutoFormat.PurifierLinkify.DocURL";s:3:"#%s";s:26:"AutoFormat.PurifierLinkify";b:0;s:32:"AutoFormat.RemoveEmpty.Predicate";a:4:{s:8:"colgroup";a:0:{}s:2:"th";a:0:{}s:2:"td";a:0:{}s:6:"iframe";a:1:{i:0;s:3:"src";}}s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";a:2:{s:2:"td";b:1;s:2:"th";b:1;}s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";b:0;s:22:"AutoFormat.RemoveEmpty";b:0;s:39:"AutoFormat.RemoveSpansWithoutAttributes";b:0;s:19:"CSS.AllowDuplicates";b:0;s:18:"CSS.AllowImportant";b:0;s:15:"CSS.AllowTricky";b:0;s:16:"CSS.AllowedFonts";N;s:21:"CSS.AllowedProperties";N;s:17:"CSS.DefinitionRev";i:1;s:23:"CSS.ForbiddenProperties";a:0:{}s:16:"CSS.MaxImgLength";s:6:"1200px";s:15:"CSS.Proprietary";b:0;s:11:"CSS.Trusted";b:0;s:20:"Cache.DefinitionImpl";s:10:"Serializer";s:20:"Cache.SerializerPath";N;s:27:"Cache.SerializerPermissions";i:493;s:22:"Core.AggressivelyFixLt";b:1;s:29:"Core.AggressivelyRemoveScript";b:1;s:28:"Core.AllowHostnameUnderscore";b:0;s:23:"Core.AllowParseManyTags";b:0;s:18:"Core.CollectErrors";b:0;s:18:"Core.ColorKeywords";a:148:{s:9:"aliceblue";s:7:"#F0F8FF";s:12:"antiquewhite";s:7:"#FAEBD7";s:4:"aqua";s:7:"#00FFFF";s:10:"aquamarine";s:7:"#7FFFD4";s:5:"azure";s:7:"#F0FFFF";s:5:"beige";s:7:"#F5F5DC";s:6:"bisque";s:7:"#FFE4C4";s:5:"black";s:7:"#000000";s:14:"blanchedalmond";s:7:"#FFEBCD";s:4:"blue";s:7:"#0000FF";s:10:"blueviolet";s:7:"#8A2BE2";s:5:"brown";s:7:"#A52A2A";s:9:"burlywood";s:7:"#DEB887";s:9:"cadetblue";s:7:"#5F9EA0";s:10:"chartreuse";s:7:"#7FFF00";s:9:"chocolate";s:7:"#D2691E";s:5:"coral";s:7:"#FF7F50";s:14:"cornflowerblue";s:7:"#6495ED";s:8:"cornsilk";s:7:"#FFF8DC";s:7:"crimson";s:7:"#DC143C";s:4:"cyan";s:7:"#00FFFF";s:8:"darkblue";s:7:"#00008B";s:8:"darkcyan";s:7:"#008B8B";s:13:"darkgoldenrod";s:7:"#B8860B";s:8:"darkgray";s:7:"#A9A9A9";s:8:"darkgrey";s:7:"#A9A9A9";s:9:"darkgreen";s:7:"#006400";s:9:"darkkhaki";s:7:"#BDB76B";s:11:"darkmagenta";s:7:"#8B008B";s:14:"darkolivegreen";s:7:"#556B2F";s:10:"darkorange";s:7:"#FF8C00";s:10:"darkorchid";s:7:"#9932CC";s:7:"darkred";s:7:"#8B0000";s:10:"darksalmon";s:7:"#E9967A";s:12:"darkseagreen";s:7:"#8FBC8F";s:13:"darkslateblue";s:7:"#483D8B";s:13:"darkslategray";s:7:"#2F4F4F";s:13:"darkslategrey";s:7:"#2F4F4F";s:13:"darkturquoise";s:7:"#00CED1";s:10:"darkviolet";s:7:"#9400D3";s:8:"deeppink";s:7:"#FF1493";s:11:"deepskyblue";s:7:"#00BFFF";s:7:"dimgray";s:7:"#696969";s:7:"dimgrey";s:7:"#696969";s:10:"dodgerblue";s:7:"#1E90FF";s:9:"firebrick";s:7:"#B22222";s:11:"floralwhite";s:7:"#FFFAF0";s:11:"forestgreen";s:7:"#228B22";s:7:"fuchsia";s:7:"#FF00FF";s:9:"gainsboro";s:7:"#DCDCDC";s:10:"ghostwhite";s:7:"#F8F8FF";s:4:"gold";s:7:"#FFD700";s:9:"goldenrod";s:7:"#DAA520";s:4:"gray";s:7:"#808080";s:4:"grey";s:7:"#808080";s:5:"green";s:7:"#008000";s:11:"greenyellow";s:7:"#ADFF2F";s:8:"honeydew";s:7:"#F0FFF0";s:7:"hotpink";s:7:"#FF69B4";s:9:"indianred";s:7:"#CD5C5C";s:6:"indigo";s:7:"#4B0082";s:5:"ivory";s:7:"#FFFFF0";s:5:"khaki";s:7:"#F0E68C";s:8:"lavender";s:7:"#E6E6FA";s:13:"lavenderblush";s:7:"#FFF0F5";s:9:"lawngreen";s:7:"#7CFC00";s:12:"lemonchiffon";s:7:"#FFFACD";s:9:"lightblue";s:7:"#ADD8E6";s:10:"lightcoral";s:7:"#F08080";s:9:"lightcyan";s:7:"#E0FFFF";s:20:"lightgoldenrodyellow";s:7:"#FAFAD2";s:9:"lightgray";s:7:"#D3D3D3";s:9:"lightgrey";s:7:"#D3D3D3";s:10:"lightgreen";s:7:"#90EE90";s:9:"lightpink";s:7:"#FFB6C1";s:11:"lightsalmon";s:7:"#FFA07A";s:13:"lightseagreen";s:7:"#20B2AA";s:12:"lightskyblue";s:7:"#87CEFA";s:14:"lightslategray";s:7:"#778899";s:14:"lightslategrey";s:7:"#778899";s:14:"lightsteelblue";s:7:"#B0C4DE";s:11:"lightyellow";s:7:"#FFFFE0";s:4:"lime";s:7:"#00FF00";s:9:"limegreen";s:7:"#32CD32";s:5:"linen";s:7:"#FAF0E6";s:7:"magenta";s:7:"#FF00FF";s:6:"maroon";s:7:"#800000";s:16:"mediumaquamarine";s:7:"#66CDAA";s:10:"mediumblue";s:7:"#0000CD";s:12:"mediumorchid";s:7:"#BA55D3";s:12:"mediumpurple";s:7:"#9370DB";s:14:"mediumseagreen";s:7:"#3CB371";s:15:"mediumslateblue";s:7:"#7B68EE";s:17:"mediumspringgreen";s:7:"#00FA9A";s:15:"mediumturquoise";s:7:"#48D1CC";s:15:"mediumvioletred";s:7:"#C71585";s:12:"midnightblue";s:7:"#191970";s:9:"mintcream";s:7:"#F5FFFA";s:9:"mistyrose";s:7:"#FFE4E1";s:8:"moccasin";s:7:"#FFE4B5";s:11:"navajowhite";s:7:"#FFDEAD";s:4:"navy";s:7:"#000080";s:7:"oldlace";s:7:"#FDF5E6";s:5:"olive";s:7:"#808000";s:9:"olivedrab";s:7:"#6B8E23";s:6:"orange";s:7:"#FFA500";s:9:"orangered";s:7:"#FF4500";s:6:"orchid";s:7:"#DA70D6";s:13:"palegoldenrod";s:7:"#EEE8AA";s:9:"palegreen";s:7:"#98FB98";s:13:"paleturquoise";s:7:"#AFEEEE";s:13:"palevioletred";s:7:"#DB7093";s:10:"papayawhip";s:7:"#FFEFD5";s:9:"peachpuff";s:7:"#FFDAB9";s:4:"peru";s:7:"#CD853F";s:4:"pink";s:7:"#FFC0CB";s:4:"plum";s:7:"#DDA0DD";s:10:"powderblue";s:7:"#B0E0E6";s:6:"purple";s:7:"#800080";s:13:"rebeccapurple";s:7:"#663399";s:3:"red";s:7:"#FF0000";s:9:"rosybrown";s:7:"#BC8F8F";s:9:"royalblue";s:7:"#4169E1";s:11:"saddlebrown";s:7:"#8B4513";s:6:"salmon";s:7:"#FA8072";s:10:"sandybrown";s:7:"#F4A460";s:8:"seagreen";s:7:"#2E8B57";s:8:"seashell";s:7:"#FFF5EE";s:6:"sienna";s:7:"#A0522D";s:6:"silver";s:7:"#C0C0C0";s:7:"skyblue";s:7:"#87CEEB";s:9:"slateblue";s:7:"#6A5ACD";s:9:"slategray";s:7:"#708090";s:9:"slategrey";s:7:"#708090";s:4:"snow";s:7:"#FFFAFA";s:11:"springgreen";s:7:"#00FF7F";s:9:"steelblue";s:7:"#4682B4";s:3:"tan";s:7:"#D2B48C";s:4:"teal";s:7:"#008080";s:7:"thistle";s:7:"#D8BFD8";s:6:"tomato";s:7:"#FF6347";s:9:"turquoise";s:7:"#40E0D0";s:6:"violet";s:7:"#EE82EE";s:5:"wheat";s:7:"#F5DEB3";s:5:"white";s:7:"#FFFFFF";s:10:"whitesmoke";s:7:"#F5F5F5";s:6:"yellow";s:7:"#FFFF00";s:11:"yellowgreen";s:7:"#9ACD32";}s:30:"Core.ConvertDocumentToFragment";b:1;s:36:"Core.DirectLexLineNumberSyncInterval";i:0;s:20:"Core.DisableExcludes";b:0;s:15:"Core.EnableIDNA";b:0;s:13:"Core.Encoding";s:5:"utf-8";s:26:"Core.EscapeInvalidChildren";b:0;s:22:"Core.EscapeInvalidTags";b:0;s:29:"Core.EscapeNonASCIICharacters";b:0;s:19:"Core.HiddenElements";a:2:{s:6:"script";b:1;s:5:"style";b:1;}s:13:"Core.Language";s:2:"en";s:24:"Core.LegacyEntityDecoder";b:0;s:14:"Core.LexerImpl";N;s:24:"Core.MaintainLineNumbers";N;s:22:"Core.NormalizeNewlines";b:1;s:17:"Core.RemoveBlanks";b:0;s:21:"Core.RemoveInvalidImg";b:1;s:33:"Core.RemoveProcessingInstructions";b:0;s:25:"Core.RemoveScriptContents";N;s:13:"Filter.Custom";a:0:{}s:34:"Filter.ExtractStyleBlocks.Escaping";b:1;s:31:"Filter.ExtractStyleBlocks.Scope";N;s:34:"Filter.ExtractStyleBlocks.TidyImpl";N;s:25:"Filter.ExtractStyleBlocks";b:0;s:14:"Filter.YouTube";b:0;s:12:"HTML.Allowed";N;s:22:"HTML.AllowedAttributes";N;s:20:"HTML.AllowedComments";a:0:{}s:26:"HTML.AllowedCommentsRegexp";N;s:20:"HTML.AllowedElements";N;s:19:"HTML.AllowedModules";N;s:23:"HTML.Attr.Name.UseCDATA";b:0;s:17:"HTML.BlockWrapper";s:1:"p";s:16:"HTML.CoreModules";a:7:{s:9:"Structure";b:1;s:4:"Text";b:1;s:9:"Hypertext";b:1;s:4:"List";b:1;s:22:"NonXMLCommonAttributes";b:1;s:19:"XMLCommonAttributes";b:1;s:16:"CommonAttributes";b:1;}s:18:"HTML.CustomDoctype";N;s:17:"HTML.DefinitionID";N;s:18:"HTML.DefinitionRev";i:1;s:12:"HTML.Doctype";N;s:25:"HTML.FlashAllowFullScreen";b:0;s:24:"HTML.ForbiddenAttributes";a:0:{}s:22:"HTML.ForbiddenElements";a:0:{}s:10:"HTML.Forms";b:0;s:17:"HTML.MaxImgLength";i:1200;s:13:"HTML.Nofollow";b:0;s:11:"HTML.Parent";s:3:"div";s:16:"HTML.Proprietary";b:0;s:14:"HTML.SafeEmbed";b:0;s:15:"HTML.SafeIframe";b:0;s:15:"HTML.SafeObject";b:0;s:18:"HTML.SafeScripting";a:0:{}s:11:"HTML.Strict";b:0;s:16:"HTML.TargetBlank";b:0;s:19:"HTML.TargetNoopener";b:1;s:21:"HTML.TargetNoreferrer";b:1;s:12:"HTML.TidyAdd";a:0:{}s:14:"HTML.TidyLevel";s:6:"medium";s:15:"HTML.TidyRemove";a:0:{}s:12:"HTML.Trusted";b:0;s:10:"HTML.XHTML";b:1;s:28:"Output.CommentScriptContents";b:1;s:19:"Output.FixInnerHTML";b:1;s:18:"Output.FlashCompat";b:0;s:14:"Output.Newline";N;s:15:"Output.SortAttr";b:0;s:17:"Output.TidyFormat";b:0;s:17:"Test.ForceNoIconv";b:0;s:18:"URI.AllowedSchemes";a:7:{s:4:"http";b:1;s:5:"https";b:1;s:6:"mailto";b:1;s:3:"ftp";b:1;s:4:"nntp";b:1;s:4:"news";b:1;s:3:"tel";b:1;}s:8:"URI.Base";N;s:17:"URI.DefaultScheme";s:4:"http";s:16:"URI.DefinitionID";N;s:17:"URI.DefinitionRev";i:1;s:11:"URI.Disable";b:0;s:19:"URI.DisableExternal";b:0;s:28:"URI.DisableExternalResources";b:0;s:20:"URI.DisableResources";b:0;s:8:"URI.Host";N;s:17:"URI.HostBlacklist";a:0:{}s:16:"URI.MakeAbsolute";b:0;s:9:"URI.Munge";N;s:18:"URI.MungeResources";b:0;s:18:"URI.MungeSecretKey";N;s:26:"URI.OverrideAllowedSchemes";b:1;s:20:"URI.SafeIframeRegexp";N;}s:9:"*parent";N;s:8:"*cache";N;}s:4:"info";a:141:{s:19:"Attr.AllowedClasses";i:-8;s:24:"Attr.AllowedFrameTargets";i:8;s:15:"Attr.AllowedRel";i:8;s:15:"Attr.AllowedRev";i:8;s:18:"Attr.ClassUseCDATA";i:-7;s:20:"Attr.DefaultImageAlt";i:-1;s:24:"Attr.DefaultInvalidImage";i:1;s:27:"Attr.DefaultInvalidImageAlt";i:1;s:19:"Attr.DefaultTextDir";O:8:"stdClass":2:{s:4:"type";i:1;s:7:"allowed";a:2:{s:3:"ltr";b:1;s:3:"rtl";b:1;}}s:13:"Attr.EnableID";i:7;s:17:"HTML.EnableAttrID";O:8:"stdClass":2:{s:3:"key";s:13:"Attr.EnableID";s:7:"isAlias";b:1;}s:21:"Attr.ForbiddenClasses";i:8;s:13:"Attr.ID.HTML5";i:-7;s:16:"Attr.IDBlacklist";i:9;s:22:"Attr.IDBlacklistRegexp";i:-1;s:13:"Attr.IDPrefix";i:1;s:18:"Attr.IDPrefixLocal";i:1;s:24:"AutoFormat.AutoParagraph";i:7;s:17:"AutoFormat.Custom";i:9;s:25:"AutoFormat.DisplayLinkURI";i:7;s:18:"AutoFormat.Linkify";i:7;s:33:"AutoFormat.PurifierLinkify.DocURL";i:1;s:37:"AutoFormatParam.PurifierLinkifyDocURL";O:8:"stdClass":2:{s:3:"key";s:33:"AutoFormat.PurifierLinkify.DocURL";s:7:"isAlias";b:1;}s:26:"AutoFormat.PurifierLinkify";i:7;s:32:"AutoFormat.RemoveEmpty.Predicate";i:10;s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";i:8;s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";i:7;s:22:"AutoFormat.RemoveEmpty";i:7;s:39:"AutoFormat.RemoveSpansWithoutAttributes";i:7;s:19:"CSS.AllowDuplicates";i:7;s:18:"CSS.AllowImportant";i:7;s:15:"CSS.AllowTricky";i:7;s:16:"CSS.AllowedFonts";i:-8;s:21:"CSS.AllowedProperties";i:-8;s:17:"CSS.DefinitionRev";i:5;s:23:"CSS.ForbiddenProperties";i:8;s:16:"CSS.MaxImgLength";i:-1;s:15:"CSS.Proprietary";i:7;s:11:"CSS.Trusted";i:7;s:20:"Cache.DefinitionImpl";i:-1;s:20:"Core.DefinitionCache";O:8:"stdClass":2:{s:3:"key";s:20:"Cache.DefinitionImpl";s:7:"isAlias";b:1;}s:20:"Cache.SerializerPath";i:-1;s:27:"Cache.SerializerPermissions";i:-5;s:22:"Core.AggressivelyFixLt";i:7;s:29:"Core.AggressivelyRemoveScript";i:7;s:28:"Core.AllowHostnameUnderscore";i:7;s:23:"Core.AllowParseManyTags";i:7;s:18:"Core.CollectErrors";i:7;s:18:"Core.ColorKeywords";i:10;s:30:"Core.ConvertDocumentToFragment";i:7;s:24:"Core.AcceptFullDocuments";O:8:"stdClass":2:{s:3:"key";s:30:"Core.ConvertDocumentToFragment";s:7:"isAlias";b:1;}s:36:"Core.DirectLexLineNumberSyncInterval";i:5;s:20:"Core.DisableExcludes";i:7;s:15:"Core.EnableIDNA";i:7;s:13:"Core.Encoding";i:2;s:26:"Core.EscapeInvalidChildren";i:7;s:22:"Core.EscapeInvalidTags";i:7;s:29:"Core.EscapeNonASCIICharacters";i:7;s:19:"Core.HiddenElements";i:8;s:13:"Core.Language";i:1;s:24:"Core.LegacyEntityDecoder";i:7;s:14:"Core.LexerImpl";i:-11;s:24:"Core.MaintainLineNumbers";i:-7;s:22:"Core.NormalizeNewlines";i:7;s:17:"Core.RemoveBlanks";i:7;s:21:"Core.RemoveInvalidImg";i:7;s:33:"Core.RemoveProcessingInstructions";i:7;s:25:"Core.RemoveScriptContents";i:-7;s:13:"Filter.Custom";i:9;s:34:"Filter.ExtractStyleBlocks.Escaping";i:7;s:33:"Filter.ExtractStyleBlocksEscaping";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.Escaping";s:7:"isAlias";b:1;}s:38:"FilterParam.ExtractStyleBlocksEscaping";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.Escaping";s:7:"isAlias";b:1;}s:31:"Filter.ExtractStyleBlocks.Scope";i:-1;s:30:"Filter.ExtractStyleBlocksScope";O:8:"stdClass":2:{s:3:"key";s:31:"Filter.ExtractStyleBlocks.Scope";s:7:"isAlias";b:1;}s:35:"FilterParam.ExtractStyleBlocksScope";O:8:"stdClass":2:{s:3:"key";s:31:"Filter.ExtractStyleBlocks.Scope";s:7:"isAlias";b:1;}s:34:"Filter.ExtractStyleBlocks.TidyImpl";i:-11;s:38:"FilterParam.ExtractStyleBlocksTidyImpl";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.TidyImpl";s:7:"isAlias";b:1;}s:25:"Filter.ExtractStyleBlocks";i:7;s:14:"Filter.YouTube";i:7;s:12:"HTML.Allowed";i:-4;s:22:"HTML.AllowedAttributes";i:-8;s:20:"HTML.AllowedComments";i:8;s:26:"HTML.AllowedCommentsRegexp";i:-1;s:20:"HTML.AllowedElements";i:-8;s:19:"HTML.AllowedModules";i:-8;s:23:"HTML.Attr.Name.UseCDATA";i:7;s:17:"HTML.BlockWrapper";i:1;s:16:"HTML.CoreModules";i:8;s:18:"HTML.CustomDoctype";i:-1;s:17:"HTML.DefinitionID";i:-1;s:18:"HTML.DefinitionRev";i:5;s:12:"HTML.Doctype";O:8:"stdClass":3:{s:4:"type";i:1;s:10:"allow_null";b:1;s:7:"allowed";a:5:{s:22:"HTML 4.01 Transitional";b:1;s:16:"HTML 4.01 Strict";b:1;s:22:"XHTML 1.0 Transitional";b:1;s:16:"XHTML 1.0 Strict";b:1;s:9:"XHTML 1.1";b:1;}}s:25:"HTML.FlashAllowFullScreen";i:7;s:24:"HTML.ForbiddenAttributes";i:8;s:22:"HTML.ForbiddenElements";i:8;s:10:"HTML.Forms";i:7;s:17:"HTML.MaxImgLength";i:-5;s:13:"HTML.Nofollow";i:7;s:11:"HTML.Parent";i:1;s:16:"HTML.Proprietary";i:7;s:14:"HTML.SafeEmbed";i:7;s:15:"HTML.SafeIframe";i:7;s:15:"HTML.SafeObject";i:7;s:18:"HTML.SafeScripting";i:8;s:11:"HTML.Strict";i:7;s:16:"HTML.TargetBlank";i:7;s:19:"HTML.TargetNoopener";i:7;s:21:"HTML.TargetNoreferrer";i:7;s:12:"HTML.TidyAdd";i:8;s:14:"HTML.TidyLevel";O:8:"stdClass":2:{s:4:"type";i:1;s:7:"allowed";a:4:{s:4:"none";b:1;s:5:"light";b:1;s:6:"medium";b:1;s:5:"heavy";b:1;}}s:15:"HTML.TidyRemove";i:8;s:12:"HTML.Trusted";i:7;s:10:"HTML.XHTML";i:7;s:10:"Core.XHTML";O:8:"stdClass":2:{s:3:"key";s:10:"HTML.XHTML";s:7:"isAlias";b:1;}s:28:"Output.CommentScriptContents";i:7;s:26:"Core.CommentScriptContents";O:8:"stdClass":2:{s:3:"key";s:28:"Output.CommentScriptContents";s:7:"isAlias";b:1;}s:19:"Output.FixInnerHTML";i:7;s:18:"Output.FlashCompat";i:7;s:14:"Output.Newline";i:-1;s:15:"Output.SortAttr";i:7;s:17:"Output.TidyFormat";i:7;s:15:"Core.TidyFormat";O:8:"stdClass":2:{s:3:"key";s:17:"Output.TidyFormat";s:7:"isAlias";b:1;}s:17:"Test.ForceNoIconv";i:7;s:18:"URI.AllowedSchemes";i:8;s:8:"URI.Base";i:-1;s:17:"URI.DefaultScheme";i:-1;s:16:"URI.DefinitionID";i:-1;s:17:"URI.DefinitionRev";i:5;s:11:"URI.Disable";i:7;s:15:"Attr.DisableURI";O:8:"stdClass":2:{s:3:"key";s:11:"URI.Disable";s:7:"isAlias";b:1;}s:19:"URI.DisableExternal";i:7;s:28:"URI.DisableExternalResources";i:7;s:20:"URI.DisableResources";i:7;s:8:"URI.Host";i:-1;s:17:"URI.HostBlacklist";i:9;s:16:"URI.MakeAbsolute";i:7;s:9:"URI.Munge";i:-1;s:18:"URI.MungeResources";i:7;s:18:"URI.MungeSecretKey";i:-1;s:26:"URI.OverrideAllowedSchemes";i:7;s:20:"URI.SafeIframeRegexp";i:-1;}} \ No newline at end of file diff --git a/tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveBlanks.txt b/tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveBlanks.txt new file mode 100644 index 000000000..95e5285ca --- /dev/null +++ b/tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.RemoveBlanks.txt @@ -0,0 +1,10 @@ +Core.RemoveBlanks +TYPE: bool +DEFAULT: false +VERSION: 4.18 +--DESCRIPTION-- +

+ If set to true, blank nodes will be removed. This can be useful for maintaining + backwards compatibility when upgrading from previous versions of PHP. +

+--# vim: et sw=4 sts=4 diff --git a/tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema/index.php b/tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/index.php b/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer.php b/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer.php index b82c6bb20..bfad967fb 100644 --- a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer.php +++ b/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer.php @@ -287,13 +287,14 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac } elseif (filegroup($dir) === posix_getgid()) { $chmod = $chmod | 0070; } else { - // PHP's probably running as nobody, so we'll - // need to give global permissions - $chmod = $chmod | 0777; + // PHP's probably running as nobody, it is + // not obvious how to fix this (777 is probably + // bad if you are multi-user), let the user figure it out + $chmod = null; } trigger_error( - 'Directory ' . $dir . ' not writable, ' . - 'please chmod to ' . decoct($chmod), + 'Directory ' . $dir . ' not writable. ' . + ($chmod === null ? '' : 'Please chmod to ' . decoct($chmod)), E_USER_WARNING ); } else { diff --git a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer/index.php b/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/index.php b/tools/htmlpurifier/HTMLPurifier/DefinitionCache/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/DefinitionCacheFactory.php b/tools/htmlpurifier/HTMLPurifier/DefinitionCacheFactory.php index fd1cc9be4..3a0f4616a 100644 --- a/tools/htmlpurifier/HTMLPurifier/DefinitionCacheFactory.php +++ b/tools/htmlpurifier/HTMLPurifier/DefinitionCacheFactory.php @@ -71,7 +71,7 @@ class HTMLPurifier_DefinitionCacheFactory return $this->caches[$method][$type]; } if (isset($this->implementations[$method]) && - class_exists($class = $this->implementations[$method], false)) { + class_exists($class = $this->implementations[$method])) { $cache = new $class($type); } else { if ($method != 'Serializer') { diff --git a/tools/htmlpurifier/HTMLPurifier/ElementDef.php b/tools/htmlpurifier/HTMLPurifier/ElementDef.php index d5311cedc..57cfd2bb0 100644 --- a/tools/htmlpurifier/HTMLPurifier/ElementDef.php +++ b/tools/htmlpurifier/HTMLPurifier/ElementDef.php @@ -176,7 +176,7 @@ class HTMLPurifier_ElementDef if (!empty($def->content_model)) { $this->content_model = - str_replace("#SUPER", $this->content_model, $def->content_model); + str_replace("#SUPER", (string)$this->content_model, $def->content_model); $this->child = false; } if (!empty($def->content_model_type)) { diff --git a/tools/htmlpurifier/HTMLPurifier/Encoder.php b/tools/htmlpurifier/HTMLPurifier/Encoder.php index 40a24266a..d4791cc1b 100644 --- a/tools/htmlpurifier/HTMLPurifier/Encoder.php +++ b/tools/htmlpurifier/HTMLPurifier/Encoder.php @@ -398,8 +398,8 @@ class HTMLPurifier_Encoder // characters to their true byte-wise ASCII/UTF-8 equivalents. $str = strtr($str, self::testEncodingSupportsASCII($encoding)); return $str; - } elseif ($encoding === 'iso-8859-1') { - $str = utf8_encode($str); + } elseif ($encoding === 'iso-8859-1' && function_exists('mb_convert_encoding')) { + $str = mb_convert_encoding($str, 'UTF-8', 'ISO-8859-1'); return $str; } $bug = HTMLPurifier_Encoder::testIconvTruncateBug(); @@ -450,8 +450,8 @@ class HTMLPurifier_Encoder // Normal stuff $str = self::iconv('utf-8', $encoding . '//IGNORE', $str); return $str; - } elseif ($encoding === 'iso-8859-1') { - $str = utf8_decode($str); + } elseif ($encoding === 'iso-8859-1' && function_exists('mb_convert_encoding')) { + $str = mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8'); return $str; } trigger_error('Encoding not supported', E_USER_ERROR); diff --git a/tools/htmlpurifier/HTMLPurifier/EntityLookup/index.php b/tools/htmlpurifier/HTMLPurifier/EntityLookup/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/EntityLookup/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/EntityParser.php b/tools/htmlpurifier/HTMLPurifier/EntityParser.php index 3ef2d09ec..0f2b83dc8 100644 --- a/tools/htmlpurifier/HTMLPurifier/EntityParser.php +++ b/tools/htmlpurifier/HTMLPurifier/EntityParser.php @@ -116,8 +116,8 @@ class HTMLPurifier_EntityParser protected function entityCallback($matches) { $entity = $matches[0]; - $hex_part = @$matches[1]; - $dec_part = @$matches[2]; + $hex_part = isset($matches[1]) ? $matches[1] : null; + $dec_part = isset($matches[2]) ? $matches[2] : null; $named_part = empty($matches[3]) ? (empty($matches[4]) ? "" : $matches[4]) : $matches[3]; if ($hex_part !== NULL && $hex_part !== "") { return HTMLPurifier_Encoder::unichr(hexdec($hex_part)); diff --git a/tools/htmlpurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php b/tools/htmlpurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php index 66f70b0fc..e7e3cac1a 100644 --- a/tools/htmlpurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php +++ b/tools/htmlpurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php @@ -54,6 +54,11 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter */ private $_enum_attrdef; + /** + * @type HTMLPurifier_AttrDef_Enum + */ + private $_universal_attrdef; + public function __construct() { $this->_tidy = new csstidy(); @@ -70,6 +75,13 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter 'focus' ) ); + $this->_universal_attrdef = new HTMLPurifier_AttrDef_Enum( + array( + 'initial', + 'inherit', + 'unset', + ) + ); } /** @@ -146,175 +158,184 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter foreach ($this->_tidy->css as $k => $decls) { // $decls are all CSS declarations inside an @ selector $new_decls = array(); - foreach ($decls as $selector => $style) { - $selector = trim($selector); - if ($selector === '') { - continue; - } // should not happen - // Parse the selector - // Here is the relevant part of the CSS grammar: - // - // ruleset - // : selector [ ',' S* selector ]* '{' ... - // selector - // : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]? - // combinator - // : '+' S* - // : '>' S* - // simple_selector - // : element_name [ HASH | class | attrib | pseudo ]* - // | [ HASH | class | attrib | pseudo ]+ - // element_name - // : IDENT | '*' - // ; - // class - // : '.' IDENT - // ; - // attrib - // : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S* - // [ IDENT | STRING ] S* ]? ']' - // ; - // pseudo - // : ':' [ IDENT | FUNCTION S* [IDENT S*]? ')' ] - // ; - // - // For reference, here are the relevant tokens: - // - // HASH #{name} - // IDENT {ident} - // INCLUDES == - // DASHMATCH |= - // STRING {string} - // FUNCTION {ident}\( - // - // And the lexical scanner tokens - // - // name {nmchar}+ - // nmchar [_a-z0-9-]|{nonascii}|{escape} - // nonascii [\240-\377] - // escape {unicode}|\\[^\r\n\f0-9a-f] - // unicode \\{h}}{1,6}(\r\n|[ \t\r\n\f])? - // ident -?{nmstart}{nmchar*} - // nmstart [_a-z]|{nonascii}|{escape} - // string {string1}|{string2} - // string1 \"([^\n\r\f\\"]|\\{nl}|{escape})*\" - // string2 \'([^\n\r\f\\"]|\\{nl}|{escape})*\' - // - // We'll implement a subset (in order to reduce attack - // surface); in particular: - // - // - No Unicode support - // - No escapes support - // - No string support (by proxy no attrib support) - // - element_name is matched against allowed - // elements (some people might find this - // annoying...) - // - Pseudo-elements one of :first-child, :link, - // :visited, :active, :hover, :focus + if (is_array($decls)) { + foreach ($decls as $selector => $style) { + $selector = trim($selector); + if ($selector === '') { + continue; + } // should not happen + // Parse the selector + // Here is the relevant part of the CSS grammar: + // + // ruleset + // : selector [ ',' S* selector ]* '{' ... + // selector + // : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]? + // combinator + // : '+' S* + // : '>' S* + // simple_selector + // : element_name [ HASH | class | attrib | pseudo ]* + // | [ HASH | class | attrib | pseudo ]+ + // element_name + // : IDENT | '*' + // ; + // class + // : '.' IDENT + // ; + // attrib + // : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S* + // [ IDENT | STRING ] S* ]? ']' + // ; + // pseudo + // : ':' [ IDENT | FUNCTION S* [IDENT S*]? ')' ] + // ; + // + // For reference, here are the relevant tokens: + // + // HASH #{name} + // IDENT {ident} + // INCLUDES == + // DASHMATCH |= + // STRING {string} + // FUNCTION {ident}\( + // + // And the lexical scanner tokens + // + // name {nmchar}+ + // nmchar [_a-z0-9-]|{nonascii}|{escape} + // nonascii [\240-\377] + // escape {unicode}|\\[^\r\n\f0-9a-f] + // unicode \\{h}}{1,6}(\r\n|[ \t\r\n\f])? + // ident -?{nmstart}{nmchar*} + // nmstart [_a-z]|{nonascii}|{escape} + // string {string1}|{string2} + // string1 \"([^\n\r\f\\"]|\\{nl}|{escape})*\" + // string2 \'([^\n\r\f\\"]|\\{nl}|{escape})*\' + // + // We'll implement a subset (in order to reduce attack + // surface); in particular: + // + // - No Unicode support + // - No escapes support + // - No string support (by proxy no attrib support) + // - element_name is matched against allowed + // elements (some people might find this + // annoying...) + // - Pseudo-elements one of :first-child, :link, + // :visited, :active, :hover, :focus - // handle ruleset - $selectors = array_map('trim', explode(',', $selector)); - $new_selectors = array(); - foreach ($selectors as $sel) { - // split on +, > and spaces - $basic_selectors = preg_split('/\s*([+> ])\s*/', $sel, -1, PREG_SPLIT_DELIM_CAPTURE); - // even indices are chunks, odd indices are - // delimiters - $nsel = null; - $delim = null; // guaranteed to be non-null after - // two loop iterations - for ($i = 0, $c = count($basic_selectors); $i < $c; $i++) { - $x = $basic_selectors[$i]; - if ($i % 2) { - // delimiter - if ($x === ' ') { - $delim = ' '; - } else { - $delim = ' ' . $x . ' '; - } - } else { - // simple selector - $components = preg_split('/([#.:])/', $x, -1, PREG_SPLIT_DELIM_CAPTURE); - $sdelim = null; - $nx = null; - for ($j = 0, $cc = count($components); $j < $cc; $j++) { - $y = $components[$j]; - if ($j === 0) { - if ($y === '*' || isset($html_definition->info[$y = strtolower($y)])) { - $nx = $y; - } else { - // $nx stays null; this matters - // if we don't manage to find - // any valid selector content, - // in which case we ignore the - // outer $delim - } - } elseif ($j % 2) { - // set delimiter - $sdelim = $y; + // handle ruleset + $selectors = array_map('trim', explode(',', $selector)); + $new_selectors = array(); + foreach ($selectors as $sel) { + // split on +, > and spaces + $basic_selectors = preg_split('/\s*([+> ])\s*/', $sel, -1, PREG_SPLIT_DELIM_CAPTURE); + // even indices are chunks, odd indices are + // delimiters + $nsel = null; + $delim = null; // guaranteed to be non-null after + // two loop iterations + for ($i = 0, $c = count($basic_selectors); $i < $c; $i++) { + $x = $basic_selectors[$i]; + if ($i % 2) { + // delimiter + if ($x === ' ') { + $delim = ' '; } else { - $attrdef = null; - if ($sdelim === '#') { - $attrdef = $this->_id_attrdef; - } elseif ($sdelim === '.') { - $attrdef = $this->_class_attrdef; - } elseif ($sdelim === ':') { - $attrdef = $this->_enum_attrdef; - } else { - throw new HTMLPurifier_Exception('broken invariant sdelim and preg_split'); - } - $r = $attrdef->validate($y, $config, $context); - if ($r !== false) { - if ($r !== true) { - $y = $r; - } - if ($nx === null) { - $nx = ''; - } - $nx .= $sdelim . $y; - } - } - } - if ($nx !== null) { - if ($nsel === null) { - $nsel = $nx; - } else { - $nsel .= $delim . $nx; + $delim = ' ' . $x . ' '; } } else { - // delimiters to the left of invalid - // basic selector ignored + // simple selector + $components = preg_split('/([#.:])/', $x, -1, PREG_SPLIT_DELIM_CAPTURE); + $sdelim = null; + $nx = null; + for ($j = 0, $cc = count($components); $j < $cc; $j++) { + $y = $components[$j]; + if ($j === 0) { + if ($y === '*' || isset($html_definition->info[$y = strtolower($y)])) { + $nx = $y; + } else { + // $nx stays null; this matters + // if we don't manage to find + // any valid selector content, + // in which case we ignore the + // outer $delim + } + } elseif ($j % 2) { + // set delimiter + $sdelim = $y; + } else { + $attrdef = null; + if ($sdelim === '#') { + $attrdef = $this->_id_attrdef; + } elseif ($sdelim === '.') { + $attrdef = $this->_class_attrdef; + } elseif ($sdelim === ':') { + $attrdef = $this->_enum_attrdef; + } else { + throw new HTMLPurifier_Exception('broken invariant sdelim and preg_split'); + } + $r = $attrdef->validate($y, $config, $context); + if ($r !== false) { + if ($r !== true) { + $y = $r; + } + if ($nx === null) { + $nx = ''; + } + $nx .= $sdelim . $y; + } + } + } + if ($nx !== null) { + if ($nsel === null) { + $nsel = $nx; + } else { + $nsel .= $delim . $nx; + } + } else { + // delimiters to the left of invalid + // basic selector ignored + } + } + } + if ($nsel !== null) { + if (!empty($scopes)) { + foreach ($scopes as $s) { + $new_selectors[] = "$s $nsel"; + } + } else { + $new_selectors[] = $nsel; } } } - if ($nsel !== null) { - if (!empty($scopes)) { - foreach ($scopes as $s) { - $new_selectors[] = "$s $nsel"; - } - } else { - $new_selectors[] = $nsel; - } - } - } - if (empty($new_selectors)) { - continue; - } - $selector = implode(', ', $new_selectors); - foreach ($style as $name => $value) { - if (!isset($css_definition->info[$name])) { - unset($style[$name]); + if (empty($new_selectors)) { continue; } - $def = $css_definition->info[$name]; - $ret = $def->validate($value, $config, $context); - if ($ret === false) { - unset($style[$name]); - } else { - $style[$name] = $ret; + $selector = implode(', ', $new_selectors); + foreach ($style as $name => $value) { + if (!isset($css_definition->info[$name])) { + unset($style[$name]); + continue; + } + $uni_ret = $this->_universal_attrdef->validate($value, $config, $context); + if ($uni_ret !== false) { + $style[$name] = $uni_ret; + continue; + } + $def = $css_definition->info[$name]; + $ret = $def->validate($value, $config, $context); + if ($ret === false) { + unset($style[$name]); + } else { + $style[$name] = $ret; + } } + $new_decls[$selector] = $style; } - $new_decls[$selector] = $style; + } else { + continue; } $new_css[$k] = $new_decls; } diff --git a/tools/htmlpurifier/HTMLPurifier/Filter/index.php b/tools/htmlpurifier/HTMLPurifier/Filter/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Filter/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/HTMLModule.php b/tools/htmlpurifier/HTMLPurifier/HTMLModule.php index 6d898f80c..9dbb98729 100644 --- a/tools/htmlpurifier/HTMLPurifier/HTMLModule.php +++ b/tools/htmlpurifier/HTMLPurifier/HTMLModule.php @@ -257,8 +257,9 @@ class HTMLPurifier_HTMLModule */ public function makeLookup($list) { + $args = func_get_args(); if (is_string($list)) { - $list = func_get_args(); + $list = $args; } $ret = array(); foreach ($list as $value) { diff --git a/tools/htmlpurifier/HTMLPurifier/HTMLModule/CommonAttributes.php b/tools/htmlpurifier/HTMLPurifier/HTMLModule/CommonAttributes.php index a96ab1bef..7220c14cc 100644 --- a/tools/htmlpurifier/HTMLPurifier/HTMLModule/CommonAttributes.php +++ b/tools/htmlpurifier/HTMLPurifier/HTMLModule/CommonAttributes.php @@ -17,6 +17,7 @@ class HTMLPurifier_HTMLModule_CommonAttributes extends HTMLPurifier_HTMLModule 'class' => 'Class', 'id' => 'ID', 'title' => 'CDATA', + 'contenteditable' => 'ContentEditable', ), 'Lang' => array(), 'I18N' => array( diff --git a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Iframe.php b/tools/htmlpurifier/HTMLPurifier/HTMLModule/Iframe.php index f7e7c91c0..71dfc7744 100644 --- a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Iframe.php +++ b/tools/htmlpurifier/HTMLPurifier/HTMLModule/Iframe.php @@ -28,22 +28,28 @@ class HTMLPurifier_HTMLModule_Iframe extends HTMLPurifier_HTMLModule if ($config->get('HTML.SafeIframe')) { $this->safe = true; } + $attrs = array( + 'src' => 'URI#embedded', + 'width' => 'Length', + 'height' => 'Length', + 'name' => 'ID', + 'scrolling' => 'Enum#yes,no,auto', + 'frameborder' => 'Enum#0,1', + 'longdesc' => 'URI', + 'marginheight' => 'Pixels', + 'marginwidth' => 'Pixels', + ); + + if ($config->get('HTML.Trusted')) { + $attrs['allowfullscreen'] = 'Bool#allowfullscreen'; + } + $this->addElement( 'iframe', 'Inline', 'Flow', 'Common', - array( - 'src' => 'URI#embedded', - 'width' => 'Length', - 'height' => 'Length', - 'name' => 'ID', - 'scrolling' => 'Enum#yes,no,auto', - 'frameborder' => 'Enum#0,1', - 'longdesc' => 'URI', - 'marginheight' => 'Pixels', - 'marginwidth' => 'Pixels', - ) + $attrs ); } } diff --git a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy.php b/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy.php index 08aa23247..76fd93a6c 100644 --- a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy.php +++ b/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy.php @@ -146,10 +146,7 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule $type = "info_$type"; $e = $this; } - // PHP does some weird parsing when I do - // $e->$type[$attr], so I have to assign a ref. - $f =& $e->$type; - $f[$attr] = $fix; + $e->{$type}[$attr] = $fix; break; case 'tag_transform': $this->info_tag_transform[$params['element']] = $fix; @@ -224,6 +221,7 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule */ public function makeFixes() { + return array(); } } diff --git a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php b/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php index 700a25dbc..9ee3ffcc9 100644 --- a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php +++ b/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php @@ -168,9 +168,11 @@ class HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4 extends HTMLPurifier_HTMLModule // @vspace for img ------------------------------------------------ $r['img@vspace'] = new HTMLPurifier_AttrTransform_ImgSpace('vspace'); - // @width for hr, td, th ------------------------------------------ + // @width for table, hr, td, th, col ------------------------------------------ + $r['table@width'] = $r['td@width'] = $r['th@width'] = + $r['col@width'] = $r['hr@width'] = new HTMLPurifier_AttrTransform_Length('width'); return $r; diff --git a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/index.php b/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/HTMLModule/index.php b/tools/htmlpurifier/HTMLPurifier/HTMLModule/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/HTMLModule/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/Injector/Linkify.php b/tools/htmlpurifier/HTMLPurifier/Injector/Linkify.php index 74f83eaa7..3b6d70f6e 100644 --- a/tools/htmlpurifier/HTMLPurifier/Injector/Linkify.php +++ b/tools/htmlpurifier/HTMLPurifier/Injector/Linkify.php @@ -40,6 +40,9 @@ class HTMLPurifier_Injector_Linkify extends HTMLPurifier_Injector '/\\b((?:[a-z][\\w\\-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/)(?:[^\\s()<>]|\\((?:[^\\s()<>]|(?:\\([^\\s()<>]+\\)))*\\))+(?:\\((?:[^\\s()<>]|(?:\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'".,<>?\x{00ab}\x{00bb}\x{201c}\x{201d}\x{2018}\x{2019}]))/iu', $token->data, -1, PREG_SPLIT_DELIM_CAPTURE); + if ($bits === false) { + return; + } $token = array(); diff --git a/tools/htmlpurifier/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php b/tools/htmlpurifier/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php index 9ee7aa84d..42d514447 100644 --- a/tools/htmlpurifier/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php +++ b/tools/htmlpurifier/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php @@ -31,6 +31,16 @@ class HTMLPurifier_Injector_RemoveSpansWithoutAttributes extends HTMLPurifier_In */ private $context; + /** + * @type SplObjectStorage + */ + private $markForDeletion; + + public function __construct() + { + $this->markForDeletion = new SplObjectStorage(); + } + public function prepare($config, $context) { $this->attrValidator = new HTMLPurifier_AttrValidator(); @@ -64,7 +74,7 @@ class HTMLPurifier_Injector_RemoveSpansWithoutAttributes extends HTMLPurifier_In if ($current instanceof HTMLPurifier_Token_End && $current->name === 'span') { // Mark closing span tag for deletion - $current->markForDeletion = true; + $this->markForDeletion->attach($current); // Delete open span tag $token = false; } @@ -75,7 +85,8 @@ class HTMLPurifier_Injector_RemoveSpansWithoutAttributes extends HTMLPurifier_In */ public function handleEnd(&$token) { - if ($token->markForDeletion) { + if ($this->markForDeletion->contains($token)) { + $this->markForDeletion->detach($token); $token = false; } } diff --git a/tools/htmlpurifier/HTMLPurifier/Injector/index.php b/tools/htmlpurifier/HTMLPurifier/Injector/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Injector/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/Language/index.php b/tools/htmlpurifier/HTMLPurifier/Language/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Language/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/Language/messages/index.php b/tools/htmlpurifier/HTMLPurifier/Language/messages/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Language/messages/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/LanguageFactory.php b/tools/htmlpurifier/HTMLPurifier/LanguageFactory.php index 4e35272d8..16a4f6932 100644 --- a/tools/htmlpurifier/HTMLPurifier/LanguageFactory.php +++ b/tools/htmlpurifier/HTMLPurifier/LanguageFactory.php @@ -109,7 +109,7 @@ class HTMLPurifier_LanguageFactory } else { $class = 'HTMLPurifier_Language_' . $pcode; $file = $this->dir . '/Language/classes/' . $code . '.php'; - if (file_exists($file) || class_exists($class, false)) { + if (file_exists($file) || class_exists($class)) { $lang = new $class($config, $context); } else { // Go fallback diff --git a/tools/htmlpurifier/HTMLPurifier/Length.php b/tools/htmlpurifier/HTMLPurifier/Length.php index e70da55a9..b6ea12345 100644 --- a/tools/htmlpurifier/HTMLPurifier/Length.php +++ b/tools/htmlpurifier/HTMLPurifier/Length.php @@ -78,7 +78,7 @@ class HTMLPurifier_Length if ($this->n === '0' && $this->unit === false) { return true; } - if (!ctype_lower($this->unit)) { + if ($this->unit === false || !ctype_lower($this->unit)) { $this->unit = strtolower($this->unit); } if (!isset(HTMLPurifier_Length::$allowedUnits[$this->unit])) { diff --git a/tools/htmlpurifier/HTMLPurifier/Lexer.php b/tools/htmlpurifier/HTMLPurifier/Lexer.php index e9da3ed5e..fe87fa4ba 100644 --- a/tools/htmlpurifier/HTMLPurifier/Lexer.php +++ b/tools/htmlpurifier/HTMLPurifier/Lexer.php @@ -48,6 +48,11 @@ class HTMLPurifier_Lexer */ public $tracksLineNumbers = false; + /** + * @type HTMLPurifier_EntityParser + */ + private $_entity_parser; + // -- STATIC ---------------------------------------------------------- /** @@ -96,7 +101,7 @@ class HTMLPurifier_Lexer break; } - if (class_exists('DOMDocument', false) && + if (class_exists('DOMDocument') && method_exists('DOMDocument', 'loadHTML') && !extension_loaded('domxml') ) { @@ -264,20 +269,6 @@ class HTMLPurifier_Lexer ); } - /** - * Special Internet Explorer conditional comments should be removed. - * @param string $string HTML string to process. - * @return string HTML with conditional comments removed. - */ - protected static function removeIEConditional($string) - { - return preg_replace( - '##si', // probably should generalize for all strings - '', - $string - ); - } - /** * Callback function for escapeCDATA() that does the work. * @@ -306,8 +297,8 @@ class HTMLPurifier_Lexer { // normalize newlines to \n if ($config->get('Core.NormalizeNewlines')) { - $html = str_replace("\r\n", "\n", $html); - $html = str_replace("\r", "\n", $html); + $html = str_replace("\r\n", "\n", (string)$html); + $html = str_replace("\r", "\n", (string)$html); } if ($config->get('HTML.Trusted')) { @@ -318,8 +309,6 @@ class HTMLPurifier_Lexer // escape CDATA $html = $this->escapeCDATA($html); - $html = $this->removeIEConditional($html); - // extract body from document if applicable if ($config->get('Core.ConvertDocumentToFragment')) { $e = false; diff --git a/tools/htmlpurifier/HTMLPurifier/Lexer/DOMLex.php b/tools/htmlpurifier/HTMLPurifier/Lexer/DOMLex.php index ca5f25b84..7d579837c 100644 --- a/tools/htmlpurifier/HTMLPurifier/Lexer/DOMLex.php +++ b/tools/htmlpurifier/HTMLPurifier/Lexer/DOMLex.php @@ -72,6 +72,9 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer if ($config->get('Core.AllowParseManyTags') && defined('LIBXML_PARSEHUGE')) { $options |= LIBXML_PARSEHUGE; } + if ($config->get('Core.RemoveBlanks') && defined('LIBXML_NOBLANKS')) { + $options |= LIBXML_NOBLANKS; + } set_error_handler(array($this, 'muteErrorHandler')); // loadHTML() fails on PHP 5.3 when second parameter is given @@ -104,7 +107,6 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer * To iterate is human, to recurse divine - L. Peter Deutsch * @param DOMNode $node DOMNode to be tokenized. * @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens. - * @return HTMLPurifier_Token of node appended to previously passed tokens. */ protected function tokenizeDOM($node, &$tokens, $config) { diff --git a/tools/htmlpurifier/HTMLPurifier/Lexer/PH5P.php b/tools/htmlpurifier/HTMLPurifier/Lexer/PH5P.php index 72476ddf3..1564f283d 100644 --- a/tools/htmlpurifier/HTMLPurifier/Lexer/PH5P.php +++ b/tools/htmlpurifier/HTMLPurifier/Lexer/PH5P.php @@ -4410,7 +4410,7 @@ class HTML5TreeConstructer foreach ($token['attr'] as $attr) { if (!$el->hasAttribute($attr['name'])) { - $el->setAttribute($attr['name'], $attr['value']); + $el->setAttribute($attr['name'], (string)$attr['value']); } } diff --git a/tools/htmlpurifier/HTMLPurifier/Lexer/index.php b/tools/htmlpurifier/HTMLPurifier/Lexer/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Lexer/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/Node/index.php b/tools/htmlpurifier/HTMLPurifier/Node/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Node/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/Printer/ConfigForm.php b/tools/htmlpurifier/HTMLPurifier/Printer/ConfigForm.php index 33ae11397..4c3ce1758 100644 --- a/tools/htmlpurifier/HTMLPurifier/Printer/ConfigForm.php +++ b/tools/htmlpurifier/HTMLPurifier/Printer/ConfigForm.php @@ -32,6 +32,11 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer */ protected $compress = false; + /** + * @var HTMLPurifier_Config + */ + protected $genConfig; + /** * @param string $name Form element name for directives to be stuffed into * @param string $doc_url String documentation URL, will have fragment tagged on diff --git a/tools/htmlpurifier/HTMLPurifier/Printer/index.php b/tools/htmlpurifier/HTMLPurifier/Printer/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Printer/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/PropertyListIterator.php b/tools/htmlpurifier/HTMLPurifier/PropertyListIterator.php index 15b330ea3..f68fc8c30 100644 --- a/tools/htmlpurifier/HTMLPurifier/PropertyListIterator.php +++ b/tools/htmlpurifier/HTMLPurifier/PropertyListIterator.php @@ -29,6 +29,7 @@ class HTMLPurifier_PropertyListIterator extends FilterIterator /** * @return bool */ + #[\ReturnTypeWillChange] public function accept() { $key = $this->getInnerIterator()->key(); diff --git a/tools/htmlpurifier/HTMLPurifier/Strategy/index.php b/tools/htmlpurifier/HTMLPurifier/Strategy/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Strategy/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/StringHash.php b/tools/htmlpurifier/HTMLPurifier/StringHash.php index c07370197..c41ae3a76 100644 --- a/tools/htmlpurifier/HTMLPurifier/StringHash.php +++ b/tools/htmlpurifier/HTMLPurifier/StringHash.php @@ -20,6 +20,7 @@ class HTMLPurifier_StringHash extends ArrayObject * @param mixed $index * @return mixed */ + #[\ReturnTypeWillChange] public function offsetGet($index) { $this->accessed[$index] = true; diff --git a/tools/htmlpurifier/HTMLPurifier/TagTransform/index.php b/tools/htmlpurifier/HTMLPurifier/TagTransform/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/TagTransform/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/Token/Tag.php b/tools/htmlpurifier/HTMLPurifier/Token/Tag.php index d643fa64e..dcf365589 100644 --- a/tools/htmlpurifier/HTMLPurifier/Token/Tag.php +++ b/tools/htmlpurifier/HTMLPurifier/Token/Tag.php @@ -44,7 +44,7 @@ abstract class HTMLPurifier_Token_Tag extends HTMLPurifier_Token $this->name = ctype_lower($name) ? $name : strtolower($name); foreach ($attr as $key => $value) { // normalization only necessary when key is not lowercase - if (!ctype_lower($key)) { + if (!ctype_lower((string)$key)) { $new_key = strtolower($key); if (!isset($attr[$new_key])) { $attr[$new_key] = $attr[$key]; diff --git a/tools/htmlpurifier/HTMLPurifier/Token/index.php b/tools/htmlpurifier/HTMLPurifier/Token/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Token/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/URIFilter/HostBlacklist.php b/tools/htmlpurifier/HTMLPurifier/URIFilter/HostBlacklist.php index a6645c17e..32197c0e6 100644 --- a/tools/htmlpurifier/HTMLPurifier/URIFilter/HostBlacklist.php +++ b/tools/htmlpurifier/HTMLPurifier/URIFilter/HostBlacklist.php @@ -35,7 +35,7 @@ class HTMLPurifier_URIFilter_HostBlacklist extends HTMLPurifier_URIFilter public function filter(&$uri, $config, $context) { foreach ($this->blacklist as $blacklisted_host_fragment) { - if (strpos($uri->host, $blacklisted_host_fragment) !== false) { + if ($uri->host !== null && strpos($uri->host, $blacklisted_host_fragment) !== false) { return false; } } diff --git a/tools/htmlpurifier/HTMLPurifier/URIFilter/Munge.php b/tools/htmlpurifier/HTMLPurifier/URIFilter/Munge.php index 6e03315a1..e1393deb7 100644 --- a/tools/htmlpurifier/HTMLPurifier/URIFilter/Munge.php +++ b/tools/htmlpurifier/HTMLPurifier/URIFilter/Munge.php @@ -100,11 +100,11 @@ class HTMLPurifier_URIFilter_Munge extends HTMLPurifier_URIFilter $string = $uri->toString(); // always available $this->replace['%s'] = $string; - $this->replace['%r'] = $context->get('EmbeddedURI', true); - $token = $context->get('CurrentToken', true); - $this->replace['%n'] = $token ? $token->name : null; - $this->replace['%m'] = $context->get('CurrentAttr', true); - $this->replace['%p'] = $context->get('CurrentCSSProperty', true); + $this->replace['%r'] = $context->get('EmbeddedURI', true) ?: ''; + $token = $context->get('CurrentToken', true) ?: ''; + $this->replace['%n'] = $token ? $token->name : ''; + $this->replace['%m'] = $context->get('CurrentAttr', true) ?: ''; + $this->replace['%p'] = $context->get('CurrentCSSProperty', true) ?: ''; // not always available if ($this->secretKey) { $this->replace['%t'] = hash_hmac("sha256", $string, $this->secretKey); diff --git a/tools/htmlpurifier/HTMLPurifier/URIFilter/index.php b/tools/htmlpurifier/HTMLPurifier/URIFilter/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/URIFilter/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/URIScheme/index.php b/tools/htmlpurifier/HTMLPurifier/URIScheme/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/URIScheme/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/URIScheme/tel.php b/tools/htmlpurifier/HTMLPurifier/URIScheme/tel.php index 8cd193352..dfad8efcf 100644 --- a/tools/htmlpurifier/HTMLPurifier/URIScheme/tel.php +++ b/tools/htmlpurifier/HTMLPurifier/URIScheme/tel.php @@ -33,11 +33,11 @@ class HTMLPurifier_URIScheme_tel extends HTMLPurifier_URIScheme $uri->host = null; $uri->port = null; - // Delete all non-numeric characters, non-x characters + // Delete all non-numeric characters, commas, and non-x characters // from phone number, EXCEPT for a leading plus sign. - $uri->path = preg_replace('/(?!^\+)[^\dx]/', '', + $uri->path = preg_replace('/(?!^\+)[^\dx,]/', '', // Normalize e(x)tension to lower-case - str_replace('X', 'x', $uri->path)); + str_replace('X', 'x', rawurldecode($uri->path))); return true; } diff --git a/tools/htmlpurifier/HTMLPurifier/UnitConverter.php b/tools/htmlpurifier/HTMLPurifier/UnitConverter.php index 166f3bf30..b5a1eab5c 100644 --- a/tools/htmlpurifier/HTMLPurifier/UnitConverter.php +++ b/tools/htmlpurifier/HTMLPurifier/UnitConverter.php @@ -261,7 +261,7 @@ class HTMLPurifier_UnitConverter */ private function round($n, $sigfigs) { - $new_log = (int)floor(log(abs($n), 10)); // Number of digits left of decimal - 1 + $new_log = (int)floor(log(abs((float)$n), 10)); // Number of digits left of decimal - 1 $rp = $sigfigs - $new_log - 1; // Number of decimal places needed $neg = $n < 0 ? '-' : ''; // Negative sign if ($this->bcmath) { @@ -276,7 +276,7 @@ class HTMLPurifier_UnitConverter } return $n; } else { - return $this->scale(round($n, $sigfigs - $new_log - 1), $rp + 1); + return $this->scale(round((float)$n, $sigfigs - $new_log - 1), $rp + 1); } } @@ -300,7 +300,7 @@ class HTMLPurifier_UnitConverter // Now we return it, truncating the zero that was rounded off. return substr($precise, 0, -1) . str_repeat('0', -$scale + 1); } - return sprintf('%.' . $scale . 'f', (float)$r); + return number_format((float)$r, $scale, '.', ''); } } diff --git a/tools/htmlpurifier/HTMLPurifier/VarParser/index.php b/tools/htmlpurifier/HTMLPurifier/VarParser/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/VarParser/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/index.php b/tools/htmlpurifier/HTMLPurifier/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/LICENSE b/tools/htmlpurifier/LICENSE deleted file mode 100644 index 8c88a20d4..000000000 --- a/tools/htmlpurifier/LICENSE +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - vim: et sw=4 sts=4 diff --git a/tools/htmlpurifier/index.php b/tools/htmlpurifier/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/http_build_url/http_build_url.php b/tools/http_build_url/http_build_url.php index 388dda3af..49cbeaa6a 100644 --- a/tools/http_build_url/http_build_url.php +++ b/tools/http_build_url/http_build_url.php @@ -5,7 +5,6 @@ * http_build_url()". * * @see http://us2.php.net/manual/en/http.constants.php#http.constants.url - * @see https://github.com/jakeasmith/http_build_url */ if (!defined('HTTP_URL_REPLACE')) { define('HTTP_URL_REPLACE', 1); @@ -93,6 +92,8 @@ if (!function_exists('http_build_url')) { } else { if (isset($parts['path']) && ($flags & HTTP_URL_JOIN_PATH)) { if (isset($url['path']) && substr($parts['path'], 0, 1) !== '/') { + // Workaround for trailing slashes + $url['path'] .= 'a'; $url['path'] = rtrim( str_replace(basename($url['path']), '', $url['path']), '/' @@ -119,6 +120,10 @@ if (!function_exists('http_build_url')) { } } + if (isset($url['path']) && $url['path'] !== '' && substr($url['path'], 0, 1) !== '/') { + $url['path'] = '/' . $url['path']; + } + foreach ($keys as $key) { $strip = 'HTTP_URL_STRIP_' . strtoupper($key); if ($flags & constant($strip)) { @@ -128,11 +133,11 @@ if (!function_exists('http_build_url')) { $parsed_string = ''; - if (isset($url['scheme'])) { + if (!empty($url['scheme'])) { $parsed_string .= $url['scheme'] . '://'; } - if (isset($url['user'])) { + if (!empty($url['user'])) { $parsed_string .= $url['user']; if (isset($url['pass'])) { @@ -142,25 +147,23 @@ if (!function_exists('http_build_url')) { $parsed_string .= '@'; } - if (isset($url['host'])) { + if (!empty($url['host'])) { $parsed_string .= $url['host']; } - if (isset($url['port'])) { + if (!empty($url['port'])) { $parsed_string .= ':' . $url['port']; } if (!empty($url['path'])) { $parsed_string .= $url['path']; - } else { - $parsed_string .= '/'; } - if (isset($url['query'])) { + if (!empty($url['query'])) { $parsed_string .= '?' . $url['query']; } - if (isset($url['fragment'])) { + if (!empty($url['fragment'])) { $parsed_string .= '#' . $url['fragment']; } diff --git a/tools/js_minify/LICENSE b/tools/js_minify/LICENSE index 1362c2a45..c6597d85c 100644 --- a/tools/js_minify/LICENSE +++ b/tools/js_minify/LICENSE @@ -1,21 +1,29 @@ -Copyright (c) 2002 Douglas Crockford (www.crockford.com) +BSD 3-Clause License -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: +Copyright (c) 2009, Robert Hafner +All rights reserved. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: -The Software shall be used for Good, not Evil. +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. -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. +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. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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/tools/js_minify/jsmin.php b/tools/js_minify/jsmin.php index b6879f371..c85dd07f2 100644 --- a/tools/js_minify/jsmin.php +++ b/tools/js_minify/jsmin.php @@ -1,385 +1,721 @@ - * $minifiedJs = JSMin::minify($js); - * + * (c) Robert Hafner * - * This is a modified port of jsmin.c. Improvements: - * - * Does not choke on some regexp literals containing quote characters. E.g. /'/ - * - * Spaces are preserved after some add/sub operators, so they are not mistakenly - * converted to post-inc/dec. E.g. a + ++b -> a+ ++b - * - * Preserves multi-line comments that begin with /*! - * - * PHP 5 or higher is required. - * - * Permission is hereby granted to use this version of the library under the - * same terms as jsmin.c, which has the following license: - * - * -- - * Copyright (c) 2002 Douglas Crockford (www.crockford.com) - * - * 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 shall be used for Good, not Evil. - * - * 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. - * -- - * - * @package JSMin - * @author Ryan Grove (PHP port) - * @author Steve Clay (modifications + cleanup) - * @author Andrea Giammarchi (spaceBeforeRegExp) - * @copyright 2002 Douglas Crockford (jsmin.c) - * @copyright 2008 Ryan Grove (PHP port) - * @license http://opensource.org/licenses/mit-license.php MIT License - * @link http://code.google.com/p/jsmin-php/ + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -class JSMin { - const ORD_LF = 10; - const ORD_SPACE = 32; - const ACTION_KEEP_A = 1; - const ACTION_DELETE_A = 2; - const ACTION_DELETE_A_B = 3; +/** + * JShrink + * + * + * @package JShrink + * @author Robert Hafner + */ - protected $a = "\n"; - protected $b = ''; - protected $input = ''; - protected $inputIndex = 0; - protected $inputLength = 0; - protected $lookAhead = null; - protected $output = ''; - protected $lastByteOut = ''; +namespace JShrink; + +/** + * Minifier + * + * Usage - Minifier::minify($js); + * Usage - Minifier::minify($js, $options); + * Usage - Minifier::minify($js, array('flaggedComments' => false)); + * + * @package JShrink + * @author Robert Hafner + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + */ +class Minifier +{ + /** + * The input javascript to be minified. + * + * @var string + */ + protected $input; /** - * Minify Javascript. + * Length of input javascript. * - * @param string $js Javascript to be minified - * - * @return string + * @var int */ - public static function minify($js) - { - $jsmin = new JSMin($js); - return $jsmin->min(); - } + protected $len = 0; /** - * @param string $input + * The location of the character (in the input string) that is next to be + * processed. + * + * @var int */ - public function __construct($input) - { - $this->input = $input; - } + protected $index = 0; /** - * Perform minification, return result + * The first of the characters currently being looked at. * - * @return string + * @var string */ - public function min() + protected $a = ''; + + /** + * The next character being looked at (after a); + * + * @var string + */ + protected $b = ''; + + /** + * This character is only active when certain look ahead actions take place. + * + * @var string + */ + protected $c; + + /** + * This character is only active when certain look ahead actions take place. + * + * @var string + */ + protected $last_char; + + /** + * This character is only active when certain look ahead actions take place. + * + * @var string + */ + protected $output; + + /** + * Contains the options for the current minification process. + * + * @var array + */ + protected $options; + + /** + * These characters are used to define strings. + */ + protected $stringDelimiters = ['\'' => true, '"' => true, '`' => true]; + + /** + * Contains the default options for minification. This array is merged with + * the one passed in by the user to create the request specific set of + * options (stored in the $options attribute). + * + * @var array + */ + protected static $defaultOptions = ['flaggedComments' => true]; + + + protected static $keywords = ["delete", "do", "for", "in", "instanceof", "return", "typeof", "yield"]; + + protected $max_keyword_len; + + /** + * Contains lock ids which are used to replace certain code patterns and + * prevent them from being minified + * + * @var array + */ + protected $locks = []; + + /** + * Takes a string containing javascript and removes unneeded characters in + * order to shrink the code without altering it's functionality. + * + * @param string $js The raw javascript to be minified + * @param array $options Various runtime options in an associative array + * @throws \Exception + * @return bool|string + */ + public static function minify($js, $options = []) { - if ($this->output !== '') { // min already run - return $this->output; - } - - $mbIntEnc = null; - if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) { - $mbIntEnc = mb_internal_encoding(); - mb_internal_encoding('8bit'); - } - $this->input = str_replace("\r\n", "\n", $this->input); - $this->inputLength = strlen($this->input); - - $this->action(self::ACTION_DELETE_A_B); - - while ($this->a !== null) { - // determine next command - $command = self::ACTION_KEEP_A; // default - if ($this->a === ' ') { - if (($this->lastByteOut === '+' || $this->lastByteOut === '-') - && ($this->b === $this->lastByteOut)) { - // Don't delete this space. If we do, the addition/subtraction - // could be parsed as a post-increment - } elseif (! $this->isAlphaNum($this->b)) { - $command = self::ACTION_DELETE_A; - } - } elseif ($this->a === "\n") { - if ($this->b === ' ') { - $command = self::ACTION_DELETE_A_B; - // in case of mbstring.func_overload & 2, must check for null b, - // otherwise mb_strpos will give WARNING - } elseif ($this->b === null - || (false === strpos('{[(+-', $this->b) - && ! $this->isAlphaNum($this->b))) { - $command = self::ACTION_DELETE_A; - } - } elseif (! $this->isAlphaNum($this->a)) { - if ($this->b === ' ' - || ($this->b === "\n" - && (false === strpos('}])+-"\'', $this->a)))) { - $command = self::ACTION_DELETE_A_B; - } + try { + $jshrink = new Minifier(); + $js = $jshrink->lock($js); + $js = ltrim($jshrink->minifyToString($js, $options)); + $js = $jshrink->unlock($js); + unset($jshrink); + return $js; + } catch (\Exception $e) { + if (isset($jshrink)) { + // Since the breakdownScript function probably wasn't finished + // we clean it out before discarding it. + $jshrink->clean(); + unset($jshrink); } - $this->action($command); + throw $e; } - $this->output = trim($this->output); + } - if ($mbIntEnc !== null) { - mb_internal_encoding($mbIntEnc); - } + /** + * Processes a javascript string and outputs only the required characters, + * stripping out all unneeded characters. + * + * @param string $js The raw javascript to be minified + * @param array $options Various runtime options in an associative array + */ + protected function minifyToString($js, $options) + { + $this->initialize($js, $options); + $this->loop(); + $this->clean(); return $this->output; } /** - * ACTION_KEEP_A = Output A. Copy B to A. Get the next B. - * ACTION_DELETE_A = Copy B to A. Get the next B. - * ACTION_DELETE_A_B = Get the next B. + * Initializes internal variables, normalizes new lines, * - * @param int $command - * @throws JSMin_UnterminatedRegExpException|JSMin_UnterminatedStringException + * @param string $js The raw javascript to be minified + * @param array $options Various runtime options in an associative array */ - protected function action($command) + protected function initialize($js, $options) { - if ($command === self::ACTION_DELETE_A_B - && $this->b === ' ' - && ($this->a === '+' || $this->a === '-')) { - // Note: we're at an addition/substraction operator; the inputIndex - // will certainly be a valid index - if ($this->input[$this->inputIndex] === $this->a) { - // This is "+ +" or "- -". Don't delete the space. - $command = self::ACTION_KEEP_A; - } - } - switch ($command) { - case self::ACTION_KEEP_A: - $this->output .= $this->a; - $this->lastByteOut = $this->a; - - // fallthrough - case self::ACTION_DELETE_A: - $this->a = $this->b; - if ($this->a === "'" || $this->a === '"') { // string literal - $str = $this->a; // in case needed for exception - while (true) { - $this->output .= $this->a; - $this->lastByteOut = $this->a; - - $this->a = $this->get(); - if ($this->a === $this->b) { // end quote + $this->options = array_merge(static::$defaultOptions, $options); + $this->input = $js; + + // We add a newline to the end of the script to make it easier to deal + // with comments at the bottom of the script- this prevents the unclosed + // comment error that can otherwise occur. + $this->input .= PHP_EOL; + + // save input length to skip calculation every time + $this->len = strlen($this->input); + + // Populate "a" with a new line, "b" with the first character, before + // entering the loop + $this->a = "\n"; + $this->b = "\n"; + $this->last_char = "\n"; + $this->output = ""; + + $this->max_keyword_len = max(array_map('strlen', static::$keywords)); + } + + /** + * Characters that can't stand alone preserve the newline. + * + * @var array + */ + protected $noNewLineCharacters = [ + '(' => true, + '-' => true, + '+' => true, + '[' => true, + '#' => true, + '@' => true]; + + + protected function echo($char) { + $this->output .= $char; + $this->last_char = $char[-1]; + } + + + /** + * The primary action occurs here. This function loops through the input string, + * outputting anything that's relevant and discarding anything that is not. + */ + protected function loop() + { + while ($this->a !== false && !is_null($this->a) && $this->a !== '') { + switch ($this->a) { + // new lines + case "\r": + case "\n": + // if the next line is something that can't stand alone preserve the newline + if ($this->b !== false && isset($this->noNewLineCharacters[$this->b])) { + $this->echo($this->a); + $this->saveString(); + break; + } + + // if B is a space we skip the rest of the switch block and go down to the + // string/regex check below, resetting $this->b with getReal + if ($this->b === ' ') { + break; + } + + // otherwise we treat the newline like a space + + // no break + case ' ': + if (static::isAlphaNumeric($this->b)) { + $this->echo($this->a); + } + + $this->saveString(); + break; + + default: + switch ($this->b) { + case "\r": + case "\n": + if (strpos('}])+-"\'', $this->a) !== false) { + $this->echo($this->a); + $this->saveString(); + break; + } else { + if (static::isAlphaNumeric($this->a)) { + $this->echo($this->a); + $this->saveString(); + } + } + break; + + case ' ': + if (!static::isAlphaNumeric($this->a)) { + break; + } + + // no break + default: + // check for some regex that breaks stuff + if ($this->a === '/' && ($this->b === '\'' || $this->b === '"')) { + $this->saveRegex(); + continue 3; + } + + $this->echo($this->a); + $this->saveString(); break; - } - if (ord($this->a) <= self::ORD_LF) { - throw new JSMin_UnterminatedStringException( - "JSMin: Unterminated String at byte " - . $this->inputIndex . ": {$str}"); - } - $str .= $this->a; - if ($this->a === '\\') { - $this->output .= $this->a; - $this->lastByteOut = $this->a; - - $this->a = $this->get(); - $str .= $this->a; - } } + } + + // do reg check of doom + $this->b = $this->getReal(); + + if ($this->b == '/') { + $valid_tokens = "(,=:[!&|?\n"; + + # Find last "real" token, excluding spaces. + $last_token = $this->a; + if ($last_token == " ") { + $last_token = $this->last_char; } - // fallthrough - case self::ACTION_DELETE_A_B: - $this->b = $this->next(); - if ($this->b === '/' && $this->isRegexpLiteral()) { // RegExp literal - $this->output .= $this->a . $this->b; - $pattern = '/'; // in case needed for exception - while (true) { - $this->a = $this->get(); - $pattern .= $this->a; - if ($this->a === '/') { // end pattern - break; // while (true) - } elseif ($this->a === '\\') { - $this->output .= $this->a; - $this->a = $this->get(); - $pattern .= $this->a; - } elseif (ord($this->a) <= self::ORD_LF) { - throw new JSMin_UnterminatedRegExpException( - "JSMin: Unterminated RegExp at byte " - . $this->inputIndex .": {$pattern}"); - } - $this->output .= $this->a; - $this->lastByteOut = $this->a; - } - $this->b = $this->next(); + + if (strpos($valid_tokens, $last_token) !== false) { + // Regex can appear unquoted after these symbols + $this->saveRegex(); + } else if ($this->endsInKeyword()) { + // This block checks for the "return" token before the slash. + $this->saveRegex(); } - // end case ACTION_DELETE_A_B + } + + // if (($this->b == '/' && strpos('(,=:[!&|?', $this->a) !== false)) { + // $this->saveRegex(); + // } } } /** + * Resets attributes that do not need to be stored between requests so that + * the next request is ready to go. Another reason for this is to make sure + * the variables are cleared and are not taking up memory. + */ + protected function clean() + { + unset($this->input); + $this->len = 0; + $this->index = 0; + $this->a = $this->b = ''; + unset($this->c); + unset($this->options); + } + + /** + * Returns the next string for processing based off of the current index. + * + * @return string + */ + protected function getChar() + { + // Check to see if we had anything in the look ahead buffer and use that. + if (isset($this->c)) { + $char = $this->c; + unset($this->c); + } else { + // Otherwise we start pulling from the input. + $char = $this->index < $this->len ? $this->input[$this->index] : false; + + // If the next character doesn't exist return false. + if (isset($char) && $char === false) { + return false; + } + + // Otherwise increment the pointer and use this char. + $this->index++; + } + + # Convert all line endings to unix standard. + # `\r\n` converts to `\n\n` and is minified. + if ($char == "\r") { + $char = "\n"; + } + + // Normalize all whitespace except for the newline character into a + // standard space. + if ($char !== "\n" && $char < "\x20") { + return ' '; + } + + return $char; + } + + /** + * This function returns the next character without moving the index forward. + * + * + * @return string The next character + * @throws \RuntimeException + */ + protected function peek() + { + if ($this->index >= $this->len) { + return false; + } + + $char = $this->input[$this->index]; + # Convert all line endings to unix standard. + # `\r\n` converts to `\n\n` and is minified. + if ($char == "\r") { + $char = "\n"; + } + + // Normalize all whitespace except for the newline character into a + // standard space. + if ($char !== "\n" && $char < "\x20") { + return ' '; + } + + # Return the next character but don't push the index. + return $char; + } + + /** + * This function gets the next "real" character. It is essentially a wrapper + * around the getChar function that skips comments. This has significant + * performance benefits as the skipping is done using native functions (ie, + * c code) rather than in script php. + * + * + * @return string Next 'real' character to be processed. + * @throws \RuntimeException + */ + protected function getReal() + { + $startIndex = $this->index; + $char = $this->getChar(); + + // Check to see if we're potentially in a comment + if ($char !== '/') { + return $char; + } + + $this->c = $this->getChar(); + + if ($this->c === '/') { + $this->processOneLineComments($startIndex); + + return $this->getReal(); + } elseif ($this->c === '*') { + $this->processMultiLineComments($startIndex); + + return $this->getReal(); + } + + return $char; + } + + /** + * Removed one line comments, with the exception of some very specific types of + * conditional comments. + * + * @param int $startIndex The index point where "getReal" function started + * @return void + */ + protected function processOneLineComments($startIndex) + { + $thirdCommentString = $this->index < $this->len ? $this->input[$this->index] : false; + + // kill rest of line + $this->getNext("\n"); + + unset($this->c); + + if ($thirdCommentString == '@') { + $endPoint = $this->index - $startIndex; + $this->c = "\n" . substr($this->input, $startIndex, $endPoint); + } + } + + /** + * Skips multiline comments where appropriate, and includes them where needed. + * Conditional comments and "license" style blocks are preserved. + * + * @param int $startIndex The index point where "getReal" function started + * @return void + * @throws \RuntimeException Unclosed comments will throw an error + */ + protected function processMultiLineComments($startIndex) + { + $this->getChar(); // current C + $thirdCommentString = $this->getChar(); + + // Detect a completely empty comment, ie `/**/` + if ($thirdCommentString == "*") { + $peekChar = $this->peek(); + if ($peekChar == "/") { + $this->index++; + return; + } + } + + // kill everything up to the next */ if it's there + if ($this->getNext('*/')) { + $this->getChar(); // get * + $this->getChar(); // get / + $char = $this->getChar(); // get next real character + + // Now we reinsert conditional comments and YUI-style licensing comments + if (($this->options['flaggedComments'] && $thirdCommentString === '!') + || ($thirdCommentString === '@')) { + + // If conditional comments or flagged comments are not the first thing in the script + // we need to echo a and fill it with a space before moving on. + if ($startIndex > 0) { + $this->echo($this->a); + $this->a = " "; + + // If the comment started on a new line we let it stay on the new line + if ($this->input[($startIndex - 1)] === "\n") { + $this->echo("\n"); + } + } + + $endPoint = ($this->index - 1) - $startIndex; + $this->echo(substr($this->input, $startIndex, $endPoint)); + + $this->c = $char; + + return; + } + } else { + $char = false; + } + + if ($char === false) { + throw new \RuntimeException('Unclosed multiline comment at position: ' . ($this->index - 2)); + } + + // if we're here c is part of the comment and therefore tossed + $this->c = $char; + } + + /** + * Pushes the index ahead to the next instance of the supplied string. If it + * is found the first character of the string is returned and the index is set + * to it's position. + * + * @param string $string + * @return string|false Returns the first character of the string or false. + */ + protected function getNext($string) + { + // Find the next occurrence of "string" after the current position. + $pos = strpos($this->input, $string, $this->index); + + // If it's not there return false. + if ($pos === false) { + return false; + } + + // Adjust position of index to jump ahead to the asked for string + $this->index = $pos; + + // Return the first character of that string. + return $this->index < $this->len ? $this->input[$this->index] : false; + } + + /** + * When a javascript string is detected this function crawls for the end of + * it and saves the whole string. + * + * @throws \RuntimeException Unclosed strings will throw an error + */ + protected function saveString() + { + $startpos = $this->index; + + // saveString is always called after a gets cleared, so we push b into + // that spot. + $this->a = $this->b; + + // If this isn't a string we don't need to do anything. + if (!isset($this->stringDelimiters[$this->a])) { + return; + } + + // String type is the quote used, " or ' + $stringType = $this->a; + + // Echo out that starting quote + $this->echo($this->a); + + // Loop until the string is done + // Grab the very next character and load it into a + while (($this->a = $this->getChar()) !== false) { + switch ($this->a) { + + // If the string opener (single or double quote) is used + // output it and break out of the while loop- + // The string is finished! + case $stringType: + break 2; + + // New lines in strings without line delimiters are bad- actual + // new lines will be represented by the string \n and not the actual + // character, so those will be treated just fine using the switch + // block below. + case "\n": + if ($stringType === '`') { + $this->echo($this->a); + } else { + throw new \RuntimeException('Unclosed string at position: ' . $startpos); + } + break; + + // Escaped characters get picked up here. If it's an escaped new line it's not really needed + case '\\': + + // a is a slash. We want to keep it, and the next character, + // unless it's a new line. New lines as actual strings will be + // preserved, but escaped new lines should be reduced. + $this->b = $this->getChar(); + + // If b is a new line we discard a and b and restart the loop. + if ($this->b === "\n") { + break; + } + + // echo out the escaped character and restart the loop. + $this->echo($this->a . $this->b); + break; + + + // Since we're not dealing with any special cases we simply + // output the character and continue our loop. + default: + $this->echo($this->a); + } + } + } + + /** + * When a regular expression is detected this function crawls for the end of + * it and saves the whole regex. + * + * @throws \RuntimeException Unclosed regex will throw an error + */ + protected function saveRegex() + { + if ($this->a != " ") { + $this->echo($this->a); + } + + $this->echo($this->b); + + while (($this->a = $this->getChar()) !== false) { + if ($this->a === '/') { + break; + } + + if ($this->a === '\\') { + $this->echo($this->a); + $this->a = $this->getChar(); + } + + if ($this->a === "\n") { + throw new \RuntimeException('Unclosed regex pattern at position: ' . $this->index); + } + + $this->echo($this->a); + } + $this->b = $this->getReal(); + } + + /** + * Checks to see if a character is alphanumeric. + * + * @param string $char Just one character * @return bool */ - protected function isRegexpLiteral() + protected static function isAlphaNumeric($char) { - if (false !== strpos("\n{;(,=:[!&|?", $this->a)) { // we aren't dividing - return true; - } - if (' ' === $this->a) { - $length = strlen($this->output); - if ($length < 2) { // weird edge case + return preg_match('/^[\w\$\pL]$/', $char) === 1 || $char == '/'; + } + + protected function endsInKeyword() { + + # When this function is called A is not yet assigned to output. + # Regular expression only needs to check final part of output for keyword. + $testOutput = substr($this->output . $this->a, -1 * ($this->max_keyword_len + 10)); + + foreach(static::$keywords as $keyword) { + if (preg_match('/[^\w]'.$keyword.'[ ]?$/i', $testOutput) === 1) { return true; } - // you can't divide a keyword - if (preg_match('/(?:case|else|in|return|typeof)$/', $this->output, $m)) { - if ($this->output === $m[0]) { // odd but could happen - return true; - } - // make sure it's a keyword, not end of an identifier - $charBeforeKeyword = substr($this->output, $length - strlen($m[0]) - 1, 1); - if (! $this->isAlphaNum($charBeforeKeyword)) { - return true; - } - } } return false; } - /** - * Get next char. Convert ctrl char to space. - * - * @return string - */ - protected function get() - { - $c = $this->lookAhead; - $this->lookAhead = null; - if ($c === null) { - if ($this->inputIndex < $this->inputLength) { - $c = $this->input[$this->inputIndex]; - $this->inputIndex += 1; - } else { - return null; - } - } - if ($c === "\r" || $c === "\n") { - return "\n"; - } - if (ord($c) < self::ORD_SPACE) { // control char - return ' '; - } - return $c; - } + /** - * Get next char. If is ctrl character, translate to a space or newline. - * - * @return string - */ - protected function peek() - { - $this->lookAhead = $this->get(); - return $this->lookAhead; - } - - /** - * Is $c a letter, digit, underscore, dollar sign, escape, or non-ASCII? - * - * @param string $c + * Replace patterns in the given string and store the replacement * + * @param string $js The string to lock * @return bool */ - protected function isAlphaNum($c) + protected function lock($js) { - return (preg_match('/^[0-9a-zA-Z_\\$\\\\]$/', $c) || ord($c) > 126); - } + /* lock things like "asd" + ++x; */ + $lock = '"LOCK---' . crc32(time()) . '"'; - /** - * @return string - */ - protected function singleLineComment() - { - $comment = ''; - while (true) { - $get = $this->get(); - $comment .= $get; - if (ord($get) <= self::ORD_LF) { // EOL reached - // if IE conditional comment - if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) { - return "/{$comment}"; - } - return $get; - } + $matches = []; + preg_match('/([+-])(\s+)([+-])/S', $js, $matches); + if (empty($matches)) { + return $js; } + + $this->locks[$lock] = $matches[2]; + + $js = preg_replace('/([+-])\s+([+-])/S', "$1{$lock}$2", $js); + /* -- */ + + return $js; } /** - * @return string - * @throws JSMin_UnterminatedCommentException - */ - protected function multipleLineComment() - { - $this->get(); - $comment = ''; - while (true) { - $get = $this->get(); - if ($get === '*') { - if ($this->peek() === '/') { // end of comment reached - $this->get(); - // if comment preserved by YUI Compressor - if (0 === strpos($comment, '!')) { - return "\n/*!" . substr($comment, 1) . "*/\n"; - } - // if IE conditional comment - if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) { - return "/*{$comment}*/"; - } - return ' '; - } - } elseif ($get === null) { - throw new JSMin_UnterminatedCommentException( - "JSMin: Unterminated comment at byte " - . $this->inputIndex . ": /*{$comment}"); - } - $comment .= $get; - } - } - - /** - * Get the next character, skipping over comments. - * Some comments may be preserved. + * Replace "locks" with the original characters * - * @return string + * @param string $js The string to unlock + * @return bool */ - protected function next() + protected function unlock($js) { - $get = $this->get(); - if ($get !== '/') { - return $get; + if (empty($this->locks)) { + return $js; } - switch ($this->peek()) { - case '/': return $this->singleLineComment(); - case '*': return $this->multipleLineComment(); - default: return $get; - } - } -} -class JSMin_UnterminatedStringException extends Exception {} -class JSMin_UnterminatedCommentException extends Exception {} -class JSMin_UnterminatedRegExpException extends Exception {} + foreach ($this->locks as $lock => $replacement) { + $js = str_replace($lock, $replacement, $js); + } + + return $js; + } +} \ No newline at end of file diff --git a/tools/mailer/autoload.php b/tools/mailer/autoload.php new file mode 100644 index 000000000..bec346a85 --- /dev/null +++ b/tools/mailer/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @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', 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 string[] $classMap Class to filename map + * @psalm-param array $classMap + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $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 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) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * 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 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) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * 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 string[]|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $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 string[]|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * 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') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * 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 true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + 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 + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + * @private + */ +function includeFile($file) +{ + include $file; +} diff --git a/tools/mailer/composer/InstalledVersions.php b/tools/mailer/composer/InstalledVersions.php new file mode 100644 index 000000000..d50e0c9fc --- /dev/null +++ b/tools/mailer/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/tools/mailer/composer/LICENSE b/tools/mailer/composer/LICENSE new file mode 100644 index 000000000..f27399a04 --- /dev/null +++ b/tools/mailer/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +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/tools/mailer/composer/autoload_classmap.php b/tools/mailer/composer/autoload_classmap.php new file mode 100644 index 000000000..fd407a3a1 --- /dev/null +++ b/tools/mailer/composer/autoload_classmap.php @@ -0,0 +1,11 @@ + $vendorDir . '/composer/InstalledVersions.php', + 'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', +); diff --git a/tools/mailer/composer/autoload_files.php b/tools/mailer/composer/autoload_files.php new file mode 100644 index 000000000..9c8e6cfe3 --- /dev/null +++ b/tools/mailer/composer/autoload_files.php @@ -0,0 +1,13 @@ + $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', + 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', + '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', +); diff --git a/tools/mailer/composer/autoload_namespaces.php b/tools/mailer/composer/autoload_namespaces.php new file mode 100644 index 000000000..b7fc0125d --- /dev/null +++ b/tools/mailer/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/symfony/polyfill-mbstring'), + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'), + 'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'), + 'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'), + 'Symfony\\Contracts\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher-contracts'), + 'Symfony\\Component\\Mime\\' => array($vendorDir . '/symfony/mime'), + 'Symfony\\Component\\Mailer\\' => array($vendorDir . '/symfony/mailer'), + 'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log/src'), + 'Psr\\EventDispatcher\\' => array($vendorDir . '/psr/event-dispatcher/src'), + 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), + 'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/src'), + 'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/src'), +); diff --git a/tools/mailer/composer/autoload_real.php b/tools/mailer/composer/autoload_real.php new file mode 100644 index 000000000..59416d97b --- /dev/null +++ b/tools/mailer/composer/autoload_real.php @@ -0,0 +1,80 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInite7be09a88df86ec7472e11aba80f87bc::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + if ($useStaticLoader) { + $includeFiles = Composer\Autoload\ComposerStaticInite7be09a88df86ec7472e11aba80f87bc::$files; + } else { + $includeFiles = require __DIR__ . '/autoload_files.php'; + } + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequiree7be09a88df86ec7472e11aba80f87bc($fileIdentifier, $file); + } + + return $loader; + } +} + +/** + * @param string $fileIdentifier + * @param string $file + * @return void + */ +function composerRequiree7be09a88df86ec7472e11aba80f87bc($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } +} diff --git a/tools/mailer/composer/autoload_static.php b/tools/mailer/composer/autoload_static.php new file mode 100644 index 000000000..ee19c4b40 --- /dev/null +++ b/tools/mailer/composer/autoload_static.php @@ -0,0 +1,113 @@ + __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', + 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', + '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'S' => + array ( + 'Symfony\\Polyfill\\Mbstring\\' => 26, + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33, + 'Symfony\\Polyfill\\Intl\\Idn\\' => 26, + 'Symfony\\Contracts\\Service\\' => 26, + 'Symfony\\Contracts\\EventDispatcher\\' => 34, + 'Symfony\\Component\\Mime\\' => 23, + 'Symfony\\Component\\Mailer\\' => 25, + 'Symfony\\Component\\EventDispatcher\\' => 34, + ), + 'P' => + array ( + 'Psr\\Log\\' => 8, + 'Psr\\EventDispatcher\\' => 20, + 'Psr\\Container\\' => 14, + ), + 'E' => + array ( + 'Egulias\\EmailValidator\\' => 23, + ), + 'D' => + array ( + 'Doctrine\\Common\\Lexer\\' => 22, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Symfony\\Polyfill\\Mbstring\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', + ), + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer', + ), + 'Symfony\\Polyfill\\Intl\\Idn\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn', + ), + 'Symfony\\Contracts\\Service\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/service-contracts', + ), + 'Symfony\\Contracts\\EventDispatcher\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/event-dispatcher-contracts', + ), + 'Symfony\\Component\\Mime\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/mime', + ), + 'Symfony\\Component\\Mailer\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/mailer', + ), + 'Symfony\\Component\\EventDispatcher\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/event-dispatcher', + ), + 'Psr\\Log\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/log/src', + ), + 'Psr\\EventDispatcher\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/event-dispatcher/src', + ), + 'Psr\\Container\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/container/src', + ), + 'Egulias\\EmailValidator\\' => + array ( + 0 => __DIR__ . '/..' . '/egulias/email-validator/src', + ), + 'Doctrine\\Common\\Lexer\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/lexer/src', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInite7be09a88df86ec7472e11aba80f87bc::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInite7be09a88df86ec7472e11aba80f87bc::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInite7be09a88df86ec7472e11aba80f87bc::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/tools/mailer/composer/installed.json b/tools/mailer/composer/installed.json new file mode 100644 index 000000000..665c1ae10 --- /dev/null +++ b/tools/mailer/composer/installed.json @@ -0,0 +1,1059 @@ +{ + "packages": [ + { + "name": "doctrine/lexer", + "version": "3.0.1", + "version_normalized": "3.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^5.21" + }, + "time": "2024-02-05T11:56:58+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/3.0.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "install-path": "../doctrine/lexer" + }, + { + "name": "egulias/email-validator", + "version": "4.0.2", + "version_normalized": "4.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ebaaf5be6c0286928352e054f2d5125608e5405e", + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2.0 || ^3.0", + "php": ">=8.1", + "symfony/polyfill-intl-idn": "^1.26" + }, + "require-dev": { + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "time": "2023-10-06T06:47:41+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/4.0.2" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "install-path": "../egulias/email-validator" + }, + { + "name": "psr/container", + "version": "2.0.2", + "version_normalized": "2.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "time": "2021-11-05T16:47:00+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "install-path": "../psr/container" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "time": "2019-01-08T18:20:26+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "install-path": "../psr/event-dispatcher" + }, + { + "name": "psr/log", + "version": "3.0.2", + "version_normalized": "3.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "time": "2024-09-11T13:17:53+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "install-path": "../psr/log" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.0", + "version_normalized": "3.5.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "time": "2024-04-18T09:32:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "function.php" + ] + }, + "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": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.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/deprecation-contracts" + }, + { + "name": "symfony/event-dispatcher", + "version": "v7.1.6", + "version_normalized": "7.1.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "87254c78dd50721cfd015b62277a8281c5589702" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/87254c78dd50721cfd015b62277a8281c5589702", + "reference": "87254c78dd50721cfd015b62277a8281c5589702", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0" + }, + "time": "2024-09-25T14:20:29+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v7.1.6" + }, + "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/event-dispatcher" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.5.0", + "version_normalized": "3.5.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/8f93aec25d41b72493c6ddff14e916177c9efc50", + "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "time": "2024-04-18T09:32:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "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": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.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/event-dispatcher-contracts" + }, + { + "name": "symfony/mailer", + "version": "v6.4.13", + "version_normalized": "6.4.13.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "c2f7e0d8d7ac8fe25faccf5d8cac462805db2663" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/c2f7e0d8d7ac8fe25faccf5d8cac462805db2663", + "reference": "c2f7e0d8d7ac8fe25faccf5d8cac462805db2663", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3|^4", + "php": ">=8.1", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/mime": "^6.2|^7.0", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<5.4", + "symfony/messenger": "<6.2", + "symfony/mime": "<6.2", + "symfony/twig-bridge": "<6.2.1" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/messenger": "^6.2|^7.0", + "symfony/twig-bridge": "^6.2|^7.0" + }, + "time": "2024-09-25T14:18:03+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps sending emails", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/mailer/tree/v6.4.13" + }, + "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/mailer" + }, + { + "name": "symfony/mime", + "version": "v7.1.6", + "version_normalized": "7.1.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "caa1e521edb2650b8470918dfe51708c237f0598" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/caa1e521edb2650b8470918dfe51708c237f0598", + "reference": "caa1e521edb2650b8470918dfe51708c237f0598", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<6.4", + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3" + }, + "time": "2024-10-25T15:11:02+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v7.1.6" + }, + "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/mime" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.31.0", + "version_normalized": "1.31.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2024-09-09T11:45:10+00:00", + "type": "library", + "extra": { + "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.31.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" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.31.0", + "version_normalized": "1.31.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2024-09-09T11:45:10+00:00", + "type": "library", + "extra": { + "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.31.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" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.31.0", + "version_normalized": "1.31.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "time": "2024-09-09T11:45:10+00:00", + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "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 the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.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-mbstring" + }, + { + "name": "symfony/service-contracts", + "version": "v3.5.0", + "version_normalized": "3.5.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "time": "2024-04-18T09:32:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "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": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.5.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/service-contracts" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/tools/mailer/composer/installed.php b/tools/mailer/composer/installed.php new file mode 100644 index 000000000..424ecaafa --- /dev/null +++ b/tools/mailer/composer/installed.php @@ -0,0 +1,161 @@ + array( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => NULL, + 'name' => '__root__', + 'dev' => true, + ), + 'versions' => array( + '__root__' => array( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => NULL, + 'dev_requirement' => false, + ), + 'doctrine/lexer' => array( + 'pretty_version' => '3.0.1', + 'version' => '3.0.1.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../doctrine/lexer', + 'aliases' => array(), + 'reference' => '31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd', + 'dev_requirement' => false, + ), + 'egulias/email-validator' => array( + 'pretty_version' => '4.0.2', + 'version' => '4.0.2.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../egulias/email-validator', + 'aliases' => array(), + 'reference' => 'ebaaf5be6c0286928352e054f2d5125608e5405e', + 'dev_requirement' => false, + ), + 'psr/container' => array( + 'pretty_version' => '2.0.2', + 'version' => '2.0.2.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/container', + 'aliases' => array(), + 'reference' => 'c71ecc56dfe541dbd90c5360474fbc405f8d5963', + 'dev_requirement' => false, + ), + 'psr/event-dispatcher' => array( + 'pretty_version' => '1.0.0', + 'version' => '1.0.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/event-dispatcher', + 'aliases' => array(), + 'reference' => 'dbefd12671e8a14ec7f180cab83036ed26714bb0', + 'dev_requirement' => false, + ), + 'psr/event-dispatcher-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/log' => array( + 'pretty_version' => '3.0.2', + 'version' => '3.0.2.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/log', + 'aliases' => array(), + 'reference' => 'f16e1d5863e37f8d8c2a01719f5b34baa2b714d3', + 'dev_requirement' => false, + ), + 'symfony/deprecation-contracts' => array( + 'pretty_version' => 'v3.5.0', + 'version' => '3.5.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', + 'aliases' => array(), + 'reference' => '0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1', + 'dev_requirement' => false, + ), + 'symfony/event-dispatcher' => array( + 'pretty_version' => 'v7.1.6', + 'version' => '7.1.6.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/event-dispatcher', + 'aliases' => array(), + 'reference' => '87254c78dd50721cfd015b62277a8281c5589702', + 'dev_requirement' => false, + ), + 'symfony/event-dispatcher-contracts' => array( + 'pretty_version' => 'v3.5.0', + 'version' => '3.5.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/event-dispatcher-contracts', + 'aliases' => array(), + 'reference' => '8f93aec25d41b72493c6ddff14e916177c9efc50', + 'dev_requirement' => false, + ), + 'symfony/event-dispatcher-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '2.0|3.0', + ), + ), + 'symfony/mailer' => array( + 'pretty_version' => 'v6.4.13', + 'version' => '6.4.13.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/mailer', + 'aliases' => array(), + 'reference' => 'c2f7e0d8d7ac8fe25faccf5d8cac462805db2663', + 'dev_requirement' => false, + ), + 'symfony/mime' => array( + 'pretty_version' => 'v7.1.6', + 'version' => '7.1.6.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/mime', + 'aliases' => array(), + 'reference' => 'caa1e521edb2650b8470918dfe51708c237f0598', + 'dev_requirement' => false, + ), + 'symfony/polyfill-intl-idn' => array( + 'pretty_version' => 'v1.31.0', + 'version' => '1.31.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn', + 'aliases' => array(), + 'reference' => 'c36586dcf89a12315939e00ec9b4474adcb1d773', + 'dev_requirement' => false, + ), + 'symfony/polyfill-intl-normalizer' => array( + 'pretty_version' => 'v1.31.0', + 'version' => '1.31.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', + 'aliases' => array(), + 'reference' => '3833d7255cc303546435cb650316bff708a1c75c', + 'dev_requirement' => false, + ), + 'symfony/polyfill-mbstring' => array( + 'pretty_version' => 'v1.31.0', + 'version' => '1.31.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', + 'aliases' => array(), + 'reference' => '85181ba99b2345b0ef10ce42ecac37612d9fd341', + 'dev_requirement' => false, + ), + 'symfony/service-contracts' => array( + 'pretty_version' => 'v3.5.0', + 'version' => '3.5.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/service-contracts', + 'aliases' => array(), + 'reference' => 'bd1d9e59a81d8fa4acdcea3f617c581f7475a80f', + 'dev_requirement' => false, + ), + ), +); diff --git a/tools/mailer/composer/platform_check.php b/tools/mailer/composer/platform_check.php new file mode 100644 index 000000000..adfb472fb --- /dev/null +++ b/tools/mailer/composer/platform_check.php @@ -0,0 +1,26 @@ += 80000)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 8.0.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/tools/mailer/doctrine/lexer/LICENSE b/tools/mailer/doctrine/lexer/LICENSE new file mode 100644 index 000000000..e8fdec4af --- /dev/null +++ b/tools/mailer/doctrine/lexer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006-2018 Doctrine Project + +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/tools/mailer/doctrine/lexer/README.md b/tools/mailer/doctrine/lexer/README.md new file mode 100644 index 000000000..784f2a271 --- /dev/null +++ b/tools/mailer/doctrine/lexer/README.md @@ -0,0 +1,9 @@ +# Doctrine Lexer + +[![Build Status](https://github.com/doctrine/lexer/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/lexer/actions) + +Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers. + +This lexer is used in Doctrine Annotations and in Doctrine ORM (DQL). + +https://www.doctrine-project.org/projects/lexer.html diff --git a/tools/mailer/doctrine/lexer/UPGRADE.md b/tools/mailer/doctrine/lexer/UPGRADE.md new file mode 100644 index 000000000..1933fcb2e --- /dev/null +++ b/tools/mailer/doctrine/lexer/UPGRADE.md @@ -0,0 +1,22 @@ +Note about upgrading: Doctrine uses static and runtime mechanisms to raise +awareness about deprecated code. + +- Use of `@deprecated` docblock that is detected by IDEs (like PHPStorm) or + Static Analysis tools (like Psalm, phpstan) +- Use of our low-overhead runtime deprecation API, details: + https://github.com/doctrine/deprecations/ + +# Upgrade to 3.0.0 + +`Doctrine\Common\Lexer\Token` no longer implements `ArrayAccess`. +Parameter type declarations have been added to +`Doctrine\Common\Lexer\AbstractLexer` and `Doctrine\Common\Lexer\Token`. +You should add both parameter type declarations and return type declarations to +your lexers, based on the `@return` phpdoc. + +# Upgrade to 2.0.0 + +`AbstractLexer::glimpse()` and `AbstractLexer::peek()` now return +instances of `Doctrine\Common\Lexer\Token`, which is an array-like class +Using it as an array is deprecated in favor of using properties of that class. +Using `count()` on it is deprecated with no replacement. diff --git a/tools/mailer/doctrine/lexer/composer.json b/tools/mailer/doctrine/lexer/composer.json new file mode 100644 index 000000000..995dafa0d --- /dev/null +++ b/tools/mailer/doctrine/lexer/composer.json @@ -0,0 +1,55 @@ +{ + "name": "doctrine/lexer", + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "license": "MIT", + "type": "library", + "keywords": [ + "php", + "parser", + "lexer", + "annotations", + "docblock" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^5.21" + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Doctrine\\Tests\\Common\\Lexer\\": "tests" + } + }, + "config": { + "allow-plugins": { + "composer/package-versions-deprecated": true, + "dealerdirect/phpcodesniffer-composer-installer": true + }, + "sort-packages": true + } +} diff --git a/tools/mailer/doctrine/lexer/src/AbstractLexer.php b/tools/mailer/doctrine/lexer/src/AbstractLexer.php new file mode 100644 index 000000000..2436885e4 --- /dev/null +++ b/tools/mailer/doctrine/lexer/src/AbstractLexer.php @@ -0,0 +1,328 @@ +> + */ + private array $tokens = []; + + /** + * Current lexer position in input string. + */ + private int $position = 0; + + /** + * Current peek of current lexer position. + */ + private int $peek = 0; + + /** + * The next token in the input. + * + * @var Token|null + */ + public Token|null $lookahead; + + /** + * The last matched/seen token. + * + * @var Token|null + */ + public Token|null $token; + + /** + * Composed regex for input parsing. + * + * @var non-empty-string|null + */ + private string|null $regex = null; + + /** + * Sets the input data to be tokenized. + * + * The Lexer is immediately reset and the new input tokenized. + * Any unprocessed tokens from any previous input are lost. + * + * @param string $input The input to be tokenized. + * + * @return void + */ + public function setInput(string $input) + { + $this->input = $input; + $this->tokens = []; + + $this->reset(); + $this->scan($input); + } + + /** + * Resets the lexer. + * + * @return void + */ + public function reset() + { + $this->lookahead = null; + $this->token = null; + $this->peek = 0; + $this->position = 0; + } + + /** + * Resets the peek pointer to 0. + * + * @return void + */ + public function resetPeek() + { + $this->peek = 0; + } + + /** + * Resets the lexer position on the input to the given position. + * + * @param int $position Position to place the lexical scanner. + * + * @return void + */ + public function resetPosition(int $position = 0) + { + $this->position = $position; + } + + /** + * Retrieve the original lexer's input until a given position. + * + * @return string + */ + public function getInputUntilPosition(int $position) + { + return substr($this->input, 0, $position); + } + + /** + * Checks whether a given token matches the current lookahead. + * + * @param T $type + * + * @return bool + * + * @psalm-assert-if-true !=null $this->lookahead + */ + public function isNextToken(int|string|UnitEnum $type) + { + return $this->lookahead !== null && $this->lookahead->isA($type); + } + + /** + * Checks whether any of the given tokens matches the current lookahead. + * + * @param list $types + * + * @return bool + * + * @psalm-assert-if-true !=null $this->lookahead + */ + public function isNextTokenAny(array $types) + { + return $this->lookahead !== null && $this->lookahead->isA(...$types); + } + + /** + * Moves to the next token in the input string. + * + * @return bool + * + * @psalm-assert-if-true !null $this->lookahead + */ + public function moveNext() + { + $this->peek = 0; + $this->token = $this->lookahead; + $this->lookahead = isset($this->tokens[$this->position]) + ? $this->tokens[$this->position++] : null; + + return $this->lookahead !== null; + } + + /** + * Tells the lexer to skip input tokens until it sees a token with the given value. + * + * @param T $type The token type to skip until. + * + * @return void + */ + public function skipUntil(int|string|UnitEnum $type) + { + while ($this->lookahead !== null && ! $this->lookahead->isA($type)) { + $this->moveNext(); + } + } + + /** + * Checks if given value is identical to the given token. + * + * @return bool + */ + public function isA(string $value, int|string|UnitEnum $token) + { + return $this->getType($value) === $token; + } + + /** + * Moves the lookahead token forward. + * + * @return Token|null The next token or NULL if there are no more tokens ahead. + */ + public function peek() + { + if (isset($this->tokens[$this->position + $this->peek])) { + return $this->tokens[$this->position + $this->peek++]; + } + + return null; + } + + /** + * Peeks at the next token, returns it and immediately resets the peek. + * + * @return Token|null The next token or NULL if there are no more tokens ahead. + */ + public function glimpse() + { + $peek = $this->peek(); + $this->peek = 0; + + return $peek; + } + + /** + * Scans the input string for tokens. + * + * @param string $input A query string. + * + * @return void + */ + protected function scan(string $input) + { + if (! isset($this->regex)) { + $this->regex = sprintf( + '/(%s)|%s/%s', + implode(')|(', $this->getCatchablePatterns()), + implode('|', $this->getNonCatchablePatterns()), + $this->getModifiers(), + ); + } + + $flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE; + $matches = preg_split($this->regex, $input, -1, $flags); + + if ($matches === false) { + // Work around https://bugs.php.net/78122 + $matches = [[$input, 0]]; + } + + foreach ($matches as $match) { + // Must remain before 'value' assignment since it can change content + $firstMatch = $match[0]; + $type = $this->getType($firstMatch); + + $this->tokens[] = new Token( + $firstMatch, + $type, + $match[1], + ); + } + } + + /** + * Gets the literal for a given token. + * + * @param T $token + * + * @return int|string + */ + public function getLiteral(int|string|UnitEnum $token) + { + if ($token instanceof UnitEnum) { + return $token::class . '::' . $token->name; + } + + $className = static::class; + + $reflClass = new ReflectionClass($className); + $constants = $reflClass->getConstants(); + + foreach ($constants as $name => $value) { + if ($value === $token) { + return $className . '::' . $name; + } + } + + return $token; + } + + /** + * Regex modifiers + * + * @return string + */ + protected function getModifiers() + { + return 'iu'; + } + + /** + * Lexical catchable patterns. + * + * @return string[] + */ + abstract protected function getCatchablePatterns(); + + /** + * Lexical non-catchable patterns. + * + * @return string[] + */ + abstract protected function getNonCatchablePatterns(); + + /** + * Retrieve token type. Also processes the token value if necessary. + * + * @return T|null + * + * @param-out V $value + */ + abstract protected function getType(string &$value); +} diff --git a/tools/mailer/doctrine/lexer/src/Token.php b/tools/mailer/doctrine/lexer/src/Token.php new file mode 100644 index 000000000..b6df69465 --- /dev/null +++ b/tools/mailer/doctrine/lexer/src/Token.php @@ -0,0 +1,56 @@ +value = $value; + $this->type = $type; + $this->position = $position; + } + + /** @param T ...$types */ + public function isA(...$types): bool + { + return in_array($this->type, $types, true); + } +} diff --git a/tools/mailer/egulias/email-validator/CHANGELOG.md b/tools/mailer/egulias/email-validator/CHANGELOG.md new file mode 100644 index 000000000..39f5a8a05 --- /dev/null +++ b/tools/mailer/egulias/email-validator/CHANGELOG.md @@ -0,0 +1,32 @@ +# EmailValidator Changelog + +## New Features + +* Access to local part and domain part from EmailParser +* Validations outside of the scope of the RFC will be considered "extra" validations, thus opening the door for adding new; will live in their own folder "extra" (as requested in #248, #195, #183). + +## Breaking changes + +* PHP version upgraded to match Symfony's (as of 12/2020). +* DNSCheckValidation now fails for missing MX records. While the RFC argues that the existence of only A records to be valid, starting in v3 they will be considered invalid. +* Emails domain part are now intenteded to be RFC 1035 compliant, rendering previous valid emails (e.g example@examp&) invalid. + +## PHP versions upgrade policy +PHP version upgrade requirement will happen via MINOR (3.x) version upgrades of the library, following the adoption level by major frameworks. + +## Changes +* #235 +* #215 +* #130 +* #258 +* #188 +* #181 +* #217 +* #214 +* #249 +* #236 +* #257 +* #210 + +## Thanks +To contributors, be it with PRs, reporting issues or supporting otherwise. diff --git a/tools/mailer/egulias/email-validator/CONTRIBUTING.md b/tools/mailer/egulias/email-validator/CONTRIBUTING.md new file mode 100644 index 000000000..907bc2c9b --- /dev/null +++ b/tools/mailer/egulias/email-validator/CONTRIBUTING.md @@ -0,0 +1,153 @@ +# Contributing + +When contributing to this repository make sure to follow the Pull request process below. +Reduce to the minimum 3rd party dependencies. + +Please note we have a [code of conduct](#Code of Conduct), please follow it in all your interactions with the project. + +## Pull Request Process + +When doing a PR to v2 remember that you also have to do the PR port to v3, or tests confirming the bug is not reproducible. + +1. Supported version is v3. If you are fixing a bug in v2, please port to v3 +2. Use the title as a brief description of the changes +3. Describe the changes you are proposing + 1. If adding an extra validation state the benefits of adding it and the problem is solving + 2. Document in the readme, by adding it to the list +4. Provide appropriate tests for the code you are submitting: aim to keep the existing coverage percentage. +5. Add your Twitter handle (if you have) so we can thank you there. + +## License +By contributing, you agree that your contributions will be licensed under its MIT License. + +## Code of Conduct + +### Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +### Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +### Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +### Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +### Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at . +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +#### Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +#### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +#### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +#### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +#### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +### Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available +at [https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/tools/mailer/egulias/email-validator/LICENSE b/tools/mailer/egulias/email-validator/LICENSE new file mode 100644 index 000000000..b1902a4e9 --- /dev/null +++ b/tools/mailer/egulias/email-validator/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013-2023 Eduardo Gulias Davis + +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/tools/mailer/egulias/email-validator/composer.json b/tools/mailer/egulias/email-validator/composer.json new file mode 100644 index 000000000..bf1b3f4c9 --- /dev/null +++ b/tools/mailer/egulias/email-validator/composer.json @@ -0,0 +1,37 @@ +{ + "name": "egulias/email-validator", + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": ["email", "validation", "validator", "emailvalidation", "emailvalidator"], + "license": "MIT", + "authors": [ + {"name": "Eduardo Gulias Davis"} + ], + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "require": { + "php": ">=8.1", + "doctrine/lexer": "^2.0 || ^3.0", + "symfony/polyfill-intl-idn": "^1.26" + }, + "require-dev": { + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Egulias\\EmailValidator\\Tests\\": "tests" + } + } +} diff --git a/tools/mailer/egulias/email-validator/src/EmailLexer.php b/tools/mailer/egulias/email-validator/src/EmailLexer.php new file mode 100644 index 000000000..969c049f8 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/EmailLexer.php @@ -0,0 +1,330 @@ + */ +class EmailLexer extends AbstractLexer +{ + //ASCII values + public const S_EMPTY = -1; + public const C_NUL = 0; + public const S_HTAB = 9; + public const S_LF = 10; + public const S_CR = 13; + public const S_SP = 32; + public const EXCLAMATION = 33; + public const S_DQUOTE = 34; + public const NUMBER_SIGN = 35; + public const DOLLAR = 36; + public const PERCENTAGE = 37; + public const AMPERSAND = 38; + public const S_SQUOTE = 39; + public const S_OPENPARENTHESIS = 40; + public const S_CLOSEPARENTHESIS = 41; + public const ASTERISK = 42; + public const S_PLUS = 43; + public const S_COMMA = 44; + public const S_HYPHEN = 45; + public const S_DOT = 46; + public const S_SLASH = 47; + public const S_COLON = 58; + public const S_SEMICOLON = 59; + public const S_LOWERTHAN = 60; + public const S_EQUAL = 61; + public const S_GREATERTHAN = 62; + public const QUESTIONMARK = 63; + public const S_AT = 64; + public const S_OPENBRACKET = 91; + public const S_BACKSLASH = 92; + public const S_CLOSEBRACKET = 93; + public const CARET = 94; + public const S_UNDERSCORE = 95; + public const S_BACKTICK = 96; + public const S_OPENCURLYBRACES = 123; + public const S_PIPE = 124; + public const S_CLOSECURLYBRACES = 125; + public const S_TILDE = 126; + public const C_DEL = 127; + public const INVERT_QUESTIONMARK = 168; + public const INVERT_EXCLAMATION = 173; + public const GENERIC = 300; + public const S_IPV6TAG = 301; + public const INVALID = 302; + public const CRLF = 1310; + public const S_DOUBLECOLON = 5858; + public const ASCII_INVALID_FROM = 127; + public const ASCII_INVALID_TO = 199; + + /** + * US-ASCII visible characters not valid for atext (@link http://tools.ietf.org/html/rfc5322#section-3.2.3) + * + * @var array + */ + protected $charValue = [ + '{' => self::S_OPENCURLYBRACES, + '}' => self::S_CLOSECURLYBRACES, + '(' => self::S_OPENPARENTHESIS, + ')' => self::S_CLOSEPARENTHESIS, + '<' => self::S_LOWERTHAN, + '>' => self::S_GREATERTHAN, + '[' => self::S_OPENBRACKET, + ']' => self::S_CLOSEBRACKET, + ':' => self::S_COLON, + ';' => self::S_SEMICOLON, + '@' => self::S_AT, + '\\' => self::S_BACKSLASH, + '/' => self::S_SLASH, + ',' => self::S_COMMA, + '.' => self::S_DOT, + "'" => self::S_SQUOTE, + "`" => self::S_BACKTICK, + '"' => self::S_DQUOTE, + '-' => self::S_HYPHEN, + '::' => self::S_DOUBLECOLON, + ' ' => self::S_SP, + "\t" => self::S_HTAB, + "\r" => self::S_CR, + "\n" => self::S_LF, + "\r\n" => self::CRLF, + 'IPv6' => self::S_IPV6TAG, + '' => self::S_EMPTY, + '\0' => self::C_NUL, + '*' => self::ASTERISK, + '!' => self::EXCLAMATION, + '&' => self::AMPERSAND, + '^' => self::CARET, + '$' => self::DOLLAR, + '%' => self::PERCENTAGE, + '~' => self::S_TILDE, + '|' => self::S_PIPE, + '_' => self::S_UNDERSCORE, + '=' => self::S_EQUAL, + '+' => self::S_PLUS, + '¿' => self::INVERT_QUESTIONMARK, + '?' => self::QUESTIONMARK, + '#' => self::NUMBER_SIGN, + '¡' => self::INVERT_EXCLAMATION, + ]; + + public const INVALID_CHARS_REGEX = "/[^\p{S}\p{C}\p{Cc}]+/iu"; + + public const VALID_UTF8_REGEX = '/\p{Cc}+/u'; + + public const CATCHABLE_PATTERNS = [ + '[a-zA-Z]+[46]?', //ASCII and domain literal + '[^\x00-\x7F]', //UTF-8 + '[0-9]+', + '\r\n', + '::', + '\s+?', + '.', + ]; + + public const NON_CATCHABLE_PATTERNS = [ + '[\xA0-\xff]+', + ]; + + public const MODIFIERS = 'iu'; + + /** @var bool */ + protected $hasInvalidTokens = false; + + /** + * @var Token + */ + protected Token $previous; + + /** + * The last matched/seen token. + * + * @var Token + */ + public Token $current; + + /** + * @var Token + */ + private Token $nullToken; + + /** @var string */ + private $accumulator = ''; + + /** @var bool */ + private $hasToRecord = false; + + public function __construct() + { + /** @var Token $nullToken */ + $nullToken = new Token('', self::S_EMPTY, 0); + $this->nullToken = $nullToken; + + $this->current = $this->previous = $this->nullToken; + $this->lookahead = null; + } + + public function reset(): void + { + $this->hasInvalidTokens = false; + parent::reset(); + $this->current = $this->previous = $this->nullToken; + } + + /** + * @param int $type + * @throws \UnexpectedValueException + * @return boolean + * + * @psalm-suppress InvalidScalarArgument + */ + public function find($type): bool + { + $search = clone $this; + $search->skipUntil($type); + + if (!$search->lookahead) { + throw new \UnexpectedValueException($type . ' not found'); + } + return true; + } + + /** + * moveNext + * + * @return boolean + */ + public function moveNext(): bool + { + if ($this->hasToRecord && $this->previous === $this->nullToken) { + $this->accumulator .= $this->current->value; + } + + $this->previous = $this->current; + + if ($this->lookahead === null) { + $this->lookahead = $this->nullToken; + } + + $hasNext = parent::moveNext(); + $this->current = $this->token ?? $this->nullToken; + + if ($this->hasToRecord) { + $this->accumulator .= $this->current->value; + } + + return $hasNext; + } + + /** + * Retrieve token type. Also processes the token value if necessary. + * + * @param string $value + * @throws \InvalidArgumentException + * @return integer + */ + protected function getType(&$value): int + { + $encoded = $value; + + if (mb_detect_encoding($value, 'auto', true) !== 'UTF-8') { + $encoded = mb_convert_encoding($value, 'UTF-8', 'Windows-1252'); + } + + if ($this->isValid($encoded)) { + return $this->charValue[$encoded]; + } + + if ($this->isNullType($encoded)) { + return self::C_NUL; + } + + if ($this->isInvalidChar($encoded)) { + $this->hasInvalidTokens = true; + return self::INVALID; + } + + return self::GENERIC; + } + + protected function isValid(string $value): bool + { + return isset($this->charValue[$value]); + } + + protected function isNullType(string $value): bool + { + return $value === "\0"; + } + + protected function isInvalidChar(string $value): bool + { + return !preg_match(self::INVALID_CHARS_REGEX, $value); + } + + protected function isUTF8Invalid(string $value): bool + { + return preg_match(self::VALID_UTF8_REGEX, $value) !== false; + } + + public function hasInvalidTokens(): bool + { + return $this->hasInvalidTokens; + } + + /** + * getPrevious + * + * @return Token + */ + public function getPrevious(): Token + { + return $this->previous; + } + + /** + * Lexical catchable patterns. + * + * @return string[] + */ + protected function getCatchablePatterns(): array + { + return self::CATCHABLE_PATTERNS; + } + + /** + * Lexical non-catchable patterns. + * + * @return string[] + */ + protected function getNonCatchablePatterns(): array + { + return self::NON_CATCHABLE_PATTERNS; + } + + protected function getModifiers(): string + { + return self::MODIFIERS; + } + + public function getAccumulatedValues(): string + { + return $this->accumulator; + } + + public function startRecording(): void + { + $this->hasToRecord = true; + } + + public function stopRecording(): void + { + $this->hasToRecord = false; + } + + public function clearRecorded(): void + { + $this->accumulator = ''; + } +} diff --git a/tools/mailer/egulias/email-validator/src/EmailParser.php b/tools/mailer/egulias/email-validator/src/EmailParser.php new file mode 100644 index 000000000..fc449c76f --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/EmailParser.php @@ -0,0 +1,90 @@ +addLongEmailWarning($this->localPart, $this->domainPart); + + return $result; + } + + protected function preLeftParsing(): Result + { + if (!$this->hasAtToken()) { + return new InvalidEmail(new NoLocalPart(), $this->lexer->current->value); + } + return new ValidEmail(); + } + + protected function parseLeftFromAt(): Result + { + return $this->processLocalPart(); + } + + protected function parseRightFromAt(): Result + { + return $this->processDomainPart(); + } + + private function processLocalPart(): Result + { + $localPartParser = new LocalPart($this->lexer); + $localPartResult = $localPartParser->parse(); + $this->localPart = $localPartParser->localPart(); + $this->warnings = [...$localPartParser->getWarnings(), ...$this->warnings]; + + return $localPartResult; + } + + private function processDomainPart(): Result + { + $domainPartParser = new DomainPart($this->lexer); + $domainPartResult = $domainPartParser->parse(); + $this->domainPart = $domainPartParser->domainPart(); + $this->warnings = [...$domainPartParser->getWarnings(), ...$this->warnings]; + + return $domainPartResult; + } + + public function getDomainPart(): string + { + return $this->domainPart; + } + + public function getLocalPart(): string + { + return $this->localPart; + } + + private function addLongEmailWarning(string $localPart, string $parsedDomainPart): void + { + if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAIL_MAX_LENGTH) { + $this->warnings[EmailTooLong::CODE] = new EmailTooLong(); + } + } +} diff --git a/tools/mailer/egulias/email-validator/src/EmailValidator.php b/tools/mailer/egulias/email-validator/src/EmailValidator.php new file mode 100644 index 000000000..5a2e5c822 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/EmailValidator.php @@ -0,0 +1,67 @@ +lexer = new EmailLexer(); + } + + /** + * @param string $email + * @param EmailValidation $emailValidation + * @return bool + */ + public function isValid(string $email, EmailValidation $emailValidation) + { + $isValid = $emailValidation->isValid($email, $this->lexer); + $this->warnings = $emailValidation->getWarnings(); + $this->error = $emailValidation->getError(); + + return $isValid; + } + + /** + * @return boolean + */ + public function hasWarnings() + { + return !empty($this->warnings); + } + + /** + * @return array + */ + public function getWarnings() + { + return $this->warnings; + } + + /** + * @return InvalidEmail|null + */ + public function getError() + { + return $this->error; + } +} diff --git a/tools/mailer/egulias/email-validator/src/MessageIDParser.php b/tools/mailer/egulias/email-validator/src/MessageIDParser.php new file mode 100644 index 000000000..35bd0a7f1 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/MessageIDParser.php @@ -0,0 +1,91 @@ +addLongEmailWarning($this->idLeft, $this->idRight); + + return $result; + } + + protected function preLeftParsing(): Result + { + if (!$this->hasAtToken()) { + return new InvalidEmail(new NoLocalPart(), $this->lexer->current->value); + } + return new ValidEmail(); + } + + protected function parseLeftFromAt(): Result + { + return $this->processIDLeft(); + } + + protected function parseRightFromAt(): Result + { + return $this->processIDRight(); + } + + private function processIDLeft(): Result + { + $localPartParser = new IDLeftPart($this->lexer); + $localPartResult = $localPartParser->parse(); + $this->idLeft = $localPartParser->localPart(); + $this->warnings = [...$localPartParser->getWarnings(), ...$this->warnings]; + + return $localPartResult; + } + + private function processIDRight(): Result + { + $domainPartParser = new IDRightPart($this->lexer); + $domainPartResult = $domainPartParser->parse(); + $this->idRight = $domainPartParser->domainPart(); + $this->warnings = [...$domainPartParser->getWarnings(), ...$this->warnings]; + + return $domainPartResult; + } + + public function getLeftPart(): string + { + return $this->idLeft; + } + + public function getRightPart(): string + { + return $this->idRight; + } + + private function addLongEmailWarning(string $localPart, string $parsedDomainPart): void + { + if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAILID_MAX_LENGTH) { + $this->warnings[EmailTooLong::CODE] = new EmailTooLong(); + } + } +} diff --git a/tools/mailer/egulias/email-validator/src/Parser.php b/tools/mailer/egulias/email-validator/src/Parser.php new file mode 100644 index 000000000..d577e3eae --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Parser.php @@ -0,0 +1,78 @@ +lexer = $lexer; + } + + public function parse(string $str): Result + { + $this->lexer->setInput($str); + + if ($this->lexer->hasInvalidTokens()) { + return new InvalidEmail(new ExpectingATEXT("Invalid tokens found"), $this->lexer->current->value); + } + + $preParsingResult = $this->preLeftParsing(); + if ($preParsingResult->isInvalid()) { + return $preParsingResult; + } + + $localPartResult = $this->parseLeftFromAt(); + + if ($localPartResult->isInvalid()) { + return $localPartResult; + } + + $domainPartResult = $this->parseRightFromAt(); + + if ($domainPartResult->isInvalid()) { + return $domainPartResult; + } + + return new ValidEmail(); + } + + /** + * @return Warning\Warning[] + */ + public function getWarnings(): array + { + return $this->warnings; + } + + protected function hasAtToken(): bool + { + $this->lexer->moveNext(); + $this->lexer->moveNext(); + + return !$this->lexer->current->isA(EmailLexer::S_AT); + } +} diff --git a/tools/mailer/egulias/email-validator/src/Parser/Comment.php b/tools/mailer/egulias/email-validator/src/Parser/Comment.php new file mode 100644 index 000000000..7b5b47e29 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Parser/Comment.php @@ -0,0 +1,102 @@ +lexer = $lexer; + $this->commentStrategy = $commentStrategy; + } + + public function parse(): Result + { + if ($this->lexer->current->isA(EmailLexer::S_OPENPARENTHESIS)) { + $this->openedParenthesis++; + if ($this->noClosingParenthesis()) { + return new InvalidEmail(new UnclosedComment(), $this->lexer->current->value); + } + } + + if ($this->lexer->current->isA(EmailLexer::S_CLOSEPARENTHESIS)) { + return new InvalidEmail(new UnOpenedComment(), $this->lexer->current->value); + } + + $this->warnings[WarningComment::CODE] = new WarningComment(); + + $moreTokens = true; + while ($this->commentStrategy->exitCondition($this->lexer, $this->openedParenthesis) && $moreTokens) { + + if ($this->lexer->isNextToken(EmailLexer::S_OPENPARENTHESIS)) { + $this->openedParenthesis++; + } + $this->warnEscaping(); + if ($this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) { + $this->openedParenthesis--; + } + $moreTokens = $this->lexer->moveNext(); + } + + if ($this->openedParenthesis >= 1) { + return new InvalidEmail(new UnclosedComment(), $this->lexer->current->value); + } + if ($this->openedParenthesis < 0) { + return new InvalidEmail(new UnOpenedComment(), $this->lexer->current->value); + } + + $finalValidations = $this->commentStrategy->endOfLoopValidations($this->lexer); + + $this->warnings = [...$this->warnings, ...$this->commentStrategy->getWarnings()]; + + return $finalValidations; + } + + + /** + * @return void + */ + private function warnEscaping(): void + { + //Backslash found + if (!$this->lexer->current->isA(EmailLexer::S_BACKSLASH)) { + return; + } + + if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) { + return; + } + + $this->warnings[QuotedPart::CODE] = + new QuotedPart($this->lexer->getPrevious()->type, $this->lexer->current->type); + } + + private function noClosingParenthesis(): bool + { + try { + $this->lexer->find(EmailLexer::S_CLOSEPARENTHESIS); + return false; + } catch (\RuntimeException $e) { + return true; + } + } +} diff --git a/tools/mailer/egulias/email-validator/src/Parser/CommentStrategy/CommentStrategy.php b/tools/mailer/egulias/email-validator/src/Parser/CommentStrategy/CommentStrategy.php new file mode 100644 index 000000000..8834db04c --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Parser/CommentStrategy/CommentStrategy.php @@ -0,0 +1,22 @@ +isNextToken(EmailLexer::S_DOT)); + } + + public function endOfLoopValidations(EmailLexer $lexer): Result + { + //test for end of string + if (!$lexer->isNextToken(EmailLexer::S_DOT)) { + return new InvalidEmail(new ExpectingATEXT('DOT not found near CLOSEPARENTHESIS'), $lexer->current->value); + } + //add warning + //Address is valid within the message but cannot be used unmodified for the envelope + return new ValidEmail(); + } + + public function getWarnings(): array + { + return []; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Parser/CommentStrategy/LocalComment.php b/tools/mailer/egulias/email-validator/src/Parser/CommentStrategy/LocalComment.php new file mode 100644 index 000000000..5c18b440b --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Parser/CommentStrategy/LocalComment.php @@ -0,0 +1,37 @@ +isNextToken(EmailLexer::S_AT); + } + + public function endOfLoopValidations(EmailLexer $lexer): Result + { + if (!$lexer->isNextToken(EmailLexer::S_AT)) { + return new InvalidEmail(new ExpectingATEXT('ATEX is not expected after closing comments'), $lexer->current->value); + } + $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt(); + return new ValidEmail(); + } + + public function getWarnings(): array + { + return $this->warnings; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Parser/DomainLiteral.php b/tools/mailer/egulias/email-validator/src/Parser/DomainLiteral.php new file mode 100644 index 000000000..5093e5083 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Parser/DomainLiteral.php @@ -0,0 +1,210 @@ +addTagWarnings(); + + $IPv6TAG = false; + $addressLiteral = ''; + + do { + if ($this->lexer->current->isA(EmailLexer::C_NUL)) { + return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->current->value); + } + + $this->addObsoleteWarnings(); + + if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENBRACKET, EmailLexer::S_OPENBRACKET))) { + return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->current->value); + } + + if ($this->lexer->isNextTokenAny( + array(EmailLexer::S_HTAB, EmailLexer::S_SP, EmailLexer::CRLF) + )) { + $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); + $this->parseFWS(); + } + + if ($this->lexer->isNextToken(EmailLexer::S_CR)) { + return new InvalidEmail(new CRNoLF(), $this->lexer->current->value); + } + + if ($this->lexer->current->isA(EmailLexer::S_BACKSLASH)) { + return new InvalidEmail(new UnusualElements($this->lexer->current->value), $this->lexer->current->value); + } + if ($this->lexer->current->isA(EmailLexer::S_IPV6TAG)) { + $IPv6TAG = true; + } + + if ($this->lexer->current->isA(EmailLexer::S_CLOSEBRACKET)) { + break; + } + + $addressLiteral .= $this->lexer->current->value; + } while ($this->lexer->moveNext()); + + + //Encapsulate + $addressLiteral = str_replace('[', '', $addressLiteral); + $isAddressLiteralIPv4 = $this->checkIPV4Tag($addressLiteral); + + if (!$isAddressLiteralIPv4) { + return new ValidEmail(); + } + + $addressLiteral = $this->convertIPv4ToIPv6($addressLiteral); + + if (!$IPv6TAG) { + $this->warnings[WarningDomainLiteral::CODE] = new WarningDomainLiteral(); + return new ValidEmail(); + } + + $this->warnings[AddressLiteral::CODE] = new AddressLiteral(); + + $this->checkIPV6Tag($addressLiteral); + + return new ValidEmail(); + } + + /** + * @param string $addressLiteral + * @param int $maxGroups + */ + public function checkIPV6Tag($addressLiteral, $maxGroups = 8): void + { + $prev = $this->lexer->getPrevious(); + if ($prev->isA(EmailLexer::S_COLON)) { + $this->warnings[IPV6ColonEnd::CODE] = new IPV6ColonEnd(); + } + + $IPv6 = substr($addressLiteral, 5); + //Daniel Marschall's new IPv6 testing strategy + $matchesIP = explode(':', $IPv6); + $groupCount = count($matchesIP); + $colons = strpos($IPv6, '::'); + + if (count(preg_grep('/^[0-9A-Fa-f]{0,4}$/', $matchesIP, PREG_GREP_INVERT)) !== 0) { + $this->warnings[IPV6BadChar::CODE] = new IPV6BadChar(); + } + + if ($colons === false) { + // We need exactly the right number of groups + if ($groupCount !== $maxGroups) { + $this->warnings[IPV6GroupCount::CODE] = new IPV6GroupCount(); + } + return; + } + + if ($colons !== strrpos($IPv6, '::')) { + $this->warnings[IPV6DoubleColon::CODE] = new IPV6DoubleColon(); + return; + } + + if ($colons === 0 || $colons === (strlen($IPv6) - 2)) { + // RFC 4291 allows :: at the start or end of an address + //with 7 other groups in addition + ++$maxGroups; + } + + if ($groupCount > $maxGroups) { + $this->warnings[IPV6MaxGroups::CODE] = new IPV6MaxGroups(); + } elseif ($groupCount === $maxGroups) { + $this->warnings[IPV6Deprecated::CODE] = new IPV6Deprecated(); + } + } + + public function convertIPv4ToIPv6(string $addressLiteralIPv4): string + { + $matchesIP = []; + $IPv4Match = preg_match(self::IPV4_REGEX, $addressLiteralIPv4, $matchesIP); + + // Extract IPv4 part from the end of the address-literal (if there is one) + if ($IPv4Match > 0) { + $index = (int) strrpos($addressLiteralIPv4, $matchesIP[0]); + //There's a match but it is at the start + if ($index > 0) { + // Convert IPv4 part to IPv6 format for further testing + return substr($addressLiteralIPv4, 0, $index) . '0:0'; + } + } + + return $addressLiteralIPv4; + } + + /** + * @param string $addressLiteral + * + * @return bool + */ + protected function checkIPV4Tag($addressLiteral): bool + { + $matchesIP = []; + $IPv4Match = preg_match(self::IPV4_REGEX, $addressLiteral, $matchesIP); + + // Extract IPv4 part from the end of the address-literal (if there is one) + + if ($IPv4Match > 0) { + $index = strrpos($addressLiteral, $matchesIP[0]); + //There's a match but it is at the start + if ($index === 0) { + $this->warnings[AddressLiteral::CODE] = new AddressLiteral(); + return false; + } + } + + return true; + } + + private function addObsoleteWarnings(): void + { + if (in_array($this->lexer->current->type, self::OBSOLETE_WARNINGS)) { + $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT(); + } + } + + private function addTagWarnings(): void + { + if ($this->lexer->isNextToken(EmailLexer::S_COLON)) { + $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart(); + } + if ($this->lexer->isNextToken(EmailLexer::S_IPV6TAG)) { + $lexer = clone $this->lexer; + $lexer->moveNext(); + if ($lexer->isNextToken(EmailLexer::S_DOUBLECOLON)) { + $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart(); + } + } + } +} diff --git a/tools/mailer/egulias/email-validator/src/Parser/DomainPart.php b/tools/mailer/egulias/email-validator/src/Parser/DomainPart.php new file mode 100644 index 000000000..a1a56cf3d --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Parser/DomainPart.php @@ -0,0 +1,326 @@ +lexer->clearRecorded(); + $this->lexer->startRecording(); + + $this->lexer->moveNext(); + + $domainChecks = $this->performDomainStartChecks(); + if ($domainChecks->isInvalid()) { + return $domainChecks; + } + + if ($this->lexer->current->isA(EmailLexer::S_AT)) { + return new InvalidEmail(new ConsecutiveAt(), $this->lexer->current->value); + } + + $result = $this->doParseDomainPart(); + if ($result->isInvalid()) { + return $result; + } + + $end = $this->checkEndOfDomain(); + if ($end->isInvalid()) { + return $end; + } + + $this->lexer->stopRecording(); + $this->domainPart = $this->lexer->getAccumulatedValues(); + + $length = strlen($this->domainPart); + if ($length > self::DOMAIN_MAX_LENGTH) { + return new InvalidEmail(new DomainTooLong(), $this->lexer->current->value); + } + + return new ValidEmail(); + } + + private function checkEndOfDomain(): Result + { + $prev = $this->lexer->getPrevious(); + if ($prev->isA(EmailLexer::S_DOT)) { + return new InvalidEmail(new DotAtEnd(), $this->lexer->current->value); + } + if ($prev->isA(EmailLexer::S_HYPHEN)) { + return new InvalidEmail(new DomainHyphened('Hypen found at the end of the domain'), $prev->value); + } + + if ($this->lexer->current->isA(EmailLexer::S_SP)) { + return new InvalidEmail(new CRLFAtTheEnd(), $prev->value); + } + return new ValidEmail(); + } + + private function performDomainStartChecks(): Result + { + $invalidTokens = $this->checkInvalidTokensAfterAT(); + if ($invalidTokens->isInvalid()) { + return $invalidTokens; + } + + $missingDomain = $this->checkEmptyDomain(); + if ($missingDomain->isInvalid()) { + return $missingDomain; + } + + if ($this->lexer->current->isA(EmailLexer::S_OPENPARENTHESIS)) { + $this->warnings[DeprecatedComment::CODE] = new DeprecatedComment(); + } + return new ValidEmail(); + } + + private function checkEmptyDomain(): Result + { + $thereIsNoDomain = $this->lexer->current->isA(EmailLexer::S_EMPTY) || + ($this->lexer->current->isA(EmailLexer::S_SP) && + !$this->lexer->isNextToken(EmailLexer::GENERIC)); + + if ($thereIsNoDomain) { + return new InvalidEmail(new NoDomainPart(), $this->lexer->current->value); + } + + return new ValidEmail(); + } + + private function checkInvalidTokensAfterAT(): Result + { + if ($this->lexer->current->isA(EmailLexer::S_DOT)) { + return new InvalidEmail(new DotAtStart(), $this->lexer->current->value); + } + if ($this->lexer->current->isA(EmailLexer::S_HYPHEN)) { + return new InvalidEmail(new DomainHyphened('After AT'), $this->lexer->current->value); + } + return new ValidEmail(); + } + + protected function parseComments(): Result + { + $commentParser = new Comment($this->lexer, new DomainComment()); + $result = $commentParser->parse(); + $this->warnings = [...$this->warnings, ...$commentParser->getWarnings()]; + + return $result; + } + + protected function doParseDomainPart(): Result + { + $tldMissing = true; + $hasComments = false; + $domain = ''; + do { + $prev = $this->lexer->getPrevious(); + + $notAllowedChars = $this->checkNotAllowedChars($this->lexer->current); + if ($notAllowedChars->isInvalid()) { + return $notAllowedChars; + } + + if ( + $this->lexer->current->isA(EmailLexer::S_OPENPARENTHESIS) || + $this->lexer->current->isA(EmailLexer::S_CLOSEPARENTHESIS) + ) { + $hasComments = true; + $commentsResult = $this->parseComments(); + + //Invalid comment parsing + if ($commentsResult->isInvalid()) { + return $commentsResult; + } + } + + $dotsResult = $this->checkConsecutiveDots(); + if ($dotsResult->isInvalid()) { + return $dotsResult; + } + + if ($this->lexer->current->isA(EmailLexer::S_OPENBRACKET)) { + $literalResult = $this->parseDomainLiteral(); + + $this->addTLDWarnings($tldMissing); + return $literalResult; + } + + $labelCheck = $this->checkLabelLength(); + if ($labelCheck->isInvalid()) { + return $labelCheck; + } + + $FwsResult = $this->parseFWS(); + if ($FwsResult->isInvalid()) { + return $FwsResult; + } + + $domain .= $this->lexer->current->value; + + if ($this->lexer->current->isA(EmailLexer::S_DOT) && $this->lexer->isNextToken(EmailLexer::GENERIC)) { + $tldMissing = false; + } + + $exceptionsResult = $this->checkDomainPartExceptions($prev, $hasComments); + if ($exceptionsResult->isInvalid()) { + return $exceptionsResult; + } + $this->lexer->moveNext(); + } while (!$this->lexer->current->isA(EmailLexer::S_EMPTY)); + + $labelCheck = $this->checkLabelLength(true); + if ($labelCheck->isInvalid()) { + return $labelCheck; + } + $this->addTLDWarnings($tldMissing); + + $this->domainPart = $domain; + return new ValidEmail(); + } + + /** + * @param Token $token + * + * @return Result + */ + private function checkNotAllowedChars(Token $token): Result + { + $notAllowed = [EmailLexer::S_BACKSLASH => true, EmailLexer::S_SLASH => true]; + if (isset($notAllowed[$token->type])) { + return new InvalidEmail(new CharNotAllowed(), $token->value); + } + return new ValidEmail(); + } + + /** + * @return Result + */ + protected function parseDomainLiteral(): Result + { + try { + $this->lexer->find(EmailLexer::S_CLOSEBRACKET); + } catch (\RuntimeException $e) { + return new InvalidEmail(new ExpectingDomainLiteralClose(), $this->lexer->current->value); + } + + $domainLiteralParser = new DomainLiteralParser($this->lexer); + $result = $domainLiteralParser->parse(); + $this->warnings = [...$this->warnings, ...$domainLiteralParser->getWarnings()]; + return $result; + } + + /** + * @param Token $prev + * @param bool $hasComments + * + * @return Result + */ + protected function checkDomainPartExceptions(Token $prev, bool $hasComments): Result + { + if ($this->lexer->current->isA(EmailLexer::S_OPENBRACKET) && $prev->type !== EmailLexer::S_AT) { + return new InvalidEmail(new ExpectingATEXT('OPENBRACKET not after AT'), $this->lexer->current->value); + } + + if ($this->lexer->current->isA(EmailLexer::S_HYPHEN) && $this->lexer->isNextToken(EmailLexer::S_DOT)) { + return new InvalidEmail(new DomainHyphened('Hypen found near DOT'), $this->lexer->current->value); + } + + if ( + $this->lexer->current->isA(EmailLexer::S_BACKSLASH) + && $this->lexer->isNextToken(EmailLexer::GENERIC) + ) { + return new InvalidEmail(new ExpectingATEXT('Escaping following "ATOM"'), $this->lexer->current->value); + } + + return $this->validateTokens($hasComments); + } + + protected function validateTokens(bool $hasComments): Result + { + $validDomainTokens = array( + EmailLexer::GENERIC => true, + EmailLexer::S_HYPHEN => true, + EmailLexer::S_DOT => true, + ); + + if ($hasComments) { + $validDomainTokens[EmailLexer::S_OPENPARENTHESIS] = true; + $validDomainTokens[EmailLexer::S_CLOSEPARENTHESIS] = true; + } + + if (!isset($validDomainTokens[$this->lexer->current->type])) { + return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->current->value), $this->lexer->current->value); + } + + return new ValidEmail(); + } + + private function checkLabelLength(bool $isEndOfDomain = false): Result + { + if ($this->lexer->current->isA(EmailLexer::S_DOT) || $isEndOfDomain) { + if ($this->isLabelTooLong($this->label)) { + return new InvalidEmail(new LabelTooLong(), $this->lexer->current->value); + } + $this->label = ''; + } + $this->label .= $this->lexer->current->value; + return new ValidEmail(); + } + + + private function isLabelTooLong(string $label): bool + { + if (preg_match('/[^\x00-\x7F]/', $label)) { + idn_to_ascii($label, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46, $idnaInfo); + return (bool) ($idnaInfo['errors'] & IDNA_ERROR_LABEL_TOO_LONG); + } + return strlen($label) > self::LABEL_MAX_LENGTH; + } + + private function addTLDWarnings(bool $isTLDMissing): void + { + if ($isTLDMissing) { + $this->warnings[TLD::CODE] = new TLD(); + } + } + + public function domainPart(): string + { + return $this->domainPart; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Parser/DoubleQuote.php b/tools/mailer/egulias/email-validator/src/Parser/DoubleQuote.php new file mode 100644 index 000000000..b5335d300 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Parser/DoubleQuote.php @@ -0,0 +1,91 @@ +checkDQUOTE(); + if ($validQuotedString->isInvalid()) { + return $validQuotedString; + } + + $special = [ + EmailLexer::S_CR => true, + EmailLexer::S_HTAB => true, + EmailLexer::S_LF => true + ]; + + $invalid = [ + EmailLexer::C_NUL => true, + EmailLexer::S_HTAB => true, + EmailLexer::S_CR => true, + EmailLexer::S_LF => true + ]; + + $setSpecialsWarning = true; + + $this->lexer->moveNext(); + + while (!$this->lexer->current->isA(EmailLexer::S_DQUOTE) && !$this->lexer->current->isA(EmailLexer::S_EMPTY)) { + if (isset($special[$this->lexer->current->type]) && $setSpecialsWarning) { + $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); + $setSpecialsWarning = false; + } + if ($this->lexer->current->isA(EmailLexer::S_BACKSLASH) && $this->lexer->isNextToken(EmailLexer::S_DQUOTE)) { + $this->lexer->moveNext(); + } + + $this->lexer->moveNext(); + + if (!$this->escaped() && isset($invalid[$this->lexer->current->type])) { + return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), $this->lexer->current->value); + } + } + + $prev = $this->lexer->getPrevious(); + + if ($prev->isA(EmailLexer::S_BACKSLASH)) { + $validQuotedString = $this->checkDQUOTE(); + if ($validQuotedString->isInvalid()) { + return $validQuotedString; + } + } + + if (!$this->lexer->isNextToken(EmailLexer::S_AT) && !$prev->isA(EmailLexer::S_BACKSLASH)) { + return new InvalidEmail(new ExpectingATEXT("Expecting ATEXT between DQUOTE"), $this->lexer->current->value); + } + + return new ValidEmail(); + } + + protected function checkDQUOTE(): Result + { + $previous = $this->lexer->getPrevious(); + + if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous->isA(EmailLexer::GENERIC)) { + $description = 'https://tools.ietf.org/html/rfc5322#section-3.2.4 - quoted string should be a unit'; + return new InvalidEmail(new ExpectingATEXT($description), $this->lexer->current->value); + } + + try { + $this->lexer->find(EmailLexer::S_DQUOTE); + } catch (\Exception $e) { + return new InvalidEmail(new UnclosedQuotedString(), $this->lexer->current->value); + } + $this->warnings[QuotedString::CODE] = new QuotedString($previous->value, $this->lexer->current->value); + + return new ValidEmail(); + } +} diff --git a/tools/mailer/egulias/email-validator/src/Parser/FoldingWhiteSpace.php b/tools/mailer/egulias/email-validator/src/Parser/FoldingWhiteSpace.php new file mode 100644 index 000000000..348a7af44 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Parser/FoldingWhiteSpace.php @@ -0,0 +1,87 @@ +isFWS()) { + return new ValidEmail(); + } + + $previous = $this->lexer->getPrevious(); + + $resultCRLF = $this->checkCRLFInFWS(); + if ($resultCRLF->isInvalid()) { + return $resultCRLF; + } + + if ($this->lexer->current->isA(EmailLexer::S_CR)) { + return new InvalidEmail(new CRNoLF(), $this->lexer->current->value); + } + + if ($this->lexer->isNextToken(EmailLexer::GENERIC) && !$previous->isA(EmailLexer::S_AT)) { + return new InvalidEmail(new AtextAfterCFWS(), $this->lexer->current->value); + } + + if ($this->lexer->current->isA(EmailLexer::S_LF) || $this->lexer->current->isA(EmailLexer::C_NUL)) { + return new InvalidEmail(new ExpectingCTEXT(), $this->lexer->current->value); + } + + if ($this->lexer->isNextToken(EmailLexer::S_AT) || $previous->isA(EmailLexer::S_AT)) { + $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt(); + } else { + $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); + } + + return new ValidEmail(); + } + + protected function checkCRLFInFWS(): Result + { + if (!$this->lexer->current->isA(EmailLexer::CRLF)) { + return new ValidEmail(); + } + + if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) { + return new InvalidEmail(new CRLFX2(), $this->lexer->current->value); + } + + //this has no coverage. Condition is repeated from above one + if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) { + return new InvalidEmail(new CRLFAtTheEnd(), $this->lexer->current->value); + } + + return new ValidEmail(); + } + + protected function isFWS(): bool + { + if ($this->escaped()) { + return false; + } + + return in_array($this->lexer->current->type, self::FWS_TYPES); + } +} diff --git a/tools/mailer/egulias/email-validator/src/Parser/IDLeftPart.php b/tools/mailer/egulias/email-validator/src/Parser/IDLeftPart.php new file mode 100644 index 000000000..bedcf7b20 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Parser/IDLeftPart.php @@ -0,0 +1,15 @@ +lexer->current->value); + } +} diff --git a/tools/mailer/egulias/email-validator/src/Parser/IDRightPart.php b/tools/mailer/egulias/email-validator/src/Parser/IDRightPart.php new file mode 100644 index 000000000..d2fc1d748 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Parser/IDRightPart.php @@ -0,0 +1,29 @@ + true, + EmailLexer::S_SQUOTE => true, + EmailLexer::S_BACKTICK => true, + EmailLexer::S_SEMICOLON => true, + EmailLexer::S_GREATERTHAN => true, + EmailLexer::S_LOWERTHAN => true, + ]; + + if (isset($invalidDomainTokens[$this->lexer->current->type])) { + return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->current->value), $this->lexer->current->value); + } + return new ValidEmail(); + } +} diff --git a/tools/mailer/egulias/email-validator/src/Parser/LocalPart.php b/tools/mailer/egulias/email-validator/src/Parser/LocalPart.php new file mode 100644 index 000000000..5ed29d606 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Parser/LocalPart.php @@ -0,0 +1,162 @@ + EmailLexer::S_COMMA, + EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET, + EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET, + EmailLexer::S_GREATERTHAN => EmailLexer::S_GREATERTHAN, + EmailLexer::S_LOWERTHAN => EmailLexer::S_LOWERTHAN, + EmailLexer::S_COLON => EmailLexer::S_COLON, + EmailLexer::S_SEMICOLON => EmailLexer::S_SEMICOLON, + EmailLexer::INVALID => EmailLexer::INVALID + ]; + + /** + * @var string + */ + private $localPart = ''; + + + public function parse(): Result + { + $this->lexer->startRecording(); + + while (!$this->lexer->current->isA(EmailLexer::S_AT) && !$this->lexer->current->isA(EmailLexer::S_EMPTY)) { + if ($this->hasDotAtStart()) { + return new InvalidEmail(new DotAtStart(), $this->lexer->current->value); + } + + if ($this->lexer->current->isA(EmailLexer::S_DQUOTE)) { + $dquoteParsingResult = $this->parseDoubleQuote(); + + //Invalid double quote parsing + if ($dquoteParsingResult->isInvalid()) { + return $dquoteParsingResult; + } + } + + if ( + $this->lexer->current->isA(EmailLexer::S_OPENPARENTHESIS) || + $this->lexer->current->isA(EmailLexer::S_CLOSEPARENTHESIS) + ) { + $commentsResult = $this->parseComments(); + + //Invalid comment parsing + if ($commentsResult->isInvalid()) { + return $commentsResult; + } + } + + if ($this->lexer->current->isA(EmailLexer::S_DOT) && $this->lexer->isNextToken(EmailLexer::S_DOT)) { + return new InvalidEmail(new ConsecutiveDot(), $this->lexer->current->value); + } + + if ( + $this->lexer->current->isA(EmailLexer::S_DOT) && + $this->lexer->isNextToken(EmailLexer::S_AT) + ) { + return new InvalidEmail(new DotAtEnd(), $this->lexer->current->value); + } + + $resultEscaping = $this->validateEscaping(); + if ($resultEscaping->isInvalid()) { + return $resultEscaping; + } + + $resultToken = $this->validateTokens(false); + if ($resultToken->isInvalid()) { + return $resultToken; + } + + $resultFWS = $this->parseLocalFWS(); + if ($resultFWS->isInvalid()) { + return $resultFWS; + } + + $this->lexer->moveNext(); + } + + $this->lexer->stopRecording(); + $this->localPart = rtrim($this->lexer->getAccumulatedValues(), '@'); + if (strlen($this->localPart) > LocalTooLong::LOCAL_PART_LENGTH) { + $this->warnings[LocalTooLong::CODE] = new LocalTooLong(); + } + + return new ValidEmail(); + } + + protected function validateTokens(bool $hasComments): Result + { + if (isset(self::INVALID_TOKENS[$this->lexer->current->type])) { + return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->current->value); + } + return new ValidEmail(); + } + + public function localPart(): string + { + return $this->localPart; + } + + private function parseLocalFWS(): Result + { + $foldingWS = new FoldingWhiteSpace($this->lexer); + $resultFWS = $foldingWS->parse(); + if ($resultFWS->isValid()) { + $this->warnings = [...$this->warnings, ...$foldingWS->getWarnings()]; + } + return $resultFWS; + } + + private function hasDotAtStart(): bool + { + return $this->lexer->current->isA(EmailLexer::S_DOT) && $this->lexer->getPrevious()->isA(EmailLexer::S_EMPTY); + } + + private function parseDoubleQuote(): Result + { + $dquoteParser = new DoubleQuote($this->lexer); + $parseAgain = $dquoteParser->parse(); + $this->warnings = [...$this->warnings, ...$dquoteParser->getWarnings()]; + + return $parseAgain; + } + + protected function parseComments(): Result + { + $commentParser = new Comment($this->lexer, new LocalComment()); + $result = $commentParser->parse(); + $this->warnings = [...$this->warnings, ...$commentParser->getWarnings()]; + + return $result; + } + + private function validateEscaping(): Result + { + //Backslash found + if (!$this->lexer->current->isA(EmailLexer::S_BACKSLASH)) { + return new ValidEmail(); + } + + if ($this->lexer->isNextToken(EmailLexer::GENERIC)) { + return new InvalidEmail(new ExpectingATEXT('Found ATOM after escaping'), $this->lexer->current->value); + } + + return new ValidEmail(); + } +} diff --git a/tools/mailer/egulias/email-validator/src/Parser/PartParser.php b/tools/mailer/egulias/email-validator/src/Parser/PartParser.php new file mode 100644 index 000000000..53afb2575 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Parser/PartParser.php @@ -0,0 +1,63 @@ +lexer = $lexer; + } + + abstract public function parse(): Result; + + /** + * @return Warning[] + */ + public function getWarnings() + { + return $this->warnings; + } + + protected function parseFWS(): Result + { + $foldingWS = new FoldingWhiteSpace($this->lexer); + $resultFWS = $foldingWS->parse(); + $this->warnings = [...$this->warnings, ...$foldingWS->getWarnings()]; + return $resultFWS; + } + + protected function checkConsecutiveDots(): Result + { + if ($this->lexer->current->isA(EmailLexer::S_DOT) && $this->lexer->isNextToken(EmailLexer::S_DOT)) { + return new InvalidEmail(new ConsecutiveDot(), $this->lexer->current->value); + } + + return new ValidEmail(); + } + + protected function escaped(): bool + { + $previous = $this->lexer->getPrevious(); + + return $previous->isA(EmailLexer::S_BACKSLASH) + && !$this->lexer->current->isA(EmailLexer::GENERIC); + } +} diff --git a/tools/mailer/egulias/email-validator/src/Result/InvalidEmail.php b/tools/mailer/egulias/email-validator/src/Result/InvalidEmail.php new file mode 100644 index 000000000..82699acc6 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Result/InvalidEmail.php @@ -0,0 +1,49 @@ +token = $token; + $this->reason = $reason; + } + + public function isValid(): bool + { + return false; + } + + public function isInvalid(): bool + { + return true; + } + + public function description(): string + { + return $this->reason->description() . " in char " . $this->token; + } + + public function code(): int + { + return $this->reason->code(); + } + + public function reason(): Reason + { + return $this->reason; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Result/MultipleErrors.php b/tools/mailer/egulias/email-validator/src/Result/MultipleErrors.php new file mode 100644 index 000000000..5fa85afc9 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Result/MultipleErrors.php @@ -0,0 +1,56 @@ +reasons[$reason->code()] = $reason; + } + + /** + * @return Reason[] + */ + public function getReasons() : array + { + return $this->reasons; + } + + public function reason() : Reason + { + return 0 !== count($this->reasons) + ? current($this->reasons) + : new EmptyReason(); + } + + public function description() : string + { + $description = ''; + foreach($this->reasons as $reason) { + $description .= $reason->description() . PHP_EOL; + } + + return $description; + } + + public function code() : int + { + return 0; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Result/Reason/AtextAfterCFWS.php b/tools/mailer/egulias/email-validator/src/Result/Reason/AtextAfterCFWS.php new file mode 100644 index 000000000..96e22842f --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Result/Reason/AtextAfterCFWS.php @@ -0,0 +1,16 @@ +detailedDescription = $details; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Result/Reason/DomainAcceptsNoMail.php b/tools/mailer/egulias/email-validator/src/Result/Reason/DomainAcceptsNoMail.php new file mode 100644 index 000000000..bcaefb68a --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Result/Reason/DomainAcceptsNoMail.php @@ -0,0 +1,16 @@ +exception = $exception; + + } + public function code() : int + { + return 999; + } + + public function description() : string + { + return $this->exception->getMessage(); + } +} diff --git a/tools/mailer/egulias/email-validator/src/Result/Reason/ExpectingATEXT.php b/tools/mailer/egulias/email-validator/src/Result/Reason/ExpectingATEXT.php new file mode 100644 index 000000000..07ea8d238 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Result/Reason/ExpectingATEXT.php @@ -0,0 +1,16 @@ +detailedDescription; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Result/Reason/ExpectingCTEXT.php b/tools/mailer/egulias/email-validator/src/Result/Reason/ExpectingCTEXT.php new file mode 100644 index 000000000..64f5f7c3e --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Result/Reason/ExpectingCTEXT.php @@ -0,0 +1,16 @@ +element = $element; + } + + public function code() : int + { + return 201; + } + + public function description() : string + { + return 'Unusual element found, wourld render invalid in majority of cases. Element found: ' . $this->element; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Result/Result.php b/tools/mailer/egulias/email-validator/src/Result/Result.php new file mode 100644 index 000000000..fd13e6c68 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Result/Result.php @@ -0,0 +1,27 @@ +reason = new ReasonSpoofEmail(); + parent::__construct($this->reason, ''); + } +} diff --git a/tools/mailer/egulias/email-validator/src/Result/ValidEmail.php b/tools/mailer/egulias/email-validator/src/Result/ValidEmail.php new file mode 100644 index 000000000..fdc882fac --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Result/ValidEmail.php @@ -0,0 +1,27 @@ +dnsGetRecord = $dnsGetRecord; + } + + public function isValid(string $email, EmailLexer $emailLexer): bool + { + // use the input to check DNS if we cannot extract something similar to a domain + $host = $email; + + // Arguable pattern to extract the domain. Not aiming to validate the domain nor the email + if (false !== $lastAtPos = strrpos($email, '@')) { + $host = substr($email, $lastAtPos + 1); + } + + // Get the domain parts + $hostParts = explode('.', $host); + + $isLocalDomain = count($hostParts) <= 1; + $isReservedTopLevel = in_array($hostParts[(count($hostParts) - 1)], self::RESERVED_DNS_TOP_LEVEL_NAMES, true); + + // Exclude reserved top level DNS names + if ($isLocalDomain || $isReservedTopLevel) { + $this->error = new InvalidEmail(new LocalOrReservedDomain(), $host); + return false; + } + + return $this->checkDns($host); + } + + public function getError(): ?InvalidEmail + { + return $this->error; + } + + /** + * @return Warning[] + */ + public function getWarnings(): array + { + return $this->warnings; + } + + /** + * @param string $host + * + * @return bool + */ + protected function checkDns($host) + { + $variant = INTL_IDNA_VARIANT_UTS46; + + $host = rtrim(idn_to_ascii($host, IDNA_DEFAULT, $variant), '.'); + + $hostParts = explode('.', $host); + $host = array_pop($hostParts); + + while (count($hostParts) > 0) { + $host = array_pop($hostParts) . '.' . $host; + + if ($this->validateDnsRecords($host)) { + return true; + } + } + + return false; + } + + + /** + * Validate the DNS records for given host. + * + * @param string $host A set of DNS records in the format returned by dns_get_record. + * + * @return bool True on success. + */ + private function validateDnsRecords($host): bool + { + $dnsRecordsResult = $this->dnsGetRecord->getRecords($host, DNS_A + DNS_MX); + + if ($dnsRecordsResult->withError()) { + $this->error = new InvalidEmail(new UnableToGetDNSRecord(), ''); + return false; + } + + $dnsRecords = $dnsRecordsResult->getRecords(); + + // Combined check for A+MX+AAAA can fail with SERVFAIL, even in the presence of valid A/MX records + $aaaaRecordsResult = $this->dnsGetRecord->getRecords($host, DNS_AAAA); + + if (! $aaaaRecordsResult->withError()) { + $dnsRecords = array_merge($dnsRecords, $aaaaRecordsResult->getRecords()); + } + + // No MX, A or AAAA DNS records + if ($dnsRecords === []) { + $this->error = new InvalidEmail(new ReasonNoDNSRecord(), ''); + return false; + } + + // For each DNS record + foreach ($dnsRecords as $dnsRecord) { + if (!$this->validateMXRecord($dnsRecord)) { + // No MX records (fallback to A or AAAA records) + if (empty($this->mxRecords)) { + $this->warnings[NoDNSMXRecord::CODE] = new NoDNSMXRecord(); + } + return false; + } + } + return true; + } + + /** + * Validate an MX record + * + * @param array $dnsRecord Given DNS record. + * + * @return bool True if valid. + */ + private function validateMxRecord($dnsRecord): bool + { + if (!isset($dnsRecord['type'])) { + $this->error = new InvalidEmail(new ReasonNoDNSRecord(), ''); + return false; + } + + if ($dnsRecord['type'] !== 'MX') { + return true; + } + + // "Null MX" record indicates the domain accepts no mail (https://tools.ietf.org/html/rfc7505) + if (empty($dnsRecord['target']) || $dnsRecord['target'] === '.') { + $this->error = new InvalidEmail(new DomainAcceptsNoMail(), ""); + return false; + } + + $this->mxRecords[] = $dnsRecord; + + return true; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Validation/DNSGetRecordWrapper.php b/tools/mailer/egulias/email-validator/src/Validation/DNSGetRecordWrapper.php new file mode 100644 index 000000000..25e2fa06c --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Validation/DNSGetRecordWrapper.php @@ -0,0 +1,31 @@ +records; + } + + public function withError(): bool + { + return $this->error; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Validation/EmailValidation.php b/tools/mailer/egulias/email-validator/src/Validation/EmailValidation.php new file mode 100644 index 000000000..1bcc0a70b --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Validation/EmailValidation.php @@ -0,0 +1,34 @@ +setChecks(Spoofchecker::SINGLE_SCRIPT); + + if ($checker->isSuspicious($email)) { + $this->error = new SpoofEmail(); + } + + return $this->error === null; + } + + public function getError() : ?InvalidEmail + { + return $this->error; + } + + public function getWarnings() : array + { + return []; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Validation/MessageIDValidation.php b/tools/mailer/egulias/email-validator/src/Validation/MessageIDValidation.php new file mode 100644 index 000000000..97d1ea7a7 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Validation/MessageIDValidation.php @@ -0,0 +1,55 @@ +parse($email); + $this->warnings = $parser->getWarnings(); + if ($result->isInvalid()) { + /** @psalm-suppress PropertyTypeCoercion */ + $this->error = $result; + return false; + } + } catch (\Exception $invalid) { + $this->error = new InvalidEmail(new ExceptionFound($invalid), ''); + return false; + } + + return true; + } + + /** + * @return Warning[] + */ + public function getWarnings(): array + { + return $this->warnings; + } + + public function getError(): ?InvalidEmail + { + return $this->error; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php b/tools/mailer/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php new file mode 100644 index 000000000..c908053f3 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php @@ -0,0 +1,105 @@ +validations as $validation) { + $emailLexer->reset(); + $validationResult = $validation->isValid($email, $emailLexer); + $result = $result && $validationResult; + $this->warnings = [...$this->warnings, ...$validation->getWarnings()]; + if (!$validationResult) { + $this->processError($validation); + } + + if ($this->shouldStop($result)) { + break; + } + } + + return $result; + } + + private function initErrorStorage(): void + { + if (null === $this->error) { + $this->error = new MultipleErrors(); + } + } + + private function processError(EmailValidation $validation): void + { + if (null !== $validation->getError()) { + $this->initErrorStorage(); + /** @psalm-suppress PossiblyNullReference */ + $this->error->addReason($validation->getError()->reason()); + } + } + + private function shouldStop(bool $result): bool + { + return !$result && $this->mode === self::STOP_ON_ERROR; + } + + /** + * Returns the validation errors. + */ + public function getError(): ?InvalidEmail + { + return $this->error; + } + + /** + * @return Warning[] + */ + public function getWarnings(): array + { + return $this->warnings; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Validation/NoRFCWarningsValidation.php b/tools/mailer/egulias/email-validator/src/Validation/NoRFCWarningsValidation.php new file mode 100644 index 000000000..06885ed71 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Validation/NoRFCWarningsValidation.php @@ -0,0 +1,41 @@ +getWarnings())) { + return true; + } + + $this->error = new InvalidEmail(new RFCWarnings(), ''); + + return false; + } + + /** + * {@inheritdoc} + */ + public function getError() : ?InvalidEmail + { + return $this->error ?: parent::getError(); + } +} diff --git a/tools/mailer/egulias/email-validator/src/Validation/RFCValidation.php b/tools/mailer/egulias/email-validator/src/Validation/RFCValidation.php new file mode 100644 index 000000000..f59cbfc80 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Validation/RFCValidation.php @@ -0,0 +1,54 @@ +parse($email); + $this->warnings = $parser->getWarnings(); + if ($result->isInvalid()) { + /** @psalm-suppress PropertyTypeCoercion */ + $this->error = $result; + return false; + } + } catch (\Exception $invalid) { + $this->error = new InvalidEmail(new ExceptionFound($invalid), ''); + return false; + } + + return true; + } + + public function getError(): ?InvalidEmail + { + return $this->error; + } + + /** + * @return Warning[] + */ + public function getWarnings(): array + { + return $this->warnings; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/AddressLiteral.php b/tools/mailer/egulias/email-validator/src/Warning/AddressLiteral.php new file mode 100644 index 000000000..474ff0e75 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/AddressLiteral.php @@ -0,0 +1,14 @@ +message = 'Address literal in domain part'; + $this->rfcNumber = 5321; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/CFWSNearAt.php b/tools/mailer/egulias/email-validator/src/Warning/CFWSNearAt.php new file mode 100644 index 000000000..8bac12b1e --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/CFWSNearAt.php @@ -0,0 +1,13 @@ +message = "Deprecated folding white space near @"; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/CFWSWithFWS.php b/tools/mailer/egulias/email-validator/src/Warning/CFWSWithFWS.php new file mode 100644 index 000000000..ba57601c8 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/CFWSWithFWS.php @@ -0,0 +1,13 @@ +message = 'Folding whites space followed by folding white space'; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/Comment.php b/tools/mailer/egulias/email-validator/src/Warning/Comment.php new file mode 100644 index 000000000..6508295e3 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/Comment.php @@ -0,0 +1,13 @@ +message = "Comments found in this email"; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/DeprecatedComment.php b/tools/mailer/egulias/email-validator/src/Warning/DeprecatedComment.php new file mode 100644 index 000000000..a2578076e --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/DeprecatedComment.php @@ -0,0 +1,13 @@ +message = 'Deprecated comments'; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/DomainLiteral.php b/tools/mailer/egulias/email-validator/src/Warning/DomainLiteral.php new file mode 100644 index 000000000..034388c47 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/DomainLiteral.php @@ -0,0 +1,14 @@ +message = 'Domain Literal'; + $this->rfcNumber = 5322; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/EmailTooLong.php b/tools/mailer/egulias/email-validator/src/Warning/EmailTooLong.php new file mode 100644 index 000000000..d25ad1234 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/EmailTooLong.php @@ -0,0 +1,15 @@ +message = 'Email is too long, exceeds ' . EmailParser::EMAIL_MAX_LENGTH; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/IPV6BadChar.php b/tools/mailer/egulias/email-validator/src/Warning/IPV6BadChar.php new file mode 100644 index 000000000..3ecd5bcca --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/IPV6BadChar.php @@ -0,0 +1,14 @@ +message = 'Bad char in IPV6 domain literal'; + $this->rfcNumber = 5322; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/IPV6ColonEnd.php b/tools/mailer/egulias/email-validator/src/Warning/IPV6ColonEnd.php new file mode 100644 index 000000000..3f0c2f2df --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/IPV6ColonEnd.php @@ -0,0 +1,14 @@ +message = ':: found at the end of the domain literal'; + $this->rfcNumber = 5322; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/IPV6ColonStart.php b/tools/mailer/egulias/email-validator/src/Warning/IPV6ColonStart.php new file mode 100644 index 000000000..742fb3bd1 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/IPV6ColonStart.php @@ -0,0 +1,14 @@ +message = ':: found at the start of the domain literal'; + $this->rfcNumber = 5322; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/IPV6Deprecated.php b/tools/mailer/egulias/email-validator/src/Warning/IPV6Deprecated.php new file mode 100644 index 000000000..59c3037a5 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/IPV6Deprecated.php @@ -0,0 +1,14 @@ +message = 'Deprecated form of IPV6'; + $this->rfcNumber = 5321; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/IPV6DoubleColon.php b/tools/mailer/egulias/email-validator/src/Warning/IPV6DoubleColon.php new file mode 100644 index 000000000..d40660264 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/IPV6DoubleColon.php @@ -0,0 +1,14 @@ +message = 'Double colon found after IPV6 tag'; + $this->rfcNumber = 5322; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/IPV6GroupCount.php b/tools/mailer/egulias/email-validator/src/Warning/IPV6GroupCount.php new file mode 100644 index 000000000..551bc3af1 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/IPV6GroupCount.php @@ -0,0 +1,14 @@ +message = 'Group count is not IPV6 valid'; + $this->rfcNumber = 5322; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/IPV6MaxGroups.php b/tools/mailer/egulias/email-validator/src/Warning/IPV6MaxGroups.php new file mode 100644 index 000000000..7f8a410a8 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/IPV6MaxGroups.php @@ -0,0 +1,14 @@ +message = 'Reached the maximum number of IPV6 groups allowed'; + $this->rfcNumber = 5321; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/LocalTooLong.php b/tools/mailer/egulias/email-validator/src/Warning/LocalTooLong.php new file mode 100644 index 000000000..b46b874c0 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/LocalTooLong.php @@ -0,0 +1,15 @@ +message = 'Local part is too long, exceeds 64 chars (octets)'; + $this->rfcNumber = 5322; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/NoDNSMXRecord.php b/tools/mailer/egulias/email-validator/src/Warning/NoDNSMXRecord.php new file mode 100644 index 000000000..bddb96be7 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/NoDNSMXRecord.php @@ -0,0 +1,14 @@ +message = 'No MX DSN record was found for this email'; + $this->rfcNumber = 5321; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/ObsoleteDTEXT.php b/tools/mailer/egulias/email-validator/src/Warning/ObsoleteDTEXT.php new file mode 100644 index 000000000..412fd499e --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/ObsoleteDTEXT.php @@ -0,0 +1,14 @@ +rfcNumber = 5322; + $this->message = 'Obsolete DTEXT in domain literal'; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/QuotedPart.php b/tools/mailer/egulias/email-validator/src/Warning/QuotedPart.php new file mode 100644 index 000000000..c3e017d94 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/QuotedPart.php @@ -0,0 +1,17 @@ +message = "Deprecated Quoted String found between $prevToken and $postToken"; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/QuotedString.php b/tools/mailer/egulias/email-validator/src/Warning/QuotedString.php new file mode 100644 index 000000000..c152ec2e2 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/QuotedString.php @@ -0,0 +1,17 @@ +message = "Quoted String found between $prevToken and $postToken"; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/TLD.php b/tools/mailer/egulias/email-validator/src/Warning/TLD.php new file mode 100644 index 000000000..10cec2816 --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/TLD.php @@ -0,0 +1,13 @@ +message = "RFC5321, TLD"; + } +} diff --git a/tools/mailer/egulias/email-validator/src/Warning/Warning.php b/tools/mailer/egulias/email-validator/src/Warning/Warning.php new file mode 100644 index 000000000..7adb3b85c --- /dev/null +++ b/tools/mailer/egulias/email-validator/src/Warning/Warning.php @@ -0,0 +1,53 @@ +message; + } + + /** + * @return int + */ + public function code() + { + return self::CODE; + } + + /** + * @return int + */ + public function RFCNumber() + { + return $this->rfcNumber; + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->message() . " rfc: " . $this->rfcNumber . "internal code: " . static::CODE; + } +} diff --git a/tools/mailer/psr/container/.gitignore b/tools/mailer/psr/container/.gitignore new file mode 100644 index 000000000..b2395aa05 --- /dev/null +++ b/tools/mailer/psr/container/.gitignore @@ -0,0 +1,3 @@ +composer.lock +composer.phar +/vendor/ diff --git a/tools/mailer/psr/container/LICENSE b/tools/mailer/psr/container/LICENSE new file mode 100644 index 000000000..2877a4894 --- /dev/null +++ b/tools/mailer/psr/container/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2016 container-interop +Copyright (c) 2016 PHP Framework Interoperability Group + +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/tools/mailer/psr/container/README.md b/tools/mailer/psr/container/README.md new file mode 100644 index 000000000..1b9d9e570 --- /dev/null +++ b/tools/mailer/psr/container/README.md @@ -0,0 +1,13 @@ +Container interface +============== + +This repository holds all interfaces related to [PSR-11 (Container Interface)][psr-url]. + +Note that this is not a Container implementation of its own. It is merely abstractions that describe the components of a Dependency Injection Container. + +The installable [package][package-url] and [implementations][implementation-url] are listed on Packagist. + +[psr-url]: https://www.php-fig.org/psr/psr-11/ +[package-url]: https://packagist.org/packages/psr/container +[implementation-url]: https://packagist.org/providers/psr/container-implementation + diff --git a/tools/mailer/psr/container/composer.json b/tools/mailer/psr/container/composer.json new file mode 100644 index 000000000..baf6cd1a0 --- /dev/null +++ b/tools/mailer/psr/container/composer.json @@ -0,0 +1,27 @@ +{ + "name": "psr/container", + "type": "library", + "description": "Common Container Interface (PHP FIG PSR-11)", + "keywords": ["psr", "psr-11", "container", "container-interop", "container-interface"], + "homepage": "https://github.com/php-fig/container", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=7.4.0" + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + } +} diff --git a/tools/mailer/psr/container/src/ContainerExceptionInterface.php b/tools/mailer/psr/container/src/ContainerExceptionInterface.php new file mode 100644 index 000000000..0f213f2fe --- /dev/null +++ b/tools/mailer/psr/container/src/ContainerExceptionInterface.php @@ -0,0 +1,12 @@ +=7.2.0" + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/tools/mailer/psr/event-dispatcher/src/EventDispatcherInterface.php b/tools/mailer/psr/event-dispatcher/src/EventDispatcherInterface.php new file mode 100644 index 000000000..4306fa915 --- /dev/null +++ b/tools/mailer/psr/event-dispatcher/src/EventDispatcherInterface.php @@ -0,0 +1,21 @@ +logger = $logger; + } + + public function doSomething() + { + if ($this->logger) { + $this->logger->info('Doing work'); + } + + try { + $this->doSomethingElse(); + } catch (Exception $exception) { + $this->logger->error('Oh no!', array('exception' => $exception)); + } + + // do something useful + } +} +``` + +You can then pick one of the implementations of the interface to get a logger. + +If you want to implement the interface, you can require this package and +implement `Psr\Log\LoggerInterface` in your code. Please read the +[specification text](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) +for details. diff --git a/tools/mailer/psr/log/composer.json b/tools/mailer/psr/log/composer.json new file mode 100644 index 000000000..879fc6f53 --- /dev/null +++ b/tools/mailer/psr/log/composer.json @@ -0,0 +1,26 @@ +{ + "name": "psr/log", + "description": "Common interface for logging libraries", + "keywords": ["psr", "psr-3", "log"], + "homepage": "https://github.com/php-fig/log", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=8.0.0" + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + } +} diff --git a/tools/mailer/psr/log/src/AbstractLogger.php b/tools/mailer/psr/log/src/AbstractLogger.php new file mode 100644 index 000000000..d60a091af --- /dev/null +++ b/tools/mailer/psr/log/src/AbstractLogger.php @@ -0,0 +1,15 @@ +logger = $logger; + } +} diff --git a/tools/mailer/psr/log/src/LoggerInterface.php b/tools/mailer/psr/log/src/LoggerInterface.php new file mode 100644 index 000000000..cb4cf648b --- /dev/null +++ b/tools/mailer/psr/log/src/LoggerInterface.php @@ -0,0 +1,98 @@ +log(LogLevel::EMERGENCY, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + */ + public function alert(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::ALERT, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + */ + public function critical(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + */ + public function error(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + */ + public function warning(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::WARNING, $message, $context); + } + + /** + * Normal but significant events. + */ + public function notice(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::NOTICE, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + */ + public function info(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::INFO, $message, $context); + } + + /** + * Detailed debug information. + */ + public function debug(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::DEBUG, $message, $context); + } + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * + * @throws \Psr\Log\InvalidArgumentException + */ + abstract public function log($level, string|\Stringable $message, array $context = []): void; +} diff --git a/tools/mailer/psr/log/src/NullLogger.php b/tools/mailer/psr/log/src/NullLogger.php new file mode 100644 index 000000000..de0561e2a --- /dev/null +++ b/tools/mailer/psr/log/src/NullLogger.php @@ -0,0 +1,26 @@ +logger) { }` + * blocks. + */ +class NullLogger extends AbstractLogger +{ + /** + * Logs with an arbitrary level. + * + * @param mixed[] $context + * + * @throws \Psr\Log\InvalidArgumentException + */ + public function log($level, string|\Stringable $message, array $context = []): void + { + // noop + } +} diff --git a/tools/mailer/symfony/deprecation-contracts/CHANGELOG.md b/tools/mailer/symfony/deprecation-contracts/CHANGELOG.md new file mode 100644 index 000000000..7932e2613 --- /dev/null +++ b/tools/mailer/symfony/deprecation-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/tools/swift/LICENSE b/tools/mailer/symfony/deprecation-contracts/LICENSE similarity index 95% rename from tools/swift/LICENSE rename to tools/mailer/symfony/deprecation-contracts/LICENSE index 485f1d6d6..0ed3a2465 100644 --- a/tools/swift/LICENSE +++ b/tools/mailer/symfony/deprecation-contracts/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013-2016 Fabien Potencier +Copyright (c) 2020-present Fabien Potencier 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/tools/mailer/symfony/deprecation-contracts/README.md b/tools/mailer/symfony/deprecation-contracts/README.md new file mode 100644 index 000000000..9814864c0 --- /dev/null +++ b/tools/mailer/symfony/deprecation-contracts/README.md @@ -0,0 +1,26 @@ +Symfony Deprecation Contracts +============================= + +A generic function and convention to trigger deprecation notices. + +This package provides a single global function named `trigger_deprecation()` that triggers silenced deprecation notices. + +By using a custom PHP error handler such as the one provided by the Symfony ErrorHandler component, +the triggered deprecations can be caught and logged for later discovery, both on dev and prod environments. + +The function requires at least 3 arguments: + - the name of the Composer package that is triggering the deprecation + - the version of the package that introduced the deprecation + - the message of the deprecation + - more arguments can be provided: they will be inserted in the message using `printf()` formatting + +Example: +```php +trigger_deprecation('symfony/blockchain', '8.9', 'Using "%s" is deprecated, use "%s" instead.', 'bitcoin', 'fabcoin'); +``` + +This will generate the following message: +`Since symfony/blockchain 8.9: Using "bitcoin" is deprecated, use "fabcoin" instead.` + +While not recommended, the deprecation notices can be completely ignored by declaring an empty +`function trigger_deprecation() {}` in your application. diff --git a/tools/mailer/symfony/deprecation-contracts/composer.json b/tools/mailer/symfony/deprecation-contracts/composer.json new file mode 100644 index 000000000..ceb6c0796 --- /dev/null +++ b/tools/mailer/symfony/deprecation-contracts/composer.json @@ -0,0 +1,35 @@ +{ + "name": "symfony/deprecation-contracts", + "type": "library", + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.1" + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/tools/mailer/symfony/deprecation-contracts/function.php b/tools/mailer/symfony/deprecation-contracts/function.php new file mode 100644 index 000000000..2d56512ba --- /dev/null +++ b/tools/mailer/symfony/deprecation-contracts/function.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (!function_exists('trigger_deprecation')) { + /** + * Triggers a silenced deprecation notice. + * + * @param string $package The name of the Composer package that is triggering the deprecation + * @param string $version The version of the package that introduced the deprecation + * @param string $message The message of the deprecation + * @param mixed ...$args Values to insert in the message using printf() formatting + * + * @author Nicolas Grekas + */ + function trigger_deprecation(string $package, string $version, string $message, mixed ...$args): void + { + @trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED); + } +} diff --git a/tools/mailer/symfony/event-dispatcher-contracts/CHANGELOG.md b/tools/mailer/symfony/event-dispatcher-contracts/CHANGELOG.md new file mode 100644 index 000000000..7932e2613 --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/tools/mailer/symfony/event-dispatcher-contracts/Event.php b/tools/mailer/symfony/event-dispatcher-contracts/Event.php new file mode 100644 index 000000000..2e7f99890 --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher-contracts/Event.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\EventDispatcher; + +use Psr\EventDispatcher\StoppableEventInterface; + +/** + * Event is the base class for classes containing event data. + * + * This class contains no event data. It is used by events that do not pass + * state information to an event handler when an event is raised. + * + * You can call the method stopPropagation() to abort the execution of + * further listeners in your event listener. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + * @author Nicolas Grekas + */ +class Event implements StoppableEventInterface +{ + private bool $propagationStopped = false; + + public function isPropagationStopped(): bool + { + return $this->propagationStopped; + } + + /** + * Stops the propagation of the event to further event listeners. + * + * If multiple event listeners are connected to the same event, no + * further event listener will be triggered once any trigger calls + * stopPropagation(). + */ + public function stopPropagation(): void + { + $this->propagationStopped = true; + } +} diff --git a/tools/mailer/symfony/event-dispatcher-contracts/EventDispatcherInterface.php b/tools/mailer/symfony/event-dispatcher-contracts/EventDispatcherInterface.php new file mode 100644 index 000000000..2d7840d32 --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher-contracts/EventDispatcherInterface.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\EventDispatcher; + +use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface; + +/** + * Allows providing hooks on domain-specific lifecycles by dispatching events. + */ +interface EventDispatcherInterface extends PsrEventDispatcherInterface +{ + /** + * Dispatches an event to all registered listeners. + * + * @template T of object + * + * @param T $event The event to pass to the event handlers/listeners + * @param string|null $eventName The name of the event to dispatch. If not supplied, + * the class of $event should be used instead. + * + * @return T The passed $event MUST be returned + */ + public function dispatch(object $event, ?string $eventName = null): object; +} diff --git a/tools/mailer/symfony/event-dispatcher-contracts/LICENSE b/tools/mailer/symfony/event-dispatcher-contracts/LICENSE new file mode 100644 index 000000000..7536caeae --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-present Fabien Potencier + +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/tools/mailer/symfony/event-dispatcher-contracts/README.md b/tools/mailer/symfony/event-dispatcher-contracts/README.md new file mode 100644 index 000000000..332b961cb --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher-contracts/README.md @@ -0,0 +1,9 @@ +Symfony EventDispatcher Contracts +================================= + +A set of abstractions extracted out of the Symfony components. + +Can be used to build on semantics that the Symfony components proved useful and +that already have battle tested implementations. + +See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/tools/mailer/symfony/event-dispatcher-contracts/composer.json b/tools/mailer/symfony/event-dispatcher-contracts/composer.json new file mode 100644 index 000000000..35956eb80 --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher-contracts/composer.json @@ -0,0 +1,35 @@ +{ + "name": "symfony/event-dispatcher-contracts", + "type": "library", + "description": "Generic abstractions related to dispatching event", + "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "autoload": { + "psr-4": { "Symfony\\Contracts\\EventDispatcher\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/tools/mailer/symfony/event-dispatcher/Attribute/AsEventListener.php b/tools/mailer/symfony/event-dispatcher/Attribute/AsEventListener.php new file mode 100644 index 000000000..590ada9e8 --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher/Attribute/AsEventListener.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Attribute; + +/** + * Service tag to autoconfigure event listeners. + * + * @author Alexander M. Turek + */ +#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] +class AsEventListener +{ + /** + * @param string|null $event The event name to listen to + * @param string|null $method The method to run when the listened event is triggered + * @param int $priority The priority of this listener if several are declared for the same event + * @param string|null $dispatcher The service id of the event dispatcher to listen to + */ + public function __construct( + public ?string $event = null, + public ?string $method = null, + public int $priority = 0, + public ?string $dispatcher = null, + ) { + } +} diff --git a/tools/mailer/symfony/event-dispatcher/CHANGELOG.md b/tools/mailer/symfony/event-dispatcher/CHANGELOG.md new file mode 100644 index 000000000..76b2eab6b --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher/CHANGELOG.md @@ -0,0 +1,96 @@ +CHANGELOG +========= + +6.0 +--- + + * Remove `LegacyEventDispatcherProxy` + +5.4 +--- + + * Allow `#[AsEventListener]` attribute on methods + +5.3 +--- + + * Add `#[AsEventListener]` attribute for declaring listeners on PHP 8 + +5.1.0 +----- + + * The `LegacyEventDispatcherProxy` class has been deprecated. + * Added an optional `dispatcher` attribute to the listener and subscriber tags in `RegisterListenerPass`. + +5.0.0 +----- + + * The signature of the `EventDispatcherInterface::dispatch()` method has been changed to `dispatch($event, string $eventName = null): object`. + * The `Event` class has been removed in favor of `Symfony\Contracts\EventDispatcher\Event`. + * The `TraceableEventDispatcherInterface` has been removed. + * The `WrappedListener` class is now final. + +4.4.0 +----- + + * `AddEventAliasesPass` has been added, allowing applications and bundles to extend the event alias mapping used by `RegisterListenersPass`. + * Made the `event` attribute of the `kernel.event_listener` tag optional for FQCN events. + +4.3.0 +----- + + * The signature of the `EventDispatcherInterface::dispatch()` method should be updated to `dispatch($event, string $eventName = null)`, not doing so is deprecated + * deprecated the `Event` class, use `Symfony\Contracts\EventDispatcher\Event` instead + +4.1.0 +----- + + * added support for invokable event listeners tagged with `kernel.event_listener` by default + * The `TraceableEventDispatcher::getOrphanedEvents()` method has been added. + * The `TraceableEventDispatcherInterface` has been deprecated. + +4.0.0 +----- + + * removed the `ContainerAwareEventDispatcher` class + * added the `reset()` method to the `TraceableEventDispatcherInterface` + +3.4.0 +----- + + * Implementing `TraceableEventDispatcherInterface` without the `reset()` method has been deprecated. + +3.3.0 +----- + + * The ContainerAwareEventDispatcher class has been deprecated. Use EventDispatcher with closure factories instead. + +3.0.0 +----- + + * The method `getListenerPriority($eventName, $listener)` has been added to the + `EventDispatcherInterface`. + * The methods `Event::setDispatcher()`, `Event::getDispatcher()`, `Event::setName()` + and `Event::getName()` have been removed. + The event dispatcher and the event name are passed to the listener call. + +2.5.0 +----- + + * added Debug\TraceableEventDispatcher (originally in HttpKernel) + * changed Debug\TraceableEventDispatcherInterface to extend EventDispatcherInterface + * added RegisterListenersPass (originally in HttpKernel) + +2.1.0 +----- + + * added TraceableEventDispatcherInterface + * added ContainerAwareEventDispatcher + * added a reference to the EventDispatcher on the Event + * added a reference to the Event name on the event + * added fluid interface to the dispatch() method which now returns the Event + object + * added GenericEvent event class + * added the possibility for subscribers to subscribe several times for the + same event + * added ImmutableEventDispatcher diff --git a/tools/mailer/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php b/tools/mailer/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php new file mode 100644 index 000000000..72ce52658 --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php @@ -0,0 +1,351 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Debug; + +use Psr\EventDispatcher\StoppableEventInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Contracts\Service\ResetInterface; + +/** + * Collects some data about event listeners. + * + * This event dispatcher delegates the dispatching to another one. + * + * @author Fabien Potencier + */ +class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterface +{ + /** + * @var \SplObjectStorage|null + */ + private ?\SplObjectStorage $callStack = null; + private array $wrappedListeners = []; + private array $orphanedEvents = []; + private string $currentRequestHash = ''; + + public function __construct( + private EventDispatcherInterface $dispatcher, + protected Stopwatch $stopwatch, + protected ?LoggerInterface $logger = null, + private ?RequestStack $requestStack = null, + ) { + } + + public function addListener(string $eventName, callable|array $listener, int $priority = 0): void + { + $this->dispatcher->addListener($eventName, $listener, $priority); + } + + public function addSubscriber(EventSubscriberInterface $subscriber): void + { + $this->dispatcher->addSubscriber($subscriber); + } + + public function removeListener(string $eventName, callable|array $listener): void + { + if (isset($this->wrappedListeners[$eventName])) { + foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) { + if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) { + $listener = $wrappedListener; + unset($this->wrappedListeners[$eventName][$index]); + break; + } + } + } + + $this->dispatcher->removeListener($eventName, $listener); + } + + public function removeSubscriber(EventSubscriberInterface $subscriber): void + { + $this->dispatcher->removeSubscriber($subscriber); + } + + public function getListeners(?string $eventName = null): array + { + return $this->dispatcher->getListeners($eventName); + } + + public function getListenerPriority(string $eventName, callable|array $listener): ?int + { + // we might have wrapped listeners for the event (if called while dispatching) + // in that case get the priority by wrapper + if (isset($this->wrappedListeners[$eventName])) { + foreach ($this->wrappedListeners[$eventName] as $wrappedListener) { + if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) { + return $this->dispatcher->getListenerPriority($eventName, $wrappedListener); + } + } + } + + return $this->dispatcher->getListenerPriority($eventName, $listener); + } + + public function hasListeners(?string $eventName = null): bool + { + return $this->dispatcher->hasListeners($eventName); + } + + public function dispatch(object $event, ?string $eventName = null): object + { + $eventName ??= $event::class; + + $this->callStack ??= new \SplObjectStorage(); + + $currentRequestHash = $this->currentRequestHash = $this->requestStack && ($request = $this->requestStack->getCurrentRequest()) ? spl_object_hash($request) : ''; + + if (null !== $this->logger && $event instanceof StoppableEventInterface && $event->isPropagationStopped()) { + $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName)); + } + + $this->preProcess($eventName); + try { + $this->beforeDispatch($eventName, $event); + try { + $e = $this->stopwatch->start($eventName, 'section'); + try { + $this->dispatcher->dispatch($event, $eventName); + } finally { + if ($e->isStarted()) { + $e->stop(); + } + } + } finally { + $this->afterDispatch($eventName, $event); + } + } finally { + $this->currentRequestHash = $currentRequestHash; + $this->postProcess($eventName); + } + + return $event; + } + + public function getCalledListeners(?Request $request = null): array + { + if (null === $this->callStack) { + return []; + } + + $hash = $request ? spl_object_hash($request) : null; + $called = []; + foreach ($this->callStack as $listener) { + [$eventName, $requestHash] = $this->callStack->getInfo(); + if (null === $hash || $hash === $requestHash) { + $called[] = $listener->getInfo($eventName); + } + } + + return $called; + } + + public function getNotCalledListeners(?Request $request = null): array + { + try { + $allListeners = $this->dispatcher instanceof EventDispatcher ? $this->getListenersWithPriority() : $this->getListenersWithoutPriority(); + } catch (\Exception $e) { + $this->logger?->info('An exception was thrown while getting the uncalled listeners.', ['exception' => $e]); + + // unable to retrieve the uncalled listeners + return []; + } + + $hash = $request ? spl_object_hash($request) : null; + $calledListeners = []; + + if (null !== $this->callStack) { + foreach ($this->callStack as $calledListener) { + [, $requestHash] = $this->callStack->getInfo(); + + if (null === $hash || $hash === $requestHash) { + $calledListeners[] = $calledListener->getWrappedListener(); + } + } + } + + $notCalled = []; + + foreach ($allListeners as $eventName => $listeners) { + foreach ($listeners as [$listener, $priority]) { + if (!\in_array($listener, $calledListeners, true)) { + if (!$listener instanceof WrappedListener) { + $listener = new WrappedListener($listener, null, $this->stopwatch, $this, $priority); + } + $notCalled[] = $listener->getInfo($eventName); + } + } + } + + uasort($notCalled, $this->sortNotCalledListeners(...)); + + return $notCalled; + } + + public function getOrphanedEvents(?Request $request = null): array + { + if ($request) { + return $this->orphanedEvents[spl_object_hash($request)] ?? []; + } + + if (!$this->orphanedEvents) { + return []; + } + + return array_merge(...array_values($this->orphanedEvents)); + } + + public function reset(): void + { + $this->callStack = null; + $this->orphanedEvents = []; + $this->currentRequestHash = ''; + } + + /** + * Proxies all method calls to the original event dispatcher. + * + * @param string $method The method name + * @param array $arguments The method arguments + */ + public function __call(string $method, array $arguments): mixed + { + return $this->dispatcher->{$method}(...$arguments); + } + + /** + * Called before dispatching the event. + */ + protected function beforeDispatch(string $eventName, object $event): void + { + } + + /** + * Called after dispatching the event. + */ + protected function afterDispatch(string $eventName, object $event): void + { + } + + private function preProcess(string $eventName): void + { + if (!$this->dispatcher->hasListeners($eventName)) { + $this->orphanedEvents[$this->currentRequestHash][] = $eventName; + + return; + } + + foreach ($this->dispatcher->getListeners($eventName) as $listener) { + $priority = $this->getListenerPriority($eventName, $listener); + $wrappedListener = new WrappedListener($listener instanceof WrappedListener ? $listener->getWrappedListener() : $listener, null, $this->stopwatch, $this); + $this->wrappedListeners[$eventName][] = $wrappedListener; + $this->dispatcher->removeListener($eventName, $listener); + $this->dispatcher->addListener($eventName, $wrappedListener, $priority); + $this->callStack->attach($wrappedListener, [$eventName, $this->currentRequestHash]); + } + } + + private function postProcess(string $eventName): void + { + unset($this->wrappedListeners[$eventName]); + $skipped = false; + foreach ($this->dispatcher->getListeners($eventName) as $listener) { + if (!$listener instanceof WrappedListener) { // #12845: a new listener was added during dispatch. + continue; + } + // Unwrap listener + $priority = $this->getListenerPriority($eventName, $listener); + $this->dispatcher->removeListener($eventName, $listener); + $this->dispatcher->addListener($eventName, $listener->getWrappedListener(), $priority); + + if (null !== $this->logger) { + $context = ['event' => $eventName, 'listener' => $listener->getPretty()]; + } + + if ($listener->wasCalled()) { + $this->logger?->debug('Notified event "{event}" to listener "{listener}".', $context); + } else { + $this->callStack->detach($listener); + } + + if (null !== $this->logger && $skipped) { + $this->logger->debug('Listener "{listener}" was not called for event "{event}".', $context); + } + + if ($listener->stoppedPropagation()) { + $this->logger?->debug('Listener "{listener}" stopped propagation of the event "{event}".', $context); + + $skipped = true; + } + } + } + + private function sortNotCalledListeners(array $a, array $b): int + { + if (0 !== $cmp = strcmp($a['event'], $b['event'])) { + return $cmp; + } + + if (\is_int($a['priority']) && !\is_int($b['priority'])) { + return 1; + } + + if (!\is_int($a['priority']) && \is_int($b['priority'])) { + return -1; + } + + if ($a['priority'] === $b['priority']) { + return 0; + } + + if ($a['priority'] > $b['priority']) { + return -1; + } + + return 1; + } + + private function getListenersWithPriority(): array + { + $result = []; + + $allListeners = new \ReflectionProperty(EventDispatcher::class, 'listeners'); + + foreach ($allListeners->getValue($this->dispatcher) as $eventName => $listenersByPriority) { + foreach ($listenersByPriority as $priority => $listeners) { + foreach ($listeners as $listener) { + $result[$eventName][] = [$listener, $priority]; + } + } + } + + return $result; + } + + private function getListenersWithoutPriority(): array + { + $result = []; + + foreach ($this->getListeners() as $eventName => $listeners) { + foreach ($listeners as $listener) { + $result[$eventName][] = [$listener, null]; + } + } + + return $result; + } +} diff --git a/tools/mailer/symfony/event-dispatcher/Debug/WrappedListener.php b/tools/mailer/symfony/event-dispatcher/Debug/WrappedListener.php new file mode 100644 index 000000000..b83115bbe --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher/Debug/WrappedListener.php @@ -0,0 +1,143 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Debug; + +use Psr\EventDispatcher\StoppableEventInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Component\VarDumper\Caster\ClassStub; + +/** + * @author Fabien Potencier + */ +final class WrappedListener +{ + private string|array|object $listener; + private ?\Closure $optimizedListener; + private string $name; + private bool $called = false; + private bool $stoppedPropagation = false; + private string $pretty; + private string $callableRef; + private ClassStub|string $stub; + private static bool $hasClassStub; + + public function __construct( + callable|array $listener, + ?string $name, + private Stopwatch $stopwatch, + private ?EventDispatcherInterface $dispatcher = null, + private ?int $priority = null, + ) { + $this->listener = $listener; + $this->optimizedListener = $listener instanceof \Closure ? $listener : (\is_callable($listener) ? $listener(...) : null); + + if (\is_array($listener)) { + [$this->name, $this->callableRef] = $this->parseListener($listener); + $this->pretty = $this->name.'::'.$listener[1]; + $this->callableRef .= '::'.$listener[1]; + } elseif ($listener instanceof \Closure) { + $r = new \ReflectionFunction($listener); + if ($r->isAnonymous()) { + $this->pretty = $this->name = 'closure'; + } elseif ($class = $r->getClosureCalledClass()) { + $this->name = $class->name; + $this->pretty = $this->name.'::'.$r->name; + } else { + $this->pretty = $this->name = $r->name; + } + } elseif (\is_string($listener)) { + $this->pretty = $this->name = $listener; + } else { + $this->name = get_debug_type($listener); + $this->pretty = $this->name.'::__invoke'; + $this->callableRef = $listener::class.'::__invoke'; + } + + if (null !== $name) { + $this->name = $name; + } + + self::$hasClassStub ??= class_exists(ClassStub::class); + } + + public function getWrappedListener(): callable|array + { + return $this->listener; + } + + public function wasCalled(): bool + { + return $this->called; + } + + public function stoppedPropagation(): bool + { + return $this->stoppedPropagation; + } + + public function getPretty(): string + { + return $this->pretty; + } + + public function getInfo(string $eventName): array + { + $this->stub ??= self::$hasClassStub ? new ClassStub($this->pretty.'()', $this->callableRef ?? $this->listener) : $this->pretty.'()'; + + return [ + 'event' => $eventName, + 'priority' => $this->priority ??= $this->dispatcher?->getListenerPriority($eventName, $this->listener), + 'pretty' => $this->pretty, + 'stub' => $this->stub, + ]; + } + + public function __invoke(object $event, string $eventName, EventDispatcherInterface $dispatcher): void + { + $dispatcher = $this->dispatcher ?: $dispatcher; + + $this->called = true; + $this->priority ??= $dispatcher->getListenerPriority($eventName, $this->listener); + + $e = $this->stopwatch->start($this->name, 'event_listener'); + + try { + ($this->optimizedListener ?? $this->listener)($event, $eventName, $dispatcher); + } finally { + if ($e->isStarted()) { + $e->stop(); + } + } + + if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) { + $this->stoppedPropagation = true; + } + } + + private function parseListener(array $listener): array + { + if ($listener[0] instanceof \Closure) { + foreach ((new \ReflectionFunction($listener[0]))->getAttributes(\Closure::class) as $attribute) { + if ($name = $attribute->getArguments()['name'] ?? false) { + return [$name, $attribute->getArguments()['class'] ?? $name]; + } + } + } + + if (\is_object($listener[0])) { + return [get_debug_type($listener[0]), $listener[0]::class]; + } + + return [$listener[0], $listener[0]]; + } +} diff --git a/tools/mailer/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php b/tools/mailer/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php new file mode 100644 index 000000000..530899201 --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * This pass allows bundles to extend the list of event aliases. + * + * @author Alexander M. Turek + */ +class AddEventAliasesPass implements CompilerPassInterface +{ + public function __construct( + private array $eventAliases, + ) { + } + + public function process(ContainerBuilder $container): void + { + $eventAliases = $container->hasParameter('event_dispatcher.event_aliases') ? $container->getParameter('event_dispatcher.event_aliases') : []; + + $container->setParameter( + 'event_dispatcher.event_aliases', + array_merge($eventAliases, $this->eventAliases) + ); + } +} diff --git a/tools/mailer/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php b/tools/mailer/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php new file mode 100644 index 000000000..29a76bbc7 --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php @@ -0,0 +1,213 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\DependencyInjection; + +use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Contracts\EventDispatcher\Event; + +/** + * Compiler pass to register tagged services for an event dispatcher. + */ +class RegisterListenersPass implements CompilerPassInterface +{ + private array $hotPathEvents = []; + private array $noPreloadEvents = []; + + /** + * @return $this + */ + public function setHotPathEvents(array $hotPathEvents): static + { + $this->hotPathEvents = array_flip($hotPathEvents); + + return $this; + } + + /** + * @return $this + */ + public function setNoPreloadEvents(array $noPreloadEvents): static + { + $this->noPreloadEvents = array_flip($noPreloadEvents); + + return $this; + } + + public function process(ContainerBuilder $container): void + { + if (!$container->hasDefinition('event_dispatcher') && !$container->hasAlias('event_dispatcher')) { + return; + } + + $aliases = []; + + if ($container->hasParameter('event_dispatcher.event_aliases')) { + $aliases = $container->getParameter('event_dispatcher.event_aliases'); + } + + $globalDispatcherDefinition = $container->findDefinition('event_dispatcher'); + + foreach ($container->findTaggedServiceIds('kernel.event_listener', true) as $id => $events) { + $noPreload = 0; + + foreach ($events as $event) { + $priority = $event['priority'] ?? 0; + + if (!isset($event['event'])) { + if ($container->getDefinition($id)->hasTag('kernel.event_subscriber')) { + continue; + } + + $event['method'] ??= '__invoke'; + $event['event'] = $this->getEventFromTypeDeclaration($container, $id, $event['method']); + } + + $event['event'] = $aliases[$event['event']] ?? $event['event']; + + if (!isset($event['method'])) { + $event['method'] = 'on'.preg_replace_callback([ + '/(?<=\b|_)[a-z]/i', + '/[^a-z0-9]/i', + ], fn ($matches) => strtoupper($matches[0]), $event['event']); + $event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']); + + if (null !== ($class = $container->getDefinition($id)->getClass()) && ($r = $container->getReflectionClass($class, false)) && !$r->hasMethod($event['method'])) { + if (!$r->hasMethod('__invoke')) { + throw new InvalidArgumentException(sprintf('None of the "%s" or "__invoke" methods exist for the service "%s". Please define the "method" attribute on "kernel.event_listener" tags.', $event['method'], $id)); + } + + $event['method'] = '__invoke'; + } + } + + $dispatcherDefinition = $globalDispatcherDefinition; + if (isset($event['dispatcher'])) { + $dispatcherDefinition = $container->findDefinition($event['dispatcher']); + } + + $dispatcherDefinition->addMethodCall('addListener', [$event['event'], [new ServiceClosureArgument(new Reference($id)), $event['method']], $priority]); + + if (isset($this->hotPathEvents[$event['event']])) { + $container->getDefinition($id)->addTag('container.hot_path'); + } elseif (isset($this->noPreloadEvents[$event['event']])) { + ++$noPreload; + } + } + + if ($noPreload && \count($events) === $noPreload) { + $container->getDefinition($id)->addTag('container.no_preload'); + } + } + + $extractingDispatcher = new ExtractingEventDispatcher(); + + foreach ($container->findTaggedServiceIds('kernel.event_subscriber', true) as $id => $tags) { + $def = $container->getDefinition($id); + + // We must assume that the class value has been correctly filled, even if the service is created by a factory + $class = $def->getClass(); + + if (!$r = $container->getReflectionClass($class)) { + throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + } + if (!$r->isSubclassOf(EventSubscriberInterface::class)) { + throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, EventSubscriberInterface::class)); + } + $class = $r->name; + + $dispatcherDefinitions = []; + foreach ($tags as $attributes) { + if (!isset($attributes['dispatcher']) || isset($dispatcherDefinitions[$attributes['dispatcher']])) { + continue; + } + + $dispatcherDefinitions[$attributes['dispatcher']] = $container->findDefinition($attributes['dispatcher']); + } + + if (!$dispatcherDefinitions) { + $dispatcherDefinitions = [$globalDispatcherDefinition]; + } + + $noPreload = 0; + ExtractingEventDispatcher::$aliases = $aliases; + ExtractingEventDispatcher::$subscriber = $class; + $extractingDispatcher->addSubscriber($extractingDispatcher); + foreach ($extractingDispatcher->listeners as $args) { + $args[1] = [new ServiceClosureArgument(new Reference($id)), $args[1]]; + foreach ($dispatcherDefinitions as $dispatcherDefinition) { + $dispatcherDefinition->addMethodCall('addListener', $args); + } + + if (isset($this->hotPathEvents[$args[0]])) { + $container->getDefinition($id)->addTag('container.hot_path'); + } elseif (isset($this->noPreloadEvents[$args[0]])) { + ++$noPreload; + } + } + if ($noPreload && \count($extractingDispatcher->listeners) === $noPreload) { + $container->getDefinition($id)->addTag('container.no_preload'); + } + $extractingDispatcher->listeners = []; + ExtractingEventDispatcher::$aliases = []; + } + } + + private function getEventFromTypeDeclaration(ContainerBuilder $container, string $id, string $method): string + { + if ( + null === ($class = $container->getDefinition($id)->getClass()) + || !($r = $container->getReflectionClass($class, false)) + || !$r->hasMethod($method) + || 1 > ($m = $r->getMethod($method))->getNumberOfParameters() + || !($type = $m->getParameters()[0]->getType()) instanceof \ReflectionNamedType + || $type->isBuiltin() + || Event::class === ($name = $type->getName()) + ) { + throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "kernel.event_listener" tags.', $id)); + } + + return $name; + } +} + +/** + * @internal + */ +class ExtractingEventDispatcher extends EventDispatcher implements EventSubscriberInterface +{ + public array $listeners = []; + + public static array $aliases = []; + public static string $subscriber; + + public function addListener(string $eventName, callable|array $listener, int $priority = 0): void + { + $this->listeners[] = [$eventName, $listener[1], $priority]; + } + + public static function getSubscribedEvents(): array + { + $events = []; + + foreach ([self::$subscriber, 'getSubscribedEvents']() as $eventName => $params) { + $events[self::$aliases[$eventName] ?? $eventName] = $params; + } + + return $events; + } +} diff --git a/tools/mailer/symfony/event-dispatcher/EventDispatcher.php b/tools/mailer/symfony/event-dispatcher/EventDispatcher.php new file mode 100644 index 000000000..43bc16b85 --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher/EventDispatcher.php @@ -0,0 +1,256 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +use Psr\EventDispatcher\StoppableEventInterface; +use Symfony\Component\EventDispatcher\Debug\WrappedListener; + +/** + * The EventDispatcherInterface is the central point of Symfony's event listener system. + * + * Listeners are registered on the manager and events are dispatched through the + * manager. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + * @author Fabien Potencier + * @author Jordi Boggiano + * @author Jordan Alliot + * @author Nicolas Grekas + */ +class EventDispatcher implements EventDispatcherInterface +{ + private array $listeners = []; + private array $sorted = []; + private array $optimized; + + public function __construct() + { + if (__CLASS__ === static::class) { + $this->optimized = []; + } + } + + public function dispatch(object $event, ?string $eventName = null): object + { + $eventName ??= $event::class; + + if (isset($this->optimized)) { + $listeners = $this->optimized[$eventName] ?? (empty($this->listeners[$eventName]) ? [] : $this->optimizeListeners($eventName)); + } else { + $listeners = $this->getListeners($eventName); + } + + if ($listeners) { + $this->callListeners($listeners, $eventName, $event); + } + + return $event; + } + + public function getListeners(?string $eventName = null): array + { + if (null !== $eventName) { + if (empty($this->listeners[$eventName])) { + return []; + } + + if (!isset($this->sorted[$eventName])) { + $this->sortListeners($eventName); + } + + return $this->sorted[$eventName]; + } + + foreach ($this->listeners as $eventName => $eventListeners) { + if (!isset($this->sorted[$eventName])) { + $this->sortListeners($eventName); + } + } + + return array_filter($this->sorted); + } + + public function getListenerPriority(string $eventName, callable|array $listener): ?int + { + if (empty($this->listeners[$eventName])) { + return null; + } + + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { + $listener[0] = $listener[0](); + $listener[1] ??= '__invoke'; + } + + foreach ($this->listeners[$eventName] as $priority => &$listeners) { + foreach ($listeners as &$v) { + if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) { + $v[0] = $v[0](); + $v[1] ??= '__invoke'; + } + if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) { + return $priority; + } + } + } + + return null; + } + + public function hasListeners(?string $eventName = null): bool + { + if (null !== $eventName) { + return !empty($this->listeners[$eventName]); + } + + foreach ($this->listeners as $eventListeners) { + if ($eventListeners) { + return true; + } + } + + return false; + } + + public function addListener(string $eventName, callable|array $listener, int $priority = 0): void + { + $this->listeners[$eventName][$priority][] = $listener; + unset($this->sorted[$eventName], $this->optimized[$eventName]); + } + + public function removeListener(string $eventName, callable|array $listener): void + { + if (empty($this->listeners[$eventName])) { + return; + } + + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { + $listener[0] = $listener[0](); + $listener[1] ??= '__invoke'; + } + + foreach ($this->listeners[$eventName] as $priority => &$listeners) { + foreach ($listeners as $k => &$v) { + if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) { + $v[0] = $v[0](); + $v[1] ??= '__invoke'; + } + if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) { + unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]); + } + } + + if (!$listeners) { + unset($this->listeners[$eventName][$priority]); + } + } + } + + public function addSubscriber(EventSubscriberInterface $subscriber): void + { + foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { + if (\is_string($params)) { + $this->addListener($eventName, [$subscriber, $params]); + } elseif (\is_string($params[0])) { + $this->addListener($eventName, [$subscriber, $params[0]], $params[1] ?? 0); + } else { + foreach ($params as $listener) { + $this->addListener($eventName, [$subscriber, $listener[0]], $listener[1] ?? 0); + } + } + } + } + + public function removeSubscriber(EventSubscriberInterface $subscriber): void + { + foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { + if (\is_array($params) && \is_array($params[0])) { + foreach ($params as $listener) { + $this->removeListener($eventName, [$subscriber, $listener[0]]); + } + } else { + $this->removeListener($eventName, [$subscriber, \is_string($params) ? $params : $params[0]]); + } + } + } + + /** + * Triggers the listeners of an event. + * + * This method can be overridden to add functionality that is executed + * for each listener. + * + * @param callable[] $listeners The event listeners + * @param string $eventName The name of the event to dispatch + * @param object $event The event object to pass to the event handlers/listeners + */ + protected function callListeners(iterable $listeners, string $eventName, object $event): void + { + $stoppable = $event instanceof StoppableEventInterface; + + foreach ($listeners as $listener) { + if ($stoppable && $event->isPropagationStopped()) { + break; + } + $listener($event, $eventName, $this); + } + } + + /** + * Sorts the internal list of listeners for the given event by priority. + */ + private function sortListeners(string $eventName): void + { + krsort($this->listeners[$eventName]); + $this->sorted[$eventName] = []; + + foreach ($this->listeners[$eventName] as &$listeners) { + foreach ($listeners as &$listener) { + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { + $listener[0] = $listener[0](); + $listener[1] ??= '__invoke'; + } + $this->sorted[$eventName][] = $listener; + } + } + } + + /** + * Optimizes the internal list of listeners for the given event by priority. + */ + private function optimizeListeners(string $eventName): array + { + krsort($this->listeners[$eventName]); + $this->optimized[$eventName] = []; + + foreach ($this->listeners[$eventName] as &$listeners) { + foreach ($listeners as &$listener) { + $closure = &$this->optimized[$eventName][]; + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { + $closure = static function (...$args) use (&$listener, &$closure) { + if ($listener[0] instanceof \Closure) { + $listener[0] = $listener[0](); + $listener[1] ??= '__invoke'; + } + ($closure = $listener(...))(...$args); + }; + } else { + $closure = $listener instanceof WrappedListener ? $listener : $listener(...); + } + } + } + + return $this->optimized[$eventName]; + } +} diff --git a/tools/mailer/symfony/event-dispatcher/EventDispatcherInterface.php b/tools/mailer/symfony/event-dispatcher/EventDispatcherInterface.php new file mode 100644 index 000000000..99f8b1a03 --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher/EventDispatcherInterface.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface; + +/** + * The EventDispatcherInterface is the central point of Symfony's event listener system. + * Listeners are registered on the manager and events are dispatched through the + * manager. + * + * @author Bernhard Schussek + */ +interface EventDispatcherInterface extends ContractsEventDispatcherInterface +{ + /** + * Adds an event listener that listens on the specified events. + * + * @param int $priority The higher this value, the earlier an event + * listener will be triggered in the chain (defaults to 0) + */ + public function addListener(string $eventName, callable $listener, int $priority = 0): void; + + /** + * Adds an event subscriber. + * + * The subscriber is asked for all the events it is + * interested in and added as a listener for these events. + */ + public function addSubscriber(EventSubscriberInterface $subscriber): void; + + /** + * Removes an event listener from the specified events. + */ + public function removeListener(string $eventName, callable $listener): void; + + public function removeSubscriber(EventSubscriberInterface $subscriber): void; + + /** + * Gets the listeners of a specific event or all listeners sorted by descending priority. + * + * @return array + */ + public function getListeners(?string $eventName = null): array; + + /** + * Gets the listener priority for a specific event. + * + * Returns null if the event or the listener does not exist. + */ + public function getListenerPriority(string $eventName, callable $listener): ?int; + + /** + * Checks whether an event has any registered listeners. + */ + public function hasListeners(?string $eventName = null): bool; +} diff --git a/tools/mailer/symfony/event-dispatcher/EventSubscriberInterface.php b/tools/mailer/symfony/event-dispatcher/EventSubscriberInterface.php new file mode 100644 index 000000000..2085e428e --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher/EventSubscriberInterface.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * An EventSubscriber knows itself what events it is interested in. + * If an EventSubscriber is added to an EventDispatcherInterface, the manager invokes + * {@link getSubscribedEvents} and registers the subscriber as a listener for all + * returned events. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + */ +interface EventSubscriberInterface +{ + /** + * Returns an array of event names this subscriber wants to listen to. + * + * The array keys are event names and the value can be: + * + * * The method name to call (priority defaults to 0) + * * An array composed of the method name to call and the priority + * * An array of arrays composed of the method names to call and respective + * priorities, or 0 if unset + * + * For instance: + * + * * ['eventName' => 'methodName'] + * * ['eventName' => ['methodName', $priority]] + * * ['eventName' => [['methodName1', $priority], ['methodName2']]] + * + * The code must not depend on runtime state as it will only be called at compile time. + * All logic depending on runtime state must be put into the individual methods handling the events. + * + * @return array> + */ + public static function getSubscribedEvents(); +} diff --git a/tools/mailer/symfony/event-dispatcher/GenericEvent.php b/tools/mailer/symfony/event-dispatcher/GenericEvent.php new file mode 100644 index 000000000..2ac654fb1 --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher/GenericEvent.php @@ -0,0 +1,155 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +use Symfony\Contracts\EventDispatcher\Event; + +/** + * Event encapsulation class. + * + * Encapsulates events thus decoupling the observer from the subject they encapsulate. + * + * @author Drak + * + * @implements \ArrayAccess + * @implements \IteratorAggregate + */ +class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate +{ + /** + * Encapsulate an event with $subject and $arguments. + * + * @param mixed $subject The subject of the event, usually an object or a callable + * @param array $arguments Arguments to store in the event + */ + public function __construct( + protected mixed $subject = null, + protected array $arguments = [], + ) { + } + + /** + * Getter for subject property. + */ + public function getSubject(): mixed + { + return $this->subject; + } + + /** + * Get argument by key. + * + * @throws \InvalidArgumentException if key is not found + */ + public function getArgument(string $key): mixed + { + if ($this->hasArgument($key)) { + return $this->arguments[$key]; + } + + throw new \InvalidArgumentException(sprintf('Argument "%s" not found.', $key)); + } + + /** + * Add argument to event. + * + * @return $this + */ + public function setArgument(string $key, mixed $value): static + { + $this->arguments[$key] = $value; + + return $this; + } + + /** + * Getter for all arguments. + */ + public function getArguments(): array + { + return $this->arguments; + } + + /** + * Set args property. + * + * @return $this + */ + public function setArguments(array $args = []): static + { + $this->arguments = $args; + + return $this; + } + + /** + * Has argument. + */ + public function hasArgument(string $key): bool + { + return \array_key_exists($key, $this->arguments); + } + + /** + * ArrayAccess for argument getter. + * + * @param string $key Array key + * + * @throws \InvalidArgumentException if key does not exist in $this->args + */ + public function offsetGet(mixed $key): mixed + { + return $this->getArgument($key); + } + + /** + * ArrayAccess for argument setter. + * + * @param string $key Array key to set + */ + public function offsetSet(mixed $key, mixed $value): void + { + $this->setArgument($key, $value); + } + + /** + * ArrayAccess for unset argument. + * + * @param string $key Array key + */ + public function offsetUnset(mixed $key): void + { + if ($this->hasArgument($key)) { + unset($this->arguments[$key]); + } + } + + /** + * ArrayAccess has argument. + * + * @param string $key Array key + */ + public function offsetExists(mixed $key): bool + { + return $this->hasArgument($key); + } + + /** + * IteratorAggregate for iterating over the object like an array. + * + * @return \ArrayIterator + */ + public function getIterator(): \ArrayIterator + { + return new \ArrayIterator($this->arguments); + } +} diff --git a/tools/mailer/symfony/event-dispatcher/ImmutableEventDispatcher.php b/tools/mailer/symfony/event-dispatcher/ImmutableEventDispatcher.php new file mode 100644 index 000000000..a6d078e9b --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher/ImmutableEventDispatcher.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * A read-only proxy for an event dispatcher. + * + * @author Bernhard Schussek + */ +class ImmutableEventDispatcher implements EventDispatcherInterface +{ + public function __construct( + private EventDispatcherInterface $dispatcher, + ) { + } + + public function dispatch(object $event, ?string $eventName = null): object + { + return $this->dispatcher->dispatch($event, $eventName); + } + + public function addListener(string $eventName, callable|array $listener, int $priority = 0): never + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + public function addSubscriber(EventSubscriberInterface $subscriber): never + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + public function removeListener(string $eventName, callable|array $listener): never + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + public function removeSubscriber(EventSubscriberInterface $subscriber): never + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + public function getListeners(?string $eventName = null): array + { + return $this->dispatcher->getListeners($eventName); + } + + public function getListenerPriority(string $eventName, callable|array $listener): ?int + { + return $this->dispatcher->getListenerPriority($eventName, $listener); + } + + public function hasListeners(?string $eventName = null): bool + { + return $this->dispatcher->hasListeners($eventName); + } +} diff --git a/tools/mailer/symfony/event-dispatcher/LICENSE b/tools/mailer/symfony/event-dispatcher/LICENSE new file mode 100644 index 000000000..0138f8f07 --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-present Fabien Potencier + +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/tools/mailer/symfony/event-dispatcher/README.md b/tools/mailer/symfony/event-dispatcher/README.md new file mode 100644 index 000000000..dcdb68d21 --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher/README.md @@ -0,0 +1,15 @@ +EventDispatcher Component +========================= + +The EventDispatcher component provides tools that allow your application +components to communicate with each other by dispatching events and listening to +them. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/event_dispatcher.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/tools/mailer/symfony/event-dispatcher/composer.json b/tools/mailer/symfony/event-dispatcher/composer.json new file mode 100644 index 000000000..598bbdc54 --- /dev/null +++ b/tools/mailer/symfony/event-dispatcher/composer.json @@ -0,0 +1,47 @@ +{ + "name": "symfony/event-dispatcher", + "type": "library", + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.2", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "require-dev": { + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0", + "psr/log": "^1|^2|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\EventDispatcher\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/tools/mailer/symfony/mailer/CHANGELOG.md b/tools/mailer/symfony/mailer/CHANGELOG.md new file mode 100644 index 000000000..6ef846cc8 --- /dev/null +++ b/tools/mailer/symfony/mailer/CHANGELOG.md @@ -0,0 +1,98 @@ +CHANGELOG +========= + +6.4 +--- + + * Add DSN parameter `peer_fingerprint` to verify TLS certificate fingerprint + * Change the default port for the `mailjet+smtp` transport from 465 to 587 + +6.3 +--- + + * Add `MessageEvent::reject()` to allow rejecting an email before sending it + * Change the default port for the `mailgun+smtp` transport from 465 to 587 + * Add `$authenticators` parameter in `EsmtpTransport` constructor and `EsmtpTransport::setAuthenticators()` + to allow overriding of default eSMTP authenticators + +6.2.7 +----- + + * [BC BREAK] The following data providers for `TransportFactoryTestCase` are now static: + `supportsProvider()`, `createProvider()`, `unsupportedSchemeProvider()`and `incompleteDsnProvider()` + +6.2 +--- + + * Add a `mailer:test` command + * Add `SentMessageEvent` and `FailedMessageEvent` events + +6.1 +--- + + * Make `start()` and `stop()` methods public on `SmtpTransport` + * Improve extensibility of `EsmtpTransport` + +6.0 +--- + + * The `HttpTransportException` class takes a string at first argument + +5.4 +--- + + * Enable the mailer to operate on any PSR-14-compatible event dispatcher + +5.3 +--- + + * added the `mailer` monolog channel and set it on all transport definitions + +5.2.0 +----- + + * added `NativeTransportFactory` to configure a transport based on php.ini settings + * added `local_domain`, `restart_threshold`, `restart_threshold_sleep` and `ping_threshold` options for `smtp` + * added `command` option for `sendmail` + +4.4.0 +----- + + * [BC BREAK] changed the `NullTransport` DSN from `smtp://null` to `null://null` + * [BC BREAK] renamed `SmtpEnvelope` to `Envelope`, renamed `DelayedSmtpEnvelope` to + `DelayedEnvelope` + * [BC BREAK] changed the syntax for failover and roundrobin DSNs + + Before: + + dummy://a || dummy://b (for failover) + dummy://a && dummy://b (for roundrobin) + + After: + + failover(dummy://a dummy://b) + roundrobin(dummy://a dummy://b) + + * added support for multiple transports on a `Mailer` instance + * [BC BREAK] removed the `auth_mode` DSN option (it is now always determined automatically) + * STARTTLS cannot be enabled anymore (it is used automatically if TLS is disabled and the server supports STARTTLS) + * [BC BREAK] Removed the `encryption` DSN option (use `smtps` instead) + * Added support for the `smtps` protocol (does the same as using `smtp` and port `465`) + * Added PHPUnit constraints + * Added `MessageDataCollector` + * Added `MessageEvents` and `MessageLoggerListener` to allow collecting sent emails + * [BC BREAK] `TransportInterface` has a new `__toString()` method + * [BC BREAK] Classes `AbstractApiTransport` and `AbstractHttpTransport` moved under `Transport` sub-namespace. + * [BC BREAK] Transports depend on `Symfony\Contracts\EventDispatcher\EventDispatcherInterface` + instead of `Symfony\Component\EventDispatcher\EventDispatcherInterface`. + * Added possibility to register custom transport for dsn by implementing + `Symfony\Component\Mailer\Transport\TransportFactoryInterface` and tagging with `mailer.transport_factory` tag in DI. + * Added `Symfony\Component\Mailer\Test\TransportFactoryTestCase` to ease testing custom transport factories. + * Added `SentMessage::getDebug()` and `TransportExceptionInterface::getDebug` to help debugging + * Made `MessageEvent` final + * add DSN parameter `verify_peer` to disable TLS peer verification for SMTP transport + +4.3.0 +----- + + * Added the component. diff --git a/tools/mailer/symfony/mailer/Command/MailerTestCommand.php b/tools/mailer/symfony/mailer/Command/MailerTestCommand.php new file mode 100644 index 000000000..bfc2779e3 --- /dev/null +++ b/tools/mailer/symfony/mailer/Command/MailerTestCommand.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Command; + +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Mime\Email; + +/** + * A console command to test Mailer transports. + */ +#[AsCommand(name: 'mailer:test', description: 'Test Mailer transports by sending an email')] +final class MailerTestCommand extends Command +{ + public function __construct(private TransportInterface $transport) + { + $this->transport = $transport; + + parent::__construct(); + } + + protected function configure(): void + { + $this + ->addArgument('to', InputArgument::REQUIRED, 'The recipient of the message') + ->addOption('from', null, InputOption::VALUE_OPTIONAL, 'The sender of the message', 'from@example.org') + ->addOption('subject', null, InputOption::VALUE_OPTIONAL, 'The subject of the message', 'Testing transport') + ->addOption('body', null, InputOption::VALUE_OPTIONAL, 'The body of the message', 'Testing body') + ->addOption('transport', null, InputOption::VALUE_OPTIONAL, 'The transport to be used') + ->setHelp(<<<'EOF' +The %command.name% command tests a Mailer transport by sending a simple email message: + +php %command.full_name% to@example.com + +You can also specify a specific transport: + + php %command.full_name% to@example.com --transport=transport_name + +Note that this command bypasses the Messenger bus if configured. + +EOF + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $message = (new Email()) + ->to($input->getArgument('to')) + ->from($input->getOption('from')) + ->subject($input->getOption('subject')) + ->text($input->getOption('body')) + ; + if ($transport = $input->getOption('transport')) { + $message->getHeaders()->addTextHeader('X-Transport', $transport); + } + + $this->transport->send($message); + + return 0; + } +} diff --git a/tools/mailer/symfony/mailer/DataCollector/MessageDataCollector.php b/tools/mailer/symfony/mailer/DataCollector/MessageDataCollector.php new file mode 100644 index 000000000..5c9ac3544 --- /dev/null +++ b/tools/mailer/symfony/mailer/DataCollector/MessageDataCollector.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\DataCollector; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\DataCollector\DataCollector; +use Symfony\Component\Mailer\Event\MessageEvents; +use Symfony\Component\Mailer\EventListener\MessageLoggerListener; + +/** + * @author Fabien Potencier + */ +final class MessageDataCollector extends DataCollector +{ + private MessageEvents $events; + + public function __construct(MessageLoggerListener $logger) + { + $this->events = $logger->getEvents(); + } + + public function collect(Request $request, Response $response, ?\Throwable $exception = null): void + { + $this->data['events'] = $this->events; + } + + public function getEvents(): MessageEvents + { + return $this->data['events']; + } + + /** + * @internal + */ + public function base64Encode(string $data): string + { + return base64_encode($data); + } + + public function reset(): void + { + $this->data = []; + } + + public function getName(): string + { + return 'mailer'; + } +} diff --git a/tools/mailer/symfony/mailer/DelayedEnvelope.php b/tools/mailer/symfony/mailer/DelayedEnvelope.php new file mode 100644 index 000000000..7458db2f0 --- /dev/null +++ b/tools/mailer/symfony/mailer/DelayedEnvelope.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Message; + +/** + * @author Fabien Potencier + * + * @internal + */ +final class DelayedEnvelope extends Envelope +{ + private bool $senderSet = false; + private bool $recipientsSet = false; + private Message $message; + + public function __construct(Message $message) + { + $this->message = $message; + } + + public function setSender(Address $sender): void + { + parent::setSender($sender); + + $this->senderSet = true; + } + + public function getSender(): Address + { + if (!$this->senderSet) { + parent::setSender(self::getSenderFromHeaders($this->message->getHeaders())); + } + + return parent::getSender(); + } + + public function setRecipients(array $recipients): void + { + parent::setRecipients($recipients); + + $this->recipientsSet = (bool) parent::getRecipients(); + } + + /** + * @return Address[] + */ + public function getRecipients(): array + { + if ($this->recipientsSet) { + return parent::getRecipients(); + } + + return self::getRecipientsFromHeaders($this->message->getHeaders()); + } + + private static function getRecipientsFromHeaders(Headers $headers): array + { + $recipients = []; + foreach (['to', 'cc', 'bcc'] as $name) { + foreach ($headers->all($name) as $header) { + foreach ($header->getAddresses() as $address) { + $recipients[] = $address; + } + } + } + + return $recipients; + } + + private static function getSenderFromHeaders(Headers $headers): Address + { + if ($sender = $headers->get('Sender')) { + return $sender->getAddress(); + } + if ($return = $headers->get('Return-Path')) { + return $return->getAddress(); + } + if ($from = $headers->get('From')) { + return $from->getAddresses()[0]; + } + + throw new LogicException('Unable to determine the sender of the message.'); + } +} diff --git a/tools/mailer/symfony/mailer/Envelope.php b/tools/mailer/symfony/mailer/Envelope.php new file mode 100644 index 000000000..0a4af2eda --- /dev/null +++ b/tools/mailer/symfony/mailer/Envelope.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Symfony\Component\Mailer\Exception\InvalidArgumentException; +use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + */ +class Envelope +{ + private Address $sender; + private array $recipients = []; + + /** + * @param Address[] $recipients + */ + public function __construct(Address $sender, array $recipients) + { + $this->setSender($sender); + $this->setRecipients($recipients); + } + + public static function create(RawMessage $message): self + { + if (RawMessage::class === $message::class) { + throw new LogicException('Cannot send a RawMessage instance without an explicit Envelope.'); + } + + return new DelayedEnvelope($message); + } + + public function setSender(Address $sender): void + { + // to ensure deliverability of bounce emails independent of UTF-8 capabilities of SMTP servers + if (!preg_match('/^[^@\x80-\xFF]++@/', $sender->getAddress())) { + throw new InvalidArgumentException(sprintf('Invalid sender "%s": non-ASCII characters not supported in local-part of email.', $sender->getAddress())); + } + $this->sender = $sender; + } + + /** + * @return Address Returns a "mailbox" as specified by RFC 2822 + * Must be converted to an "addr-spec" when used as a "MAIL FROM" value in SMTP (use getAddress()) + */ + public function getSender(): Address + { + return $this->sender; + } + + /** + * @param Address[] $recipients + */ + public function setRecipients(array $recipients): void + { + if (!$recipients) { + throw new InvalidArgumentException('An envelope must have at least one recipient.'); + } + + $this->recipients = []; + foreach ($recipients as $recipient) { + if (!$recipient instanceof Address) { + throw new InvalidArgumentException(sprintf('A recipient must be an instance of "%s" (got "%s").', Address::class, get_debug_type($recipient))); + } + $this->recipients[] = new Address($recipient->getAddress()); + } + } + + /** + * @return Address[] + */ + public function getRecipients(): array + { + return $this->recipients; + } +} diff --git a/tools/mailer/symfony/mailer/Event/FailedMessageEvent.php b/tools/mailer/symfony/mailer/Event/FailedMessageEvent.php new file mode 100644 index 000000000..4808c659d --- /dev/null +++ b/tools/mailer/symfony/mailer/Event/FailedMessageEvent.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Event; + +use Symfony\Component\Mime\RawMessage; +use Symfony\Contracts\EventDispatcher\Event; + +/** + * @author Fabien Potencier + */ +final class FailedMessageEvent extends Event +{ + public function __construct( + private RawMessage $message, + private \Throwable $error, + ) { + } + + public function getMessage(): RawMessage + { + return $this->message; + } + + public function getError(): \Throwable + { + return $this->error; + } +} diff --git a/tools/mailer/symfony/mailer/Event/MessageEvent.php b/tools/mailer/symfony/mailer/Event/MessageEvent.php new file mode 100644 index 000000000..f00fdd52c --- /dev/null +++ b/tools/mailer/symfony/mailer/Event/MessageEvent.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Event; + +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Messenger\Stamp\StampInterface; +use Symfony\Component\Mime\RawMessage; +use Symfony\Contracts\EventDispatcher\Event; + +/** + * Allows the transformation of a Message and the Envelope before the email is sent. + * + * @author Fabien Potencier + */ +final class MessageEvent extends Event +{ + private RawMessage $message; + private Envelope $envelope; + private string $transport; + private bool $queued; + private bool $rejected = false; + + /** @var StampInterface[] */ + private array $stamps = []; + + public function __construct(RawMessage $message, Envelope $envelope, string $transport, bool $queued = false) + { + $this->message = $message; + $this->envelope = $envelope; + $this->transport = $transport; + $this->queued = $queued; + } + + public function getMessage(): RawMessage + { + return $this->message; + } + + public function setMessage(RawMessage $message): void + { + $this->message = $message; + } + + public function getEnvelope(): Envelope + { + return $this->envelope; + } + + public function setEnvelope(Envelope $envelope): void + { + $this->envelope = $envelope; + } + + public function getTransport(): string + { + return $this->transport; + } + + public function isQueued(): bool + { + return $this->queued; + } + + public function isRejected(): bool + { + return $this->rejected; + } + + public function reject(): void + { + $this->rejected = true; + $this->stopPropagation(); + } + + public function addStamp(StampInterface $stamp): void + { + if (!$this->queued) { + throw new LogicException(sprintf('Cannot call "%s()" on a message that is not meant to be queued.', __METHOD__)); + } + + $this->stamps[] = $stamp; + } + + /** + * @return StampInterface[] + */ + public function getStamps(): array + { + if (!$this->queued) { + throw new LogicException(sprintf('Cannot call "%s()" on a message that is not meant to be queued.', __METHOD__)); + } + + return $this->stamps; + } +} diff --git a/tools/mailer/symfony/mailer/Event/MessageEvents.php b/tools/mailer/symfony/mailer/Event/MessageEvents.php new file mode 100644 index 000000000..2b438e382 --- /dev/null +++ b/tools/mailer/symfony/mailer/Event/MessageEvents.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Event; + +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + */ +class MessageEvents +{ + /** + * @var MessageEvent[] + */ + private array $events = []; + + /** + * @var array + */ + private array $transports = []; + + public function add(MessageEvent $event): void + { + $this->events[] = $event; + $this->transports[$event->getTransport()] = true; + } + + public function getTransports(): array + { + return array_keys($this->transports); + } + + /** + * @return MessageEvent[] + */ + public function getEvents(?string $name = null): array + { + if (null === $name) { + return $this->events; + } + + $events = []; + foreach ($this->events as $event) { + if ($name === $event->getTransport()) { + $events[] = $event; + } + } + + return $events; + } + + /** + * @return RawMessage[] + */ + public function getMessages(?string $name = null): array + { + $events = $this->getEvents($name); + $messages = []; + foreach ($events as $event) { + $messages[] = $event->getMessage(); + } + + return $messages; + } +} diff --git a/tools/mailer/symfony/mailer/Event/SentMessageEvent.php b/tools/mailer/symfony/mailer/Event/SentMessageEvent.php new file mode 100644 index 000000000..a412a9f46 --- /dev/null +++ b/tools/mailer/symfony/mailer/Event/SentMessageEvent.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Event; + +use Symfony\Component\Mailer\SentMessage; +use Symfony\Contracts\EventDispatcher\Event; + +/** + * @author Fabien Potencier + */ +final class SentMessageEvent extends Event +{ + public function __construct(private SentMessage $message) + { + } + + public function getMessage(): SentMessage + { + return $this->message; + } +} diff --git a/tools/mailer/symfony/mailer/EventListener/EnvelopeListener.php b/tools/mailer/symfony/mailer/EventListener/EnvelopeListener.php new file mode 100644 index 000000000..db9dd723a --- /dev/null +++ b/tools/mailer/symfony/mailer/EventListener/EnvelopeListener.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Mailer\Event\MessageEvent; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Message; + +/** + * Manipulates the Envelope of a Message. + * + * @author Fabien Potencier + */ +class EnvelopeListener implements EventSubscriberInterface +{ + private ?Address $sender = null; + + /** + * @var Address[]|null + */ + private ?array $recipients = null; + + /** + * @param array $recipients + */ + public function __construct(Address|string|null $sender = null, ?array $recipients = null) + { + if (null !== $sender) { + $this->sender = Address::create($sender); + } + if (null !== $recipients) { + $this->recipients = Address::createArray($recipients); + } + } + + public function onMessage(MessageEvent $event): void + { + if ($this->sender) { + $event->getEnvelope()->setSender($this->sender); + + $message = $event->getMessage(); + if ($message instanceof Message) { + if (!$message->getHeaders()->has('Sender') && !$message->getHeaders()->has('From')) { + $message->getHeaders()->addMailboxHeader('Sender', $this->sender); + } + } + } + + if ($this->recipients) { + $event->getEnvelope()->setRecipients($this->recipients); + } + } + + public static function getSubscribedEvents(): array + { + return [ + // should be the last one to allow header changes by other listeners first + MessageEvent::class => ['onMessage', -255], + ]; + } +} diff --git a/tools/mailer/symfony/mailer/EventListener/MessageListener.php b/tools/mailer/symfony/mailer/EventListener/MessageListener.php new file mode 100644 index 000000000..ec822d9c6 --- /dev/null +++ b/tools/mailer/symfony/mailer/EventListener/MessageListener.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Mailer\Event\MessageEvent; +use Symfony\Component\Mailer\Exception\InvalidArgumentException; +use Symfony\Component\Mailer\Exception\RuntimeException; +use Symfony\Component\Mime\BodyRendererInterface; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Header\MailboxListHeader; +use Symfony\Component\Mime\Message; + +/** + * Manipulates the headers and the body of a Message. + * + * @author Fabien Potencier + */ +class MessageListener implements EventSubscriberInterface +{ + public const HEADER_SET_IF_EMPTY = 1; + public const HEADER_ADD = 2; + public const HEADER_REPLACE = 3; + public const DEFAULT_RULES = [ + 'from' => self::HEADER_SET_IF_EMPTY, + 'return-path' => self::HEADER_SET_IF_EMPTY, + 'reply-to' => self::HEADER_ADD, + 'to' => self::HEADER_SET_IF_EMPTY, + 'cc' => self::HEADER_ADD, + 'bcc' => self::HEADER_ADD, + ]; + + private ?Headers $headers; + private array $headerRules = []; + private ?BodyRendererInterface $renderer; + + public function __construct(?Headers $headers = null, ?BodyRendererInterface $renderer = null, array $headerRules = self::DEFAULT_RULES) + { + $this->headers = $headers; + $this->renderer = $renderer; + foreach ($headerRules as $headerName => $rule) { + $this->addHeaderRule($headerName, $rule); + } + } + + public function addHeaderRule(string $headerName, int $rule): void + { + if ($rule < 1 || $rule > 3) { + throw new InvalidArgumentException(sprintf('The "%d" rule is not supported.', $rule)); + } + + $this->headerRules[strtolower($headerName)] = $rule; + } + + public function onMessage(MessageEvent $event): void + { + $message = $event->getMessage(); + if (!$message instanceof Message) { + return; + } + + $this->setHeaders($message); + $this->renderMessage($message); + } + + private function setHeaders(Message $message): void + { + if (!$this->headers) { + return; + } + + $headers = $message->getHeaders(); + foreach ($this->headers->all() as $name => $header) { + if (!$headers->has($name)) { + $headers->add($header); + + continue; + } + + switch ($this->headerRules[$name] ?? self::HEADER_SET_IF_EMPTY) { + case self::HEADER_SET_IF_EMPTY: + break; + + case self::HEADER_REPLACE: + $headers->remove($name); + $headers->add($header); + + break; + + case self::HEADER_ADD: + if (!Headers::isUniqueHeader($name)) { + $headers->add($header); + + break; + } + + $h = $headers->get($name); + if (!$h instanceof MailboxListHeader) { + throw new RuntimeException(sprintf('Unable to set header "%s".', $name)); + } + + Headers::checkHeaderClass($header); + foreach ($header->getAddresses() as $address) { + $h->addAddress($address); + } + } + } + } + + private function renderMessage(Message $message): void + { + if (!$this->renderer) { + return; + } + + $this->renderer->render($message); + } + + public static function getSubscribedEvents(): array + { + return [ + MessageEvent::class => 'onMessage', + ]; + } +} diff --git a/tools/mailer/symfony/mailer/EventListener/MessageLoggerListener.php b/tools/mailer/symfony/mailer/EventListener/MessageLoggerListener.php new file mode 100644 index 000000000..6c5605fa8 --- /dev/null +++ b/tools/mailer/symfony/mailer/EventListener/MessageLoggerListener.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Mailer\Event\MessageEvent; +use Symfony\Component\Mailer\Event\MessageEvents; +use Symfony\Contracts\Service\ResetInterface; + +/** + * Logs Messages. + * + * @author Fabien Potencier + */ +class MessageLoggerListener implements EventSubscriberInterface, ResetInterface +{ + private MessageEvents $events; + + public function __construct() + { + $this->events = new MessageEvents(); + } + + /** + * @return void + */ + public function reset() + { + $this->events = new MessageEvents(); + } + + public function onMessage(MessageEvent $event): void + { + $this->events->add($event); + } + + public function getEvents(): MessageEvents + { + return $this->events; + } + + public static function getSubscribedEvents(): array + { + return [ + MessageEvent::class => ['onMessage', -255], + ]; + } +} diff --git a/tools/mailer/symfony/mailer/EventListener/MessengerTransportListener.php b/tools/mailer/symfony/mailer/EventListener/MessengerTransportListener.php new file mode 100644 index 000000000..8cf8cc800 --- /dev/null +++ b/tools/mailer/symfony/mailer/EventListener/MessengerTransportListener.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Mailer\Event\MessageEvent; +use Symfony\Component\Messenger\Stamp\TransportNamesStamp; +use Symfony\Component\Mime\Message; + +/** + * Allows messages to be sent to specific Messenger transports via the "X-Bus-Transport" MIME header. + * + * @author Fabien Potencier + */ +final class MessengerTransportListener implements EventSubscriberInterface +{ + public function onMessage(MessageEvent $event): void + { + if (!$event->isQueued()) { + return; + } + + $message = $event->getMessage(); + if (!$message instanceof Message || !$message->getHeaders()->has('X-Bus-Transport')) { + return; + } + + $names = $message->getHeaders()->get('X-Bus-Transport')->getBody(); + $names = array_map('trim', explode(',', $names)); + $event->addStamp(new TransportNamesStamp($names)); + $message->getHeaders()->remove('X-Bus-Transport'); + } + + public static function getSubscribedEvents(): array + { + return [ + MessageEvent::class => 'onMessage', + ]; + } +} diff --git a/tools/mailer/symfony/mailer/Exception/ExceptionInterface.php b/tools/mailer/symfony/mailer/Exception/ExceptionInterface.php new file mode 100644 index 000000000..2f0f3a6f9 --- /dev/null +++ b/tools/mailer/symfony/mailer/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * Exception interface for all exceptions thrown by the component. + * + * @author Fabien Potencier + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/tools/mailer/symfony/mailer/Exception/HttpTransportException.php b/tools/mailer/symfony/mailer/Exception/HttpTransportException.php new file mode 100644 index 000000000..ad10910f3 --- /dev/null +++ b/tools/mailer/symfony/mailer/Exception/HttpTransportException.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Fabien Potencier + */ +class HttpTransportException extends TransportException +{ + private ResponseInterface $response; + + public function __construct(string $message, ResponseInterface $response, int $code = 0, ?\Throwable $previous = null) + { + parent::__construct($message, $code, $previous); + + $this->response = $response; + } + + public function getResponse(): ResponseInterface + { + return $this->response; + } +} diff --git a/tools/mailer/symfony/mailer/Exception/IncompleteDsnException.php b/tools/mailer/symfony/mailer/Exception/IncompleteDsnException.php new file mode 100644 index 000000000..f2618b65d --- /dev/null +++ b/tools/mailer/symfony/mailer/Exception/IncompleteDsnException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Konstantin Myakshin + */ +class IncompleteDsnException extends InvalidArgumentException +{ +} diff --git a/tools/mailer/symfony/mailer/Exception/InvalidArgumentException.php b/tools/mailer/symfony/mailer/Exception/InvalidArgumentException.php new file mode 100644 index 000000000..ba5333456 --- /dev/null +++ b/tools/mailer/symfony/mailer/Exception/InvalidArgumentException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/tools/mailer/symfony/mailer/Exception/LogicException.php b/tools/mailer/symfony/mailer/Exception/LogicException.php new file mode 100644 index 000000000..487c0a34f --- /dev/null +++ b/tools/mailer/symfony/mailer/Exception/LogicException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/tools/mailer/symfony/mailer/Exception/RuntimeException.php b/tools/mailer/symfony/mailer/Exception/RuntimeException.php new file mode 100644 index 000000000..44b79cc64 --- /dev/null +++ b/tools/mailer/symfony/mailer/Exception/RuntimeException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/tools/mailer/symfony/mailer/Exception/TransportException.php b/tools/mailer/symfony/mailer/Exception/TransportException.php new file mode 100644 index 000000000..ea538d6fa --- /dev/null +++ b/tools/mailer/symfony/mailer/Exception/TransportException.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + */ +class TransportException extends RuntimeException implements TransportExceptionInterface +{ + private string $debug = ''; + + public function getDebug(): string + { + return $this->debug; + } + + public function appendDebug(string $debug): void + { + $this->debug .= $debug; + } +} diff --git a/tools/mailer/symfony/mailer/Exception/TransportExceptionInterface.php b/tools/mailer/symfony/mailer/Exception/TransportExceptionInterface.php new file mode 100644 index 000000000..4318f5ce1 --- /dev/null +++ b/tools/mailer/symfony/mailer/Exception/TransportExceptionInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + */ +interface TransportExceptionInterface extends ExceptionInterface +{ + public function getDebug(): string; + + public function appendDebug(string $debug): void; +} diff --git a/tools/mailer/symfony/mailer/Exception/UnexpectedResponseException.php b/tools/mailer/symfony/mailer/Exception/UnexpectedResponseException.php new file mode 100644 index 000000000..e779df122 --- /dev/null +++ b/tools/mailer/symfony/mailer/Exception/UnexpectedResponseException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +class UnexpectedResponseException extends TransportException +{ +} diff --git a/tools/mailer/symfony/mailer/Exception/UnsupportedSchemeException.php b/tools/mailer/symfony/mailer/Exception/UnsupportedSchemeException.php new file mode 100644 index 000000000..257fd47db --- /dev/null +++ b/tools/mailer/symfony/mailer/Exception/UnsupportedSchemeException.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +use Symfony\Component\Mailer\Bridge; +use Symfony\Component\Mailer\Transport\Dsn; + +/** + * @author Konstantin Myakshin + */ +class UnsupportedSchemeException extends LogicException +{ + private const SCHEME_TO_PACKAGE_MAP = [ + 'brevo' => [ + 'class' => Bridge\Brevo\Transport\BrevoTransportFactory::class, + 'package' => 'symfony/brevo-mailer', + ], + 'gmail' => [ + 'class' => Bridge\Google\Transport\GmailTransportFactory::class, + 'package' => 'symfony/google-mailer', + ], + 'infobip' => [ + 'class' => Bridge\Infobip\Transport\InfobipTransportFactory::class, + 'package' => 'symfony/infobip-mailer', + ], + 'mailersend' => [ + 'class' => Bridge\MailerSend\Transport\MailerSendTransportFactory::class, + 'package' => 'symfony/mailersend-mailer', + ], + 'mailgun' => [ + 'class' => Bridge\Mailgun\Transport\MailgunTransportFactory::class, + 'package' => 'symfony/mailgun-mailer', + ], + 'mailjet' => [ + 'class' => Bridge\Mailjet\Transport\MailjetTransportFactory::class, + 'package' => 'symfony/mailjet-mailer', + ], + 'mailpace' => [ + 'class' => Bridge\MailPace\Transport\MailPaceTransportFactory::class, + 'package' => 'symfony/mail-pace-mailer', + ], + 'mandrill' => [ + 'class' => Bridge\Mailchimp\Transport\MandrillTransportFactory::class, + 'package' => 'symfony/mailchimp-mailer', + ], + 'ohmysmtp' => [ + 'class' => Bridge\OhMySmtp\Transport\OhMySmtpTransportFactory::class, + 'package' => 'symfony/oh-my-smtp-mailer', + ], + 'postmark' => [ + 'class' => Bridge\Postmark\Transport\PostmarkTransportFactory::class, + 'package' => 'symfony/postmark-mailer', + ], + 'scaleway' => [ + 'class' => Bridge\Scaleway\Transport\ScalewayTransportFactory::class, + 'package' => 'symfony/scaleway-mailer', + ], + 'sendgrid' => [ + 'class' => Bridge\Sendgrid\Transport\SendgridTransportFactory::class, + 'package' => 'symfony/sendgrid-mailer', + ], + 'sendinblue' => [ + 'class' => Bridge\Sendinblue\Transport\SendinblueTransportFactory::class, + 'package' => 'symfony/sendinblue-mailer', + ], + 'ses' => [ + 'class' => Bridge\Amazon\Transport\SesTransportFactory::class, + 'package' => 'symfony/amazon-mailer', + ], + ]; + + public function __construct(Dsn $dsn, ?string $name = null, array $supported = []) + { + $provider = $dsn->getScheme(); + if (false !== $pos = strpos($provider, '+')) { + $provider = substr($provider, 0, $pos); + } + $package = self::SCHEME_TO_PACKAGE_MAP[$provider] ?? null; + if ($package && !class_exists($package['class'])) { + parent::__construct(sprintf('Unable to send emails via "%s" as the bridge is not installed. Try running "composer require %s".', $provider, $package['package'])); + + return; + } + + $message = sprintf('The "%s" scheme is not supported', $dsn->getScheme()); + if ($name && $supported) { + $message .= sprintf('; supported schemes for mailer "%s" are: "%s"', $name, implode('", "', $supported)); + } + + parent::__construct($message.'.'); + } +} diff --git a/tools/mailer/symfony/mailer/Header/MetadataHeader.php b/tools/mailer/symfony/mailer/Header/MetadataHeader.php new file mode 100644 index 000000000..d6ee5440d --- /dev/null +++ b/tools/mailer/symfony/mailer/Header/MetadataHeader.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Header; + +use Symfony\Component\Mime\Header\UnstructuredHeader; + +/** + * @author Kevin Bond + */ +final class MetadataHeader extends UnstructuredHeader +{ + private string $key; + + public function __construct(string $key, string $value) + { + $this->key = $key; + + parent::__construct('X-Metadata-'.$key, $value); + } + + public function getKey(): string + { + return $this->key; + } +} diff --git a/tools/mailer/symfony/mailer/Header/TagHeader.php b/tools/mailer/symfony/mailer/Header/TagHeader.php new file mode 100644 index 000000000..7115caebe --- /dev/null +++ b/tools/mailer/symfony/mailer/Header/TagHeader.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Header; + +use Symfony\Component\Mime\Header\UnstructuredHeader; + +/** + * @author Kevin Bond + */ +final class TagHeader extends UnstructuredHeader +{ + public function __construct(string $value) + { + parent::__construct('X-Tag', $value); + } +} diff --git a/tools/mailer/symfony/mailer/LICENSE b/tools/mailer/symfony/mailer/LICENSE new file mode 100644 index 000000000..f37c76b59 --- /dev/null +++ b/tools/mailer/symfony/mailer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019-present Fabien Potencier + +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/tools/mailer/symfony/mailer/Mailer.php b/tools/mailer/symfony/mailer/Mailer.php new file mode 100644 index 000000000..6df99091a --- /dev/null +++ b/tools/mailer/symfony/mailer/Mailer.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Event\MessageEvent; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\Messenger\SendEmailMessage; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Messenger\Exception\HandlerFailedException; +use Symfony\Component\Messenger\MessageBusInterface; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + */ +final class Mailer implements MailerInterface +{ + private TransportInterface $transport; + private ?MessageBusInterface $bus; + private ?EventDispatcherInterface $dispatcher; + + public function __construct(TransportInterface $transport, ?MessageBusInterface $bus = null, ?EventDispatcherInterface $dispatcher = null) + { + $this->transport = $transport; + $this->bus = $bus; + $this->dispatcher = $dispatcher; + } + + public function send(RawMessage $message, ?Envelope $envelope = null): void + { + if (null === $this->bus) { + $this->transport->send($message, $envelope); + + return; + } + + $stamps = []; + if (null !== $this->dispatcher) { + // The dispatched event here has `queued` set to `true`; the goal is NOT to render the message, but to let + // listeners do something before a message is sent to the queue. + // We are using a cloned message as we still want to dispatch the **original** message, not the one modified by listeners. + // That's because the listeners will run again when the email is sent via Messenger by the transport (see `AbstractTransport`). + // Listeners should act depending on the `$queued` argument of the `MessageEvent` instance. + $clonedMessage = clone $message; + $clonedEnvelope = null !== $envelope ? clone $envelope : Envelope::create($clonedMessage); + $event = new MessageEvent($clonedMessage, $clonedEnvelope, (string) $this->transport, true); + $this->dispatcher->dispatch($event); + $stamps = $event->getStamps(); + + if ($event->isRejected()) { + return; + } + } + + try { + $this->bus->dispatch(new SendEmailMessage($message, $envelope), $stamps); + } catch (HandlerFailedException $e) { + foreach ($e->getWrappedExceptions() as $nested) { + if ($nested instanceof TransportExceptionInterface) { + throw $nested; + } + } + throw $e; + } + } +} diff --git a/tools/mailer/symfony/mailer/MailerInterface.php b/tools/mailer/symfony/mailer/MailerInterface.php new file mode 100644 index 000000000..ebac4b53e --- /dev/null +++ b/tools/mailer/symfony/mailer/MailerInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mime\RawMessage; + +/** + * Interface for mailers able to send emails synchronously and/or asynchronously. + * + * Implementations must support synchronous and asynchronous sending. + * + * @author Fabien Potencier + */ +interface MailerInterface +{ + /** + * @throws TransportExceptionInterface + */ + public function send(RawMessage $message, ?Envelope $envelope = null): void; +} diff --git a/tools/mailer/symfony/mailer/Messenger/MessageHandler.php b/tools/mailer/symfony/mailer/Messenger/MessageHandler.php new file mode 100644 index 000000000..f8fb14fce --- /dev/null +++ b/tools/mailer/symfony/mailer/Messenger/MessageHandler.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Messenger; + +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\Transport\TransportInterface; + +/** + * @author Fabien Potencier + */ +class MessageHandler +{ + private TransportInterface $transport; + + public function __construct(TransportInterface $transport) + { + $this->transport = $transport; + } + + public function __invoke(SendEmailMessage $message): ?SentMessage + { + return $this->transport->send($message->getMessage(), $message->getEnvelope()); + } +} diff --git a/tools/mailer/symfony/mailer/Messenger/SendEmailMessage.php b/tools/mailer/symfony/mailer/Messenger/SendEmailMessage.php new file mode 100644 index 000000000..18bd50620 --- /dev/null +++ b/tools/mailer/symfony/mailer/Messenger/SendEmailMessage.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Messenger; + +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + */ +class SendEmailMessage +{ + private RawMessage $message; + private ?Envelope $envelope; + + public function __construct(RawMessage $message, ?Envelope $envelope = null) + { + $this->message = $message; + $this->envelope = $envelope; + } + + public function getMessage(): RawMessage + { + return $this->message; + } + + public function getEnvelope(): ?Envelope + { + return $this->envelope; + } +} diff --git a/tools/mailer/symfony/mailer/README.md b/tools/mailer/symfony/mailer/README.md new file mode 100644 index 000000000..43e7dfe05 --- /dev/null +++ b/tools/mailer/symfony/mailer/README.md @@ -0,0 +1,74 @@ +Mailer Component +================ + +The Mailer component helps sending emails. + +Getting Started +--------------- + +``` +$ composer require symfony/mailer +``` + +```php +use Symfony\Component\Mailer\Transport; +use Symfony\Component\Mailer\Mailer; +use Symfony\Component\Mime\Email; + +$transport = Transport::fromDsn('smtp://localhost'); +$mailer = new Mailer($transport); + +$email = (new Email()) + ->from('hello@example.com') + ->to('you@example.com') + //->cc('cc@example.com') + //->bcc('bcc@example.com') + //->replyTo('fabien@example.com') + //->priority(Email::PRIORITY_HIGH) + ->subject('Time for Symfony Mailer!') + ->text('Sending emails is fun again!') + ->html('

See Twig integration for better HTML integration!

'); + +$mailer->send($email); +``` + +To enable the Twig integration of the Mailer, require `symfony/twig-bridge` and +set up the `BodyRenderer`: + +```php +use Symfony\Bridge\Twig\Mime\BodyRenderer; +use Symfony\Bridge\Twig\Mime\TemplatedEmail; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\Mailer\EventListener\MessageListener; +use Symfony\Component\Mailer\Mailer; +use Symfony\Component\Mailer\Transport; +use Twig\Environment as TwigEnvironment; + +$twig = new TwigEnvironment(...); +$messageListener = new MessageListener(null, new BodyRenderer($twig)); + +$eventDispatcher = new EventDispatcher(); +$eventDispatcher->addSubscriber($messageListener); + +$transport = Transport::fromDsn('smtp://localhost', $eventDispatcher); +$mailer = new Mailer($transport, null, $eventDispatcher); + +$email = (new TemplatedEmail()) + // ... + ->htmlTemplate('emails/signup.html.twig') + ->context([ + 'expiration_date' => new \DateTimeImmutable('+7 days'), + 'username' => 'foo', + ]) +; +$mailer->send($email); +``` + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/mailer.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/tools/mailer/symfony/mailer/SentMessage.php b/tools/mailer/symfony/mailer/SentMessage.php new file mode 100644 index 000000000..be8471180 --- /dev/null +++ b/tools/mailer/symfony/mailer/SentMessage.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + */ +class SentMessage +{ + private RawMessage $original; + private RawMessage $raw; + private Envelope $envelope; + private string $messageId; + private string $debug = ''; + + /** + * @internal + */ + public function __construct(RawMessage $message, Envelope $envelope) + { + $message->ensureValidity(); + + $this->original = $message; + $this->envelope = $envelope; + + if ($message instanceof Message) { + $message = clone $message; + $headers = $message->getHeaders(); + if (!$headers->has('Message-ID')) { + $headers->addIdHeader('Message-ID', $message->generateMessageId()); + } + $this->messageId = $headers->get('Message-ID')->getId(); + $this->raw = new RawMessage($message->toIterable()); + } else { + $this->raw = $message; + } + } + + public function getMessage(): RawMessage + { + return $this->raw; + } + + public function getOriginalMessage(): RawMessage + { + return $this->original; + } + + public function getEnvelope(): Envelope + { + return $this->envelope; + } + + public function setMessageId(string $id): void + { + $this->messageId = $id; + } + + public function getMessageId(): string + { + return $this->messageId; + } + + public function getDebug(): string + { + return $this->debug; + } + + public function appendDebug(string $debug): void + { + $this->debug .= $debug; + } + + public function toString(): string + { + return $this->raw->toString(); + } + + public function toIterable(): iterable + { + return $this->raw->toIterable(); + } +} diff --git a/tools/mailer/symfony/mailer/Test/Constraint/EmailCount.php b/tools/mailer/symfony/mailer/Test/Constraint/EmailCount.php new file mode 100644 index 000000000..2ba80f250 --- /dev/null +++ b/tools/mailer/symfony/mailer/Test/Constraint/EmailCount.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mailer\Event\MessageEvents; + +final class EmailCount extends Constraint +{ + private int $expectedValue; + private ?string $transport; + private bool $queued; + + public function __construct(int $expectedValue, ?string $transport = null, bool $queued = false) + { + $this->expectedValue = $expectedValue; + $this->transport = $transport; + $this->queued = $queued; + } + + public function toString(): string + { + return sprintf('%shas %s "%d" emails', $this->transport ? $this->transport.' ' : '', $this->queued ? 'queued' : 'sent', $this->expectedValue); + } + + /** + * @param MessageEvents $events + */ + protected function matches($events): bool + { + return $this->expectedValue === $this->countEmails($events); + } + + /** + * @param MessageEvents $events + */ + protected function failureDescription($events): string + { + return sprintf('the Transport %s (%d %s)', $this->toString(), $this->countEmails($events), $this->queued ? 'queued' : 'sent'); + } + + private function countEmails(MessageEvents $events): int + { + $count = 0; + foreach ($events->getEvents($this->transport) as $event) { + if ( + ($this->queued && $event->isQueued()) + || (!$this->queued && !$event->isQueued()) + ) { + ++$count; + } + } + + return $count; + } +} diff --git a/tools/mailer/symfony/mailer/Test/Constraint/EmailIsQueued.php b/tools/mailer/symfony/mailer/Test/Constraint/EmailIsQueued.php new file mode 100644 index 000000000..46436aa06 --- /dev/null +++ b/tools/mailer/symfony/mailer/Test/Constraint/EmailIsQueued.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mailer\Event\MessageEvent; + +final class EmailIsQueued extends Constraint +{ + public function toString(): string + { + return 'is queued'; + } + + /** + * @param MessageEvent $event + */ + protected function matches($event): bool + { + return $event->isQueued(); + } + + /** + * @param MessageEvent $event + */ + protected function failureDescription($event): string + { + return 'the Email '.$this->toString(); + } +} diff --git a/tools/mailer/symfony/mailer/Test/TransportFactoryTestCase.php b/tools/mailer/symfony/mailer/Test/TransportFactoryTestCase.php new file mode 100644 index 000000000..5156086ae --- /dev/null +++ b/tools/mailer/symfony/mailer/Test/TransportFactoryTestCase.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Test; + +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Symfony\Component\Mailer\Exception\IncompleteDsnException; +use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; +use Symfony\Component\Mailer\Transport\Dsn; +use Symfony\Component\Mailer\Transport\TransportFactoryInterface; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * A test case to ease testing Transport Factory. + * + * @author Konstantin Myakshin + */ +abstract class TransportFactoryTestCase extends TestCase +{ + protected const USER = 'u$er'; + protected const PASSWORD = 'pa$s'; + + protected $dispatcher; + protected $client; + protected $logger; + + abstract public function getFactory(): TransportFactoryInterface; + + abstract public static function supportsProvider(): iterable; + + abstract public static function createProvider(): iterable; + + public static function unsupportedSchemeProvider(): iterable + { + return []; + } + + public static function incompleteDsnProvider(): iterable + { + return []; + } + + /** + * @dataProvider supportsProvider + */ + public function testSupports(Dsn $dsn, bool $supports) + { + $factory = $this->getFactory(); + + $this->assertSame($supports, $factory->supports($dsn)); + } + + /** + * @dataProvider createProvider + */ + public function testCreate(Dsn $dsn, TransportInterface $transport) + { + $factory = $this->getFactory(); + + $this->assertEquals($transport, $factory->create($dsn)); + if (str_contains('smtp', $dsn->getScheme())) { + $this->assertStringMatchesFormat($dsn->getScheme().'://%S'.$dsn->getHost().'%S', (string) $transport); + } + } + + /** + * @dataProvider unsupportedSchemeProvider + */ + public function testUnsupportedSchemeException(Dsn $dsn, ?string $message = null) + { + $factory = $this->getFactory(); + + $this->expectException(UnsupportedSchemeException::class); + if (null !== $message) { + $this->expectExceptionMessage($message); + } + + $factory->create($dsn); + } + + /** + * @dataProvider incompleteDsnProvider + */ + public function testIncompleteDsnException(Dsn $dsn) + { + $factory = $this->getFactory(); + + $this->expectException(IncompleteDsnException::class); + $factory->create($dsn); + } + + protected function getDispatcher(): EventDispatcherInterface + { + return $this->dispatcher ??= $this->createMock(EventDispatcherInterface::class); + } + + protected function getClient(): HttpClientInterface + { + return $this->client ??= $this->createMock(HttpClientInterface::class); + } + + protected function getLogger(): LoggerInterface + { + return $this->logger ??= $this->createMock(LoggerInterface::class); + } +} diff --git a/tools/mailer/symfony/mailer/Transport.php b/tools/mailer/symfony/mailer/Transport.php new file mode 100644 index 000000000..599f4fbce --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport.php @@ -0,0 +1,188 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesTransportFactory; +use Symfony\Component\Mailer\Bridge\Brevo\Transport\BrevoTransportFactory; +use Symfony\Component\Mailer\Bridge\Google\Transport\GmailTransportFactory; +use Symfony\Component\Mailer\Bridge\Infobip\Transport\InfobipTransportFactory; +use Symfony\Component\Mailer\Bridge\Mailchimp\Transport\MandrillTransportFactory; +use Symfony\Component\Mailer\Bridge\MailerSend\Transport\MailerSendTransportFactory; +use Symfony\Component\Mailer\Bridge\Mailgun\Transport\MailgunTransportFactory; +use Symfony\Component\Mailer\Bridge\Mailjet\Transport\MailjetTransportFactory; +use Symfony\Component\Mailer\Bridge\MailPace\Transport\MailPaceTransportFactory; +use Symfony\Component\Mailer\Bridge\OhMySmtp\Transport\OhMySmtpTransportFactory; +use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkTransportFactory; +use Symfony\Component\Mailer\Bridge\Scaleway\Transport\ScalewayTransportFactory; +use Symfony\Component\Mailer\Bridge\Sendgrid\Transport\SendgridTransportFactory; +use Symfony\Component\Mailer\Bridge\Sendinblue\Transport\SendinblueTransportFactory; +use Symfony\Component\Mailer\Exception\InvalidArgumentException; +use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; +use Symfony\Component\Mailer\Transport\Dsn; +use Symfony\Component\Mailer\Transport\FailoverTransport; +use Symfony\Component\Mailer\Transport\NativeTransportFactory; +use Symfony\Component\Mailer\Transport\NullTransportFactory; +use Symfony\Component\Mailer\Transport\RoundRobinTransport; +use Symfony\Component\Mailer\Transport\SendmailTransportFactory; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransportFactory; +use Symfony\Component\Mailer\Transport\TransportFactoryInterface; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Mailer\Transport\Transports; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Fabien Potencier + * @author Konstantin Myakshin + */ +final class Transport +{ + private const FACTORY_CLASSES = [ + BrevoTransportFactory::class, + GmailTransportFactory::class, + InfobipTransportFactory::class, + MailerSendTransportFactory::class, + MailgunTransportFactory::class, + MailjetTransportFactory::class, + MailPaceTransportFactory::class, + MandrillTransportFactory::class, + OhMySmtpTransportFactory::class, + PostmarkTransportFactory::class, + ScalewayTransportFactory::class, + SendgridTransportFactory::class, + SendinblueTransportFactory::class, + SesTransportFactory::class, + ]; + + private iterable $factories; + + public static function fromDsn(#[\SensitiveParameter] string $dsn, ?EventDispatcherInterface $dispatcher = null, ?HttpClientInterface $client = null, ?LoggerInterface $logger = null): TransportInterface + { + $factory = new self(iterator_to_array(self::getDefaultFactories($dispatcher, $client, $logger))); + + return $factory->fromString($dsn); + } + + public static function fromDsns(#[\SensitiveParameter] array $dsns, ?EventDispatcherInterface $dispatcher = null, ?HttpClientInterface $client = null, ?LoggerInterface $logger = null): TransportInterface + { + $factory = new self(iterator_to_array(self::getDefaultFactories($dispatcher, $client, $logger))); + + return $factory->fromStrings($dsns); + } + + /** + * @param TransportFactoryInterface[] $factories + */ + public function __construct(iterable $factories) + { + $this->factories = $factories; + } + + public function fromStrings(#[\SensitiveParameter] array $dsns): Transports + { + $transports = []; + foreach ($dsns as $name => $dsn) { + $transports[$name] = $this->fromString($dsn); + } + + return new Transports($transports); + } + + public function fromString(#[\SensitiveParameter] string $dsn): TransportInterface + { + [$transport, $offset] = $this->parseDsn($dsn); + if ($offset !== \strlen($dsn)) { + throw new InvalidArgumentException('The mailer DSN has some garbage at the end.'); + } + + return $transport; + } + + private function parseDsn(#[\SensitiveParameter] string $dsn, int $offset = 0): array + { + static $keywords = [ + 'failover' => FailoverTransport::class, + 'roundrobin' => RoundRobinTransport::class, + ]; + + while (true) { + foreach ($keywords as $name => $class) { + $name .= '('; + if ($name === substr($dsn, $offset, \strlen($name))) { + $offset += \strlen($name) - 1; + preg_match('{\(([^()]|(?R))*\)}A', $dsn, $matches, 0, $offset); + if (!isset($matches[0])) { + continue; + } + + ++$offset; + $args = []; + while (true) { + [$arg, $offset] = $this->parseDsn($dsn, $offset); + $args[] = $arg; + if (\strlen($dsn) === $offset) { + break; + } + ++$offset; + if (')' === $dsn[$offset - 1]) { + break; + } + } + + return [new $class($args), $offset]; + } + } + + if (preg_match('{(\w+)\(}A', $dsn, $matches, 0, $offset)) { + throw new InvalidArgumentException(sprintf('The "%s" keyword is not valid (valid ones are "%s"), ', $matches[1], implode('", "', array_keys($keywords)))); + } + + if ($pos = strcspn($dsn, ' )', $offset)) { + return [$this->fromDsnObject(Dsn::fromString(substr($dsn, $offset, $pos))), $offset + $pos]; + } + + return [$this->fromDsnObject(Dsn::fromString(substr($dsn, $offset))), \strlen($dsn)]; + } + } + + public function fromDsnObject(Dsn $dsn): TransportInterface + { + foreach ($this->factories as $factory) { + if ($factory->supports($dsn)) { + return $factory->create($dsn); + } + } + + throw new UnsupportedSchemeException($dsn); + } + + /** + * @return \Traversable + */ + public static function getDefaultFactories(?EventDispatcherInterface $dispatcher = null, ?HttpClientInterface $client = null, ?LoggerInterface $logger = null): \Traversable + { + foreach (self::FACTORY_CLASSES as $factoryClass) { + if (class_exists($factoryClass)) { + yield new $factoryClass($dispatcher, $client, $logger); + } + } + + yield new NullTransportFactory($dispatcher, $client, $logger); + + yield new SendmailTransportFactory($dispatcher, $client, $logger); + + yield new EsmtpTransportFactory($dispatcher, $client, $logger); + + yield new NativeTransportFactory($dispatcher, $client, $logger); + } +} diff --git a/tools/mailer/symfony/mailer/Transport/AbstractApiTransport.php b/tools/mailer/symfony/mailer/Transport/AbstractApiTransport.php new file mode 100644 index 000000000..040745eed --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/AbstractApiTransport.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Exception\RuntimeException; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; +use Symfony\Component\Mime\MessageConverter; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Fabien Potencier + */ +abstract class AbstractApiTransport extends AbstractHttpTransport +{ + abstract protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $envelope): ResponseInterface; + + protected function doSendHttp(SentMessage $message): ResponseInterface + { + try { + $email = MessageConverter::toEmail($message->getOriginalMessage()); + } catch (\Exception $e) { + throw new RuntimeException(sprintf('Unable to send message with the "%s" transport: ', __CLASS__).$e->getMessage(), 0, $e); + } + + return $this->doSendApi($message, $email, $message->getEnvelope()); + } + + /** + * @return Address[] + */ + protected function getRecipients(Email $email, Envelope $envelope): array + { + return array_filter($envelope->getRecipients(), fn (Address $address) => false === \in_array($address, array_merge($email->getCc(), $email->getBcc()), true)); + } +} diff --git a/tools/mailer/symfony/mailer/Transport/AbstractHttpTransport.php b/tools/mailer/symfony/mailer/Transport/AbstractHttpTransport.php new file mode 100644 index 000000000..96b7ec009 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/AbstractHttpTransport.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\Mailer\Exception\HttpTransportException; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Victor Bocharsky + */ +abstract class AbstractHttpTransport extends AbstractTransport +{ + protected $host; + protected $port; + protected $client; + + public function __construct(?HttpClientInterface $client = null, ?EventDispatcherInterface $dispatcher = null, ?LoggerInterface $logger = null) + { + $this->client = $client; + if (null === $client) { + if (!class_exists(HttpClient::class)) { + throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__)); + } + + $this->client = HttpClient::create(); + } + + parent::__construct($dispatcher, $logger); + } + + /** + * @return $this + */ + public function setHost(?string $host): static + { + $this->host = $host; + + return $this; + } + + /** + * @return $this + */ + public function setPort(?int $port): static + { + $this->port = $port; + + return $this; + } + + abstract protected function doSendHttp(SentMessage $message): ResponseInterface; + + protected function doSend(SentMessage $message): void + { + try { + $response = $this->doSendHttp($message); + $message->appendDebug($response->getInfo('debug') ?? ''); + } catch (HttpTransportException $e) { + $e->appendDebug($e->getResponse()->getInfo('debug') ?? ''); + + throw $e; + } + } +} diff --git a/tools/mailer/symfony/mailer/Transport/AbstractTransport.php b/tools/mailer/symfony/mailer/Transport/AbstractTransport.php new file mode 100644 index 000000000..9a1cd6859 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/AbstractTransport.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; +use Symfony\Bridge\Twig\Mime\TemplatedEmail; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Event\FailedMessageEvent; +use Symfony\Component\Mailer\Event\MessageEvent; +use Symfony\Component\Mailer\Event\SentMessageEvent; +use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\BodyRendererInterface; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + */ +abstract class AbstractTransport implements TransportInterface +{ + private ?EventDispatcherInterface $dispatcher; + private LoggerInterface $logger; + private float $rate = 0; + private float $lastSent = 0; + + public function __construct(?EventDispatcherInterface $dispatcher = null, ?LoggerInterface $logger = null) + { + $this->dispatcher = $dispatcher; + $this->logger = $logger ?? new NullLogger(); + } + + /** + * Sets the maximum number of messages to send per second (0 to disable). + * + * @return $this + */ + public function setMaxPerSecond(float $rate): static + { + if (0 >= $rate) { + $rate = 0; + } + + $this->rate = $rate; + $this->lastSent = 0; + + return $this; + } + + public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMessage + { + $message = clone $message; + $envelope = null !== $envelope ? clone $envelope : Envelope::create($message); + + try { + if (!$this->dispatcher) { + $sentMessage = new SentMessage($message, $envelope); + $this->doSend($sentMessage); + + return $sentMessage; + } + + $event = new MessageEvent($message, $envelope, (string) $this); + $this->dispatcher->dispatch($event); + if ($event->isRejected()) { + return null; + } + + $envelope = $event->getEnvelope(); + $message = $event->getMessage(); + + if ($message instanceof TemplatedEmail && !$message->isRendered()) { + throw new LogicException(sprintf('You must configure a "%s" when a "%s" instance has a text or HTML template set.', BodyRendererInterface::class, get_debug_type($message))); + } + + $sentMessage = new SentMessage($message, $envelope); + + try { + $this->doSend($sentMessage); + } catch (\Throwable $error) { + $this->dispatcher->dispatch(new FailedMessageEvent($message, $error)); + $this->checkThrottling(); + + throw $error; + } + + $this->dispatcher->dispatch(new SentMessageEvent($sentMessage)); + + return $sentMessage; + } finally { + $this->checkThrottling(); + } + } + + abstract protected function doSend(SentMessage $message): void; + + /** + * @param Address[] $addresses + * + * @return string[] + */ + protected function stringifyAddresses(array $addresses): array + { + return array_map(fn (Address $a) => $a->toString(), $addresses); + } + + protected function getLogger(): LoggerInterface + { + return $this->logger; + } + + private function checkThrottling(): void + { + if (0 == $this->rate) { + return; + } + + $sleep = (1 / $this->rate) - (microtime(true) - $this->lastSent); + if (0 < $sleep) { + $this->logger->debug(sprintf('Email transport "%s" sleeps for %.2f seconds', __CLASS__, $sleep)); + usleep((int) ($sleep * 1000000)); + } + $this->lastSent = microtime(true); + } +} diff --git a/tools/mailer/symfony/mailer/Transport/AbstractTransportFactory.php b/tools/mailer/symfony/mailer/Transport/AbstractTransportFactory.php new file mode 100644 index 000000000..96e90f346 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/AbstractTransportFactory.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Mailer\Exception\IncompleteDsnException; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Konstantin Myakshin + */ +abstract class AbstractTransportFactory implements TransportFactoryInterface +{ + protected $dispatcher; + protected $client; + protected $logger; + + public function __construct(?EventDispatcherInterface $dispatcher = null, ?HttpClientInterface $client = null, ?LoggerInterface $logger = null) + { + $this->dispatcher = $dispatcher; + $this->client = $client; + $this->logger = $logger; + } + + public function supports(Dsn $dsn): bool + { + return \in_array($dsn->getScheme(), $this->getSupportedSchemes()); + } + + abstract protected function getSupportedSchemes(): array; + + protected function getUser(Dsn $dsn): string + { + return $dsn->getUser() ?? throw new IncompleteDsnException('User is not set.'); + } + + protected function getPassword(Dsn $dsn): string + { + return $dsn->getPassword() ?? throw new IncompleteDsnException('Password is not set.'); + } +} diff --git a/tools/mailer/symfony/mailer/Transport/Dsn.php b/tools/mailer/symfony/mailer/Transport/Dsn.php new file mode 100644 index 000000000..0cff6aad1 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/Dsn.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Exception\InvalidArgumentException; + +/** + * @author Konstantin Myakshin + */ +final class Dsn +{ + private string $scheme; + private string $host; + private ?string $user; + private ?string $password; + private ?int $port; + private array $options; + + public function __construct(string $scheme, string $host, ?string $user = null, #[\SensitiveParameter] ?string $password = null, ?int $port = null, array $options = []) + { + $this->scheme = $scheme; + $this->host = $host; + $this->user = $user; + $this->password = $password; + $this->port = $port; + $this->options = $options; + } + + public static function fromString(#[\SensitiveParameter] string $dsn): self + { + if (false === $params = parse_url($dsn)) { + throw new InvalidArgumentException('The mailer DSN is invalid.'); + } + + if (!isset($params['scheme'])) { + throw new InvalidArgumentException('The mailer DSN must contain a scheme.'); + } + + if (!isset($params['host'])) { + throw new InvalidArgumentException('The mailer DSN must contain a host (use "default" by default).'); + } + + $user = '' !== ($params['user'] ?? '') ? rawurldecode($params['user']) : null; + $password = '' !== ($params['pass'] ?? '') ? rawurldecode($params['pass']) : null; + $port = $params['port'] ?? null; + parse_str($params['query'] ?? '', $query); + + return new self($params['scheme'], $params['host'], $user, $password, $port, $query); + } + + public function getScheme(): string + { + return $this->scheme; + } + + public function getHost(): string + { + return $this->host; + } + + public function getUser(): ?string + { + return $this->user; + } + + public function getPassword(): ?string + { + return $this->password; + } + + public function getPort(?int $default = null): ?int + { + return $this->port ?? $default; + } + + public function getOption(string $key, mixed $default = null): mixed + { + return $this->options[$key] ?? $default; + } +} diff --git a/tools/mailer/symfony/mailer/Transport/FailoverTransport.php b/tools/mailer/symfony/mailer/Transport/FailoverTransport.php new file mode 100644 index 000000000..d6a747730 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/FailoverTransport.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +/** + * Uses several Transports using a failover algorithm. + * + * @author Fabien Potencier + */ +class FailoverTransport extends RoundRobinTransport +{ + private ?TransportInterface $currentTransport = null; + + protected function getNextTransport(): ?TransportInterface + { + if (null === $this->currentTransport || $this->isTransportDead($this->currentTransport)) { + $this->currentTransport = parent::getNextTransport(); + } + + return $this->currentTransport; + } + + protected function getInitialCursor(): int + { + return 0; + } + + protected function getNameSymbol(): string + { + return 'failover'; + } +} diff --git a/tools/mailer/symfony/mailer/Transport/NativeTransportFactory.php b/tools/mailer/symfony/mailer/Transport/NativeTransportFactory.php new file mode 100644 index 000000000..8afa53cc4 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/NativeTransportFactory.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; +use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport; +use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream; + +/** + * Factory that configures a transport (sendmail or SMTP) based on php.ini settings. + * + * @author Laurent VOULLEMIER + */ +final class NativeTransportFactory extends AbstractTransportFactory +{ + public function create(Dsn $dsn): TransportInterface + { + if (!\in_array($dsn->getScheme(), $this->getSupportedSchemes(), true)) { + throw new UnsupportedSchemeException($dsn, 'native', $this->getSupportedSchemes()); + } + + if ($sendMailPath = ini_get('sendmail_path')) { + return new SendmailTransport($sendMailPath, $this->dispatcher, $this->logger); + } + + if ('\\' !== \DIRECTORY_SEPARATOR) { + throw new TransportException('sendmail_path is not configured in php.ini.'); + } + + // Only for windows hosts; at this point non-windows + // host have already thrown an exception or returned a transport + $host = ini_get('SMTP'); + $port = (int) ini_get('smtp_port'); + + if (!$host || !$port) { + throw new TransportException('smtp or smtp_port is not configured in php.ini.'); + } + + $socketStream = new SocketStream(); + $socketStream->setHost($host); + $socketStream->setPort($port); + if (465 !== $port) { + $socketStream->disableTls(); + } + + return new SmtpTransport($socketStream, $this->dispatcher, $this->logger); + } + + protected function getSupportedSchemes(): array + { + return ['native']; + } +} diff --git a/tools/mailer/symfony/mailer/Transport/NullTransport.php b/tools/mailer/symfony/mailer/Transport/NullTransport.php new file mode 100644 index 000000000..92fb82a47 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/NullTransport.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\SentMessage; + +/** + * Pretends messages have been sent, but just ignores them. + * + * @author Fabien Potencier + */ +final class NullTransport extends AbstractTransport +{ + protected function doSend(SentMessage $message): void + { + } + + public function __toString(): string + { + return 'null://'; + } +} diff --git a/tools/mailer/symfony/mailer/Transport/NullTransportFactory.php b/tools/mailer/symfony/mailer/Transport/NullTransportFactory.php new file mode 100644 index 000000000..4c45f39e1 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/NullTransportFactory.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; + +/** + * @author Konstantin Myakshin + */ +final class NullTransportFactory extends AbstractTransportFactory +{ + public function create(Dsn $dsn): TransportInterface + { + if ('null' === $dsn->getScheme()) { + return new NullTransport($this->dispatcher, $this->logger); + } + + throw new UnsupportedSchemeException($dsn, 'null', $this->getSupportedSchemes()); + } + + protected function getSupportedSchemes(): array + { + return ['null']; + } +} diff --git a/tools/mailer/symfony/mailer/Transport/RoundRobinTransport.php b/tools/mailer/symfony/mailer/Transport/RoundRobinTransport.php new file mode 100644 index 000000000..ac9709bf7 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/RoundRobinTransport.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mime\RawMessage; + +/** + * Uses several Transports using a round robin algorithm. + * + * @author Fabien Potencier + */ +class RoundRobinTransport implements TransportInterface +{ + /** + * @var \SplObjectStorage + */ + private \SplObjectStorage $deadTransports; + private array $transports = []; + private int $retryPeriod; + private int $cursor = -1; + + /** + * @param TransportInterface[] $transports + */ + public function __construct(array $transports, int $retryPeriod = 60) + { + if (!$transports) { + throw new TransportException(sprintf('"%s" must have at least one transport configured.', static::class)); + } + + $this->transports = $transports; + $this->deadTransports = new \SplObjectStorage(); + $this->retryPeriod = $retryPeriod; + } + + public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMessage + { + $exception = null; + + while ($transport = $this->getNextTransport()) { + try { + return $transport->send($message, $envelope); + } catch (TransportExceptionInterface $e) { + $exception ??= new TransportException('All transports failed.'); + $exception->appendDebug(sprintf("Transport \"%s\": %s\n", $transport, $e->getDebug())); + $this->deadTransports[$transport] = microtime(true); + } + } + + throw $exception ?? new TransportException('No transports found.'); + } + + public function __toString(): string + { + return $this->getNameSymbol().'('.implode(' ', array_map('strval', $this->transports)).')'; + } + + /** + * Rotates the transport list around and returns the first instance. + */ + protected function getNextTransport(): ?TransportInterface + { + if (-1 === $this->cursor) { + $this->cursor = $this->getInitialCursor(); + } + + $cursor = $this->cursor; + while (true) { + $transport = $this->transports[$cursor]; + + if (!$this->isTransportDead($transport)) { + break; + } + + if ((microtime(true) - $this->deadTransports[$transport]) > $this->retryPeriod) { + $this->deadTransports->detach($transport); + + break; + } + + if ($this->cursor === $cursor = $this->moveCursor($cursor)) { + return null; + } + } + + $this->cursor = $this->moveCursor($cursor); + + return $transport; + } + + protected function isTransportDead(TransportInterface $transport): bool + { + return $this->deadTransports->contains($transport); + } + + protected function getInitialCursor(): int + { + // the cursor initial value is randomized so that + // when are not in a daemon, we are still rotating the transports + return mt_rand(0, \count($this->transports) - 1); + } + + protected function getNameSymbol(): string + { + return 'roundrobin'; + } + + private function moveCursor(int $cursor): int + { + return ++$cursor >= \count($this->transports) ? 0 : $cursor; + } +} diff --git a/tools/mailer/symfony/mailer/Transport/SendmailTransport.php b/tools/mailer/symfony/mailer/Transport/SendmailTransport.php new file mode 100644 index 000000000..3add460eb --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/SendmailTransport.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport; +use Symfony\Component\Mailer\Transport\Smtp\Stream\AbstractStream; +use Symfony\Component\Mailer\Transport\Smtp\Stream\ProcessStream; +use Symfony\Component\Mime\RawMessage; + +/** + * SendmailTransport for sending mail through a Sendmail/Postfix (etc..) binary. + * + * Transport can be instantiated through SendmailTransportFactory or NativeTransportFactory: + * + * - SendmailTransportFactory to use most common sendmail path and recommended options + * - NativeTransportFactory when configuration is set via php.ini + * + * @author Fabien Potencier + * @author Chris Corbyn + */ +class SendmailTransport extends AbstractTransport +{ + private string $command = '/usr/sbin/sendmail -bs'; + private ProcessStream $stream; + private ?SmtpTransport $transport = null; + + /** + * Constructor. + * + * Supported modes are -bs and -t, with any additional flags desired. + * + * The recommended mode is "-bs" since it is interactive and failure notifications are hence possible. + * Note that the -t mode does not support error reporting and does not support Bcc properly (the Bcc headers are not removed). + * + * If using -t mode, you are strongly advised to include -oi or -i in the flags (like /usr/sbin/sendmail -oi -t) + * + * -f flag will be appended automatically if one is not present. + */ + public function __construct(?string $command = null, ?EventDispatcherInterface $dispatcher = null, ?LoggerInterface $logger = null) + { + parent::__construct($dispatcher, $logger); + + if (null !== $command) { + if (!str_contains($command, ' -bs') && !str_contains($command, ' -t')) { + throw new \InvalidArgumentException(sprintf('Unsupported sendmail command flags "%s"; must be one of "-bs" or "-t" but can include additional flags.', $command)); + } + + $this->command = $command; + } + + $this->stream = new ProcessStream(); + if (str_contains($this->command, ' -bs')) { + $this->stream->setCommand($this->command); + $this->stream->setInteractive(true); + $this->transport = new SmtpTransport($this->stream, $dispatcher, $logger); + } + } + + public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMessage + { + if ($this->transport) { + return $this->transport->send($message, $envelope); + } + + return parent::send($message, $envelope); + } + + public function __toString(): string + { + if ($this->transport) { + return (string) $this->transport; + } + + return 'smtp://sendmail'; + } + + protected function doSend(SentMessage $message): void + { + $this->getLogger()->debug(sprintf('Email transport "%s" starting', __CLASS__)); + + $command = $this->command; + + if ($recipients = $message->getEnvelope()->getRecipients()) { + $command = str_replace(' -t', '', $command); + } + + if (!str_contains($command, ' -f')) { + $command .= ' -f'.escapeshellarg($message->getEnvelope()->getSender()->getEncodedAddress()); + } + + $chunks = AbstractStream::replace("\r\n", "\n", $message->toIterable()); + + if (!str_contains($command, ' -i') && !str_contains($command, ' -oi')) { + $chunks = AbstractStream::replace("\n.", "\n..", $chunks); + } + + foreach ($recipients as $recipient) { + $command .= ' '.escapeshellarg($recipient->getEncodedAddress()); + } + + $this->stream->setCommand($command); + $this->stream->initialize(); + foreach ($chunks as $chunk) { + $this->stream->write($chunk); + } + $this->stream->flush(); + $this->stream->terminate(); + + $this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__)); + } +} diff --git a/tools/mailer/symfony/mailer/Transport/SendmailTransportFactory.php b/tools/mailer/symfony/mailer/Transport/SendmailTransportFactory.php new file mode 100644 index 000000000..6d977e74b --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/SendmailTransportFactory.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; + +/** + * @author Konstantin Myakshin + */ +final class SendmailTransportFactory extends AbstractTransportFactory +{ + public function create(Dsn $dsn): TransportInterface + { + if ('sendmail+smtp' === $dsn->getScheme() || 'sendmail' === $dsn->getScheme()) { + return new SendmailTransport($dsn->getOption('command'), $this->dispatcher, $this->logger); + } + + throw new UnsupportedSchemeException($dsn, 'sendmail', $this->getSupportedSchemes()); + } + + protected function getSupportedSchemes(): array + { + return ['sendmail', 'sendmail+smtp']; + } +} diff --git a/tools/mailer/symfony/mailer/Transport/Smtp/Auth/AuthenticatorInterface.php b/tools/mailer/symfony/mailer/Transport/Smtp/Auth/AuthenticatorInterface.php new file mode 100644 index 000000000..98ea2d44a --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/Smtp/Auth/AuthenticatorInterface.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * An Authentication mechanism. + * + * @author Chris Corbyn + */ +interface AuthenticatorInterface +{ + /** + * Tries to authenticate the user. + * + * @throws TransportExceptionInterface + */ + public function authenticate(EsmtpTransport $client): void; + + /** + * Gets the name of the AUTH mechanism this Authenticator handles. + */ + public function getAuthKeyword(): string; +} diff --git a/tools/mailer/symfony/mailer/Transport/Smtp/Auth/CramMd5Authenticator.php b/tools/mailer/symfony/mailer/Transport/Smtp/Auth/CramMd5Authenticator.php new file mode 100644 index 000000000..79cddc469 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/Smtp/Auth/CramMd5Authenticator.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Exception\InvalidArgumentException; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * Handles CRAM-MD5 authentication. + * + * @author Chris Corbyn + */ +class CramMd5Authenticator implements AuthenticatorInterface +{ + public function getAuthKeyword(): string + { + return 'CRAM-MD5'; + } + + /** + * @see https://www.ietf.org/rfc/rfc4954.txt + */ + public function authenticate(EsmtpTransport $client): void + { + $challenge = $client->executeCommand("AUTH CRAM-MD5\r\n", [334]); + $challenge = base64_decode(substr($challenge, 4)); + $message = base64_encode($client->getUsername().' '.$this->getResponse($client->getPassword(), $challenge)); + $client->executeCommand(sprintf("%s\r\n", $message), [235]); + } + + /** + * Generates a CRAM-MD5 response from a server challenge. + */ + private function getResponse(#[\SensitiveParameter] string $secret, string $challenge): string + { + if (!$secret) { + throw new InvalidArgumentException('A non-empty secret is required.'); + } + + if (\strlen($secret) > 64) { + $secret = pack('H32', md5($secret)); + } + + if (\strlen($secret) < 64) { + $secret = str_pad($secret, 64, \chr(0)); + } + + $kipad = substr($secret, 0, 64) ^ str_repeat(\chr(0x36), 64); + $kopad = substr($secret, 0, 64) ^ str_repeat(\chr(0x5C), 64); + + $inner = pack('H32', md5($kipad.$challenge)); + $digest = md5($kopad.$inner); + + return $digest; + } +} diff --git a/tools/mailer/symfony/mailer/Transport/Smtp/Auth/LoginAuthenticator.php b/tools/mailer/symfony/mailer/Transport/Smtp/Auth/LoginAuthenticator.php new file mode 100644 index 000000000..e0b7d577e --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/Smtp/Auth/LoginAuthenticator.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * Handles LOGIN authentication. + * + * @author Chris Corbyn + */ +class LoginAuthenticator implements AuthenticatorInterface +{ + public function getAuthKeyword(): string + { + return 'LOGIN'; + } + + /** + * @see https://www.ietf.org/rfc/rfc4954.txt + */ + public function authenticate(EsmtpTransport $client): void + { + $client->executeCommand("AUTH LOGIN\r\n", [334]); + $client->executeCommand(sprintf("%s\r\n", base64_encode($client->getUsername())), [334]); + $client->executeCommand(sprintf("%s\r\n", base64_encode($client->getPassword())), [235]); + } +} diff --git a/tools/mailer/symfony/mailer/Transport/Smtp/Auth/PlainAuthenticator.php b/tools/mailer/symfony/mailer/Transport/Smtp/Auth/PlainAuthenticator.php new file mode 100644 index 000000000..6b680b511 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/Smtp/Auth/PlainAuthenticator.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * Handles PLAIN authentication. + * + * @author Chris Corbyn + */ +class PlainAuthenticator implements AuthenticatorInterface +{ + public function getAuthKeyword(): string + { + return 'PLAIN'; + } + + /** + * @see https://www.ietf.org/rfc/rfc4954.txt + */ + public function authenticate(EsmtpTransport $client): void + { + $client->executeCommand(sprintf("AUTH PLAIN %s\r\n", base64_encode($client->getUsername().\chr(0).$client->getUsername().\chr(0).$client->getPassword())), [235]); + } +} diff --git a/tools/mailer/symfony/mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php b/tools/mailer/symfony/mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php new file mode 100644 index 000000000..c3aaa4909 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * Handles XOAUTH2 authentication. + * + * @author xu.li + * + * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol + */ +class XOAuth2Authenticator implements AuthenticatorInterface +{ + public function getAuthKeyword(): string + { + return 'XOAUTH2'; + } + + /** + * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol#the_sasl_xoauth2_mechanism + */ + public function authenticate(EsmtpTransport $client): void + { + $client->executeCommand('AUTH XOAUTH2 '.base64_encode('user='.$client->getUsername()."\1auth=Bearer ".$client->getPassword()."\1\1")."\r\n", [235]); + } +} diff --git a/tools/mailer/symfony/mailer/Transport/Smtp/EsmtpTransport.php b/tools/mailer/symfony/mailer/Transport/Smtp/EsmtpTransport.php new file mode 100644 index 000000000..f5edfe112 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/Smtp/EsmtpTransport.php @@ -0,0 +1,228 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\Exception\UnexpectedResponseException; +use Symfony\Component\Mailer\Transport\Smtp\Auth\AuthenticatorInterface; +use Symfony\Component\Mailer\Transport\Smtp\Stream\AbstractStream; +use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream; + +/** + * Sends Emails over SMTP with ESMTP support. + * + * @author Fabien Potencier + * @author Chris Corbyn + */ +class EsmtpTransport extends SmtpTransport +{ + private array $authenticators = []; + private string $username = ''; + private string $password = ''; + private array $capabilities; + + public function __construct(string $host = 'localhost', int $port = 0, ?bool $tls = null, ?EventDispatcherInterface $dispatcher = null, ?LoggerInterface $logger = null, ?AbstractStream $stream = null, ?array $authenticators = null) + { + parent::__construct($stream, $dispatcher, $logger); + + if (null === $authenticators) { + // fallback to default authenticators + // order is important here (roughly most secure and popular first) + $authenticators = [ + new Auth\CramMd5Authenticator(), + new Auth\LoginAuthenticator(), + new Auth\PlainAuthenticator(), + new Auth\XOAuth2Authenticator(), + ]; + } + $this->setAuthenticators($authenticators); + + /** @var SocketStream $stream */ + $stream = $this->getStream(); + + if (null === $tls) { + if (465 === $port) { + $tls = true; + } else { + $tls = \defined('OPENSSL_VERSION_NUMBER') && 0 === $port && 'localhost' !== $host; + } + } + if (!$tls) { + $stream->disableTls(); + } + if (0 === $port) { + $port = $tls ? 465 : 25; + } + + $stream->setHost($host); + $stream->setPort($port); + } + + /** + * @return $this + */ + public function setUsername(string $username): static + { + $this->username = $username; + + return $this; + } + + public function getUsername(): string + { + return $this->username; + } + + /** + * @return $this + */ + public function setPassword(#[\SensitiveParameter] string $password): static + { + $this->password = $password; + + return $this; + } + + public function getPassword(): string + { + return $this->password; + } + + public function setAuthenticators(array $authenticators): void + { + $this->authenticators = []; + foreach ($authenticators as $authenticator) { + $this->addAuthenticator($authenticator); + } + } + + public function addAuthenticator(AuthenticatorInterface $authenticator): void + { + $this->authenticators[] = $authenticator; + } + + public function executeCommand(string $command, array $codes): string + { + return [250] === $codes && str_starts_with($command, 'HELO ') ? $this->doEhloCommand() : parent::executeCommand($command, $codes); + } + + final protected function getCapabilities(): array + { + return $this->capabilities; + } + + private function doEhloCommand(): string + { + try { + $response = $this->executeCommand(sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]); + } catch (TransportExceptionInterface $e) { + try { + return parent::executeCommand(sprintf("HELO %s\r\n", $this->getLocalDomain()), [250]); + } catch (TransportExceptionInterface $ex) { + if (!$ex->getCode()) { + throw $e; + } + + throw $ex; + } + } + + $this->capabilities = $this->parseCapabilities($response); + + /** @var SocketStream $stream */ + $stream = $this->getStream(); + // WARNING: !$stream->isTLS() is right, 100% sure :) + // if you think that the ! should be removed, read the code again + // if doing so "fixes" your issue then it probably means your SMTP server behaves incorrectly or is wrongly configured + if (!$stream->isTLS() && \defined('OPENSSL_VERSION_NUMBER') && \array_key_exists('STARTTLS', $this->capabilities)) { + $this->executeCommand("STARTTLS\r\n", [220]); + + if (!$stream->startTLS()) { + throw new TransportException('Unable to connect with STARTTLS.'); + } + + $response = $this->executeCommand(sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]); + $this->capabilities = $this->parseCapabilities($response); + } + + if (\array_key_exists('AUTH', $this->capabilities)) { + $this->handleAuth($this->capabilities['AUTH']); + } + + return $response; + } + + private function parseCapabilities(string $ehloResponse): array + { + $capabilities = []; + $lines = explode("\r\n", trim($ehloResponse)); + array_shift($lines); + foreach ($lines as $line) { + if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di', $line, $matches)) { + $value = strtoupper(ltrim($matches[2], ' =')); + $capabilities[strtoupper($matches[1])] = $value ? explode(' ', $value) : []; + } + } + + return $capabilities; + } + + private function handleAuth(array $modes): void + { + if (!$this->username) { + return; + } + + $code = null; + $authNames = []; + $errors = []; + $modes = array_map('strtolower', $modes); + foreach ($this->authenticators as $authenticator) { + if (!\in_array(strtolower($authenticator->getAuthKeyword()), $modes, true)) { + continue; + } + + $code = null; + $authNames[] = $authenticator->getAuthKeyword(); + try { + $authenticator->authenticate($this); + + return; + } catch (UnexpectedResponseException $e) { + $code = $e->getCode(); + + try { + $this->executeCommand("RSET\r\n", [250]); + } catch (TransportExceptionInterface) { + // ignore this exception as it probably means that the server error was final + } + + // keep the error message, but tries the other authenticators + $errors[$authenticator->getAuthKeyword()] = $e->getMessage(); + } + } + + if (!$authNames) { + throw new TransportException(sprintf('Failed to find an authenticator supported by the SMTP server, which currently supports: "%s".', implode('", "', $modes)), $code ?: 504); + } + + $message = sprintf('Failed to authenticate on SMTP server with username "%s" using the following authenticators: "%s".', $this->username, implode('", "', $authNames)); + foreach ($errors as $name => $error) { + $message .= sprintf(' Authenticator "%s" returned "%s".', $name, $error); + } + + throw new TransportException($message, $code ?: 535); + } +} diff --git a/tools/mailer/symfony/mailer/Transport/Smtp/EsmtpTransportFactory.php b/tools/mailer/symfony/mailer/Transport/Smtp/EsmtpTransportFactory.php new file mode 100644 index 000000000..a15d12245 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/Smtp/EsmtpTransportFactory.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp; + +use Symfony\Component\Mailer\Transport\AbstractTransportFactory; +use Symfony\Component\Mailer\Transport\Dsn; +use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream; +use Symfony\Component\Mailer\Transport\TransportInterface; + +/** + * @author Konstantin Myakshin + */ +final class EsmtpTransportFactory extends AbstractTransportFactory +{ + public function create(Dsn $dsn): TransportInterface + { + $tls = 'smtps' === $dsn->getScheme() ? true : null; + $port = $dsn->getPort(0); + $host = $dsn->getHost(); + + $transport = new EsmtpTransport($host, $port, $tls, $this->dispatcher, $this->logger); + + /** @var SocketStream $stream */ + $stream = $transport->getStream(); + $streamOptions = $stream->getStreamOptions(); + + if ('' !== $dsn->getOption('verify_peer') && !filter_var($dsn->getOption('verify_peer', true), \FILTER_VALIDATE_BOOL)) { + $streamOptions['ssl']['verify_peer'] = false; + $streamOptions['ssl']['verify_peer_name'] = false; + } + + if (null !== $peerFingerprint = $dsn->getOption('peer_fingerprint')) { + $streamOptions['ssl']['peer_fingerprint'] = $peerFingerprint; + } + + $stream->setStreamOptions($streamOptions); + + if ($user = $dsn->getUser()) { + $transport->setUsername($user); + } + + if ($password = $dsn->getPassword()) { + $transport->setPassword($password); + } + + if (null !== ($localDomain = $dsn->getOption('local_domain'))) { + $transport->setLocalDomain($localDomain); + } + + if (null !== ($maxPerSecond = $dsn->getOption('max_per_second'))) { + $transport->setMaxPerSecond((float) $maxPerSecond); + } + + if (null !== ($restartThreshold = $dsn->getOption('restart_threshold'))) { + $transport->setRestartThreshold((int) $restartThreshold, (int) $dsn->getOption('restart_threshold_sleep', 0)); + } + + if (null !== ($pingThreshold = $dsn->getOption('ping_threshold'))) { + $transport->setPingThreshold((int) $pingThreshold); + } + + return $transport; + } + + protected function getSupportedSchemes(): array + { + return ['smtp', 'smtps']; + } +} diff --git a/tools/mailer/symfony/mailer/Transport/Smtp/SmtpTransport.php b/tools/mailer/symfony/mailer/Transport/Smtp/SmtpTransport.php new file mode 100644 index 000000000..0de38fb2e --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/Smtp/SmtpTransport.php @@ -0,0 +1,392 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\Exception\UnexpectedResponseException; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\Transport\AbstractTransport; +use Symfony\Component\Mailer\Transport\Smtp\Stream\AbstractStream; +use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream; +use Symfony\Component\Mime\RawMessage; + +/** + * Sends emails over SMTP. + * + * @author Fabien Potencier + * @author Chris Corbyn + */ +class SmtpTransport extends AbstractTransport +{ + private bool $started = false; + private int $restartThreshold = 100; + private int $restartThresholdSleep = 0; + private int $restartCounter = 0; + private int $pingThreshold = 100; + private float $lastMessageTime = 0; + private AbstractStream $stream; + private string $domain = '[127.0.0.1]'; + + public function __construct(?AbstractStream $stream = null, ?EventDispatcherInterface $dispatcher = null, ?LoggerInterface $logger = null) + { + parent::__construct($dispatcher, $logger); + + $this->stream = $stream ?? new SocketStream(); + } + + public function getStream(): AbstractStream + { + return $this->stream; + } + + /** + * Sets the maximum number of messages to send before re-starting the transport. + * + * By default, the threshold is set to 100 (and no sleep at restart). + * + * @param int $threshold The maximum number of messages (0 to disable) + * @param int $sleep The number of seconds to sleep between stopping and re-starting the transport + * + * @return $this + */ + public function setRestartThreshold(int $threshold, int $sleep = 0): static + { + $this->restartThreshold = $threshold; + $this->restartThresholdSleep = $sleep; + + return $this; + } + + /** + * Sets the minimum number of seconds required between two messages, before the server is pinged. + * If the transport wants to send a message and the time since the last message exceeds the specified threshold, + * the transport will ping the server first (NOOP command) to check if the connection is still alive. + * Otherwise the message will be sent without pinging the server first. + * + * Do not set the threshold too low, as the SMTP server may drop the connection if there are too many + * non-mail commands (like pinging the server with NOOP). + * + * By default, the threshold is set to 100 seconds. + * + * @param int $seconds The minimum number of seconds between two messages required to ping the server + * + * @return $this + */ + public function setPingThreshold(int $seconds): static + { + $this->pingThreshold = $seconds; + + return $this; + } + + /** + * Sets the name of the local domain that will be used in HELO. + * + * This should be a fully-qualified domain name and should be truly the domain + * you're using. + * + * If your server does not have a domain name, use the IP address. This will + * automatically be wrapped in square brackets as described in RFC 5321, + * section 4.1.3. + * + * @return $this + */ + public function setLocalDomain(string $domain): static + { + if ('' !== $domain && '[' !== $domain[0]) { + if (filter_var($domain, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) { + $domain = '['.$domain.']'; + } elseif (filter_var($domain, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) { + $domain = '[IPv6:'.$domain.']'; + } + } + + $this->domain = $domain; + + return $this; + } + + /** + * Gets the name of the domain that will be used in HELO. + * + * If an IP address was specified, this will be returned wrapped in square + * brackets as described in RFC 5321, section 4.1.3. + */ + public function getLocalDomain(): string + { + return $this->domain; + } + + public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMessage + { + try { + $message = parent::send($message, $envelope); + } catch (TransportExceptionInterface $e) { + if ($this->started) { + try { + $this->executeCommand("RSET\r\n", [250]); + } catch (TransportExceptionInterface) { + // ignore this exception as it probably means that the server error was final + } + } + + throw $e; + } + + $this->checkRestartThreshold(); + + return $message; + } + + protected function parseMessageId(string $mtaResult): string + { + $regexps = [ + '/250 Ok (?P[0-9a-f-]+)\r?$/mis', + '/250 Ok:? queued as (?P[A-Z0-9]+)\r?$/mis', + ]; + $matches = []; + foreach ($regexps as $regexp) { + if (preg_match($regexp, $mtaResult, $matches)) { + return $matches['id']; + } + } + + return ''; + } + + public function __toString(): string + { + if ($this->stream instanceof SocketStream) { + $name = sprintf('smtp%s://%s', ($tls = $this->stream->isTLS()) ? 's' : '', $this->stream->getHost()); + $port = $this->stream->getPort(); + if (!(25 === $port || ($tls && 465 === $port))) { + $name .= ':'.$port; + } + + return $name; + } + + return 'smtp://sendmail'; + } + + /** + * Runs a command against the stream, expecting the given response codes. + * + * @param int[] $codes + * + * @throws TransportException when an invalid response if received + */ + public function executeCommand(string $command, array $codes): string + { + $this->stream->write($command); + $response = $this->getFullResponse(); + $this->assertResponseCode($response, $codes); + + return $response; + } + + protected function doSend(SentMessage $message): void + { + if (microtime(true) - $this->lastMessageTime > $this->pingThreshold) { + $this->ping(); + } + + if (!$this->started) { + $this->start(); + } + + try { + $envelope = $message->getEnvelope(); + $this->doMailFromCommand($envelope->getSender()->getEncodedAddress()); + foreach ($envelope->getRecipients() as $recipient) { + $this->doRcptToCommand($recipient->getEncodedAddress()); + } + + $this->executeCommand("DATA\r\n", [354]); + try { + foreach (AbstractStream::replace("\r\n.", "\r\n..", $message->toIterable()) as $chunk) { + $this->stream->write($chunk, false); + } + $this->stream->flush(); + } catch (TransportExceptionInterface $e) { + throw $e; + } catch (\Exception $e) { + $this->stream->terminate(); + $this->started = false; + $this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__)); + throw $e; + } + $mtaResult = $this->executeCommand("\r\n.\r\n", [250]); + $message->appendDebug($this->stream->getDebug()); + $this->lastMessageTime = microtime(true); + + if ($mtaResult && $messageId = $this->parseMessageId($mtaResult)) { + $message->setMessageId($messageId); + } + } catch (TransportExceptionInterface $e) { + $e->appendDebug($this->stream->getDebug()); + $this->lastMessageTime = 0; + throw $e; + } + } + + /** + * @internal since version 6.1, to be made private in 7.0 + * + * @final since version 6.1, to be made private in 7.0 + */ + protected function doHeloCommand(): void + { + $this->executeCommand(sprintf("HELO %s\r\n", $this->domain), [250]); + } + + private function doMailFromCommand(string $address): void + { + $this->executeCommand(sprintf("MAIL FROM:<%s>\r\n", $address), [250]); + } + + private function doRcptToCommand(string $address): void + { + $this->executeCommand(sprintf("RCPT TO:<%s>\r\n", $address), [250, 251, 252]); + } + + public function start(): void + { + if ($this->started) { + return; + } + + $this->getLogger()->debug(sprintf('Email transport "%s" starting', __CLASS__)); + + $this->stream->initialize(); + $this->assertResponseCode($this->getFullResponse(), [220]); + $this->doHeloCommand(); + $this->started = true; + $this->lastMessageTime = 0; + + $this->getLogger()->debug(sprintf('Email transport "%s" started', __CLASS__)); + } + + /** + * Manually disconnect from the SMTP server. + * + * In most cases this is not necessary since the disconnect happens automatically on termination. + * In cases of long-running scripts, this might however make sense to avoid keeping an open + * connection to the SMTP server in between sending emails. + */ + public function stop(): void + { + if (!$this->started) { + return; + } + + $this->getLogger()->debug(sprintf('Email transport "%s" stopping', __CLASS__)); + + try { + $this->executeCommand("QUIT\r\n", [221]); + } catch (TransportExceptionInterface) { + } finally { + $this->stream->terminate(); + $this->started = false; + $this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__)); + } + } + + private function ping(): void + { + if (!$this->started) { + return; + } + + try { + $this->executeCommand("NOOP\r\n", [250]); + } catch (TransportExceptionInterface) { + $this->stop(); + } + } + + /** + * @throws TransportException if a response code is incorrect + */ + private function assertResponseCode(string $response, array $codes): void + { + if (!$codes) { + throw new LogicException('You must set the expected response code.'); + } + + [$code] = sscanf($response, '%3d'); + $valid = \in_array($code, $codes); + + if (!$valid || !$response) { + $codeStr = $code ? sprintf('code "%s"', $code) : 'empty code'; + $responseStr = $response ? sprintf(', with message "%s"', trim($response)) : ''; + + throw new UnexpectedResponseException(sprintf('Expected response code "%s" but got ', implode('/', $codes)).$codeStr.$responseStr.'.', $code ?: 0); + } + } + + private function getFullResponse(): string + { + $response = ''; + do { + $line = $this->stream->readLine(); + $response .= $line; + } while ($line && isset($line[3]) && ' ' !== $line[3]); + + return $response; + } + + private function checkRestartThreshold(): void + { + // when using sendmail via non-interactive mode, the transport is never "started" + if (!$this->started) { + return; + } + + ++$this->restartCounter; + if ($this->restartCounter < $this->restartThreshold) { + return; + } + + $this->stop(); + if (0 < $sleep = $this->restartThresholdSleep) { + $this->getLogger()->debug(sprintf('Email transport "%s" sleeps for %d seconds after stopping', __CLASS__, $sleep)); + + sleep($sleep); + } + $this->start(); + $this->restartCounter = 0; + } + + public function __sleep(): array + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + /** + * @return void + */ + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + public function __destruct() + { + $this->stop(); + } +} diff --git a/tools/mailer/symfony/mailer/Transport/Smtp/Stream/AbstractStream.php b/tools/mailer/symfony/mailer/Transport/Smtp/Stream/AbstractStream.php new file mode 100644 index 000000000..498dc560c --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/Smtp/Stream/AbstractStream.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Stream; + +use Symfony\Component\Mailer\Exception\TransportException; + +/** + * A stream supporting remote sockets and local processes. + * + * @author Fabien Potencier + * @author Nicolas Grekas + * @author Chris Corbyn + * + * @internal + */ +abstract class AbstractStream +{ + /** @var resource|null */ + protected $stream; + /** @var resource|null */ + protected $in; + /** @var resource|null */ + protected $out; + protected $err; + + private string $debug = ''; + + public function write(string $bytes, bool $debug = true): void + { + if ($debug) { + foreach (explode("\n", trim($bytes)) as $line) { + $this->debug .= sprintf("> %s\n", $line); + } + } + + $bytesToWrite = \strlen($bytes); + $totalBytesWritten = 0; + while ($totalBytesWritten < $bytesToWrite) { + $bytesWritten = @fwrite($this->in, substr($bytes, $totalBytesWritten)); + if (false === $bytesWritten || 0 === $bytesWritten) { + throw new TransportException('Unable to write bytes on the wire.'); + } + + $totalBytesWritten += $bytesWritten; + } + } + + /** + * Flushes the contents of the stream (empty it) and set the internal pointer to the beginning. + */ + public function flush(): void + { + fflush($this->in); + } + + /** + * Performs any initialization needed. + */ + abstract public function initialize(): void; + + public function terminate(): void + { + $this->stream = $this->err = $this->out = $this->in = null; + } + + public function readLine(): string + { + if (feof($this->out)) { + return ''; + } + + $line = @fgets($this->out); + if ('' === $line || false === $line) { + $metas = stream_get_meta_data($this->out); + if ($metas['timed_out']) { + throw new TransportException(sprintf('Connection to "%s" timed out.', $this->getReadConnectionDescription())); + } + if ($metas['eof']) { + throw new TransportException(sprintf('Connection to "%s" has been closed unexpectedly.', $this->getReadConnectionDescription())); + } + if (false === $line) { + throw new TransportException(sprintf('Unable to read from connection to "%s": ', $this->getReadConnectionDescription()).error_get_last()['message']); + } + } + + $this->debug .= sprintf('< %s', $line); + + return $line; + } + + public function getDebug(): string + { + $debug = $this->debug; + $this->debug = ''; + + return $debug; + } + + public static function replace(string $from, string $to, iterable $chunks): \Generator + { + if ('' === $from) { + yield from $chunks; + + return; + } + + $carry = ''; + $fromLen = \strlen($from); + + foreach ($chunks as $chunk) { + if ('' === $chunk = $carry.$chunk) { + continue; + } + + if (str_contains($chunk, $from)) { + $chunk = explode($from, $chunk); + $carry = array_pop($chunk); + + yield implode($to, $chunk).$to; + } else { + $carry = $chunk; + } + + if (\strlen($carry) > $fromLen) { + yield substr($carry, 0, -$fromLen); + $carry = substr($carry, -$fromLen); + } + } + + if ('' !== $carry) { + yield $carry; + } + } + + abstract protected function getReadConnectionDescription(): string; +} diff --git a/tools/mailer/symfony/mailer/Transport/Smtp/Stream/ProcessStream.php b/tools/mailer/symfony/mailer/Transport/Smtp/Stream/ProcessStream.php new file mode 100644 index 000000000..e63514709 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/Smtp/Stream/ProcessStream.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Stream; + +use Symfony\Component\Mailer\Exception\TransportException; + +/** + * A stream supporting local processes. + * + * @author Fabien Potencier + * @author Chris Corbyn + * + * @internal + */ +final class ProcessStream extends AbstractStream +{ + private string $command; + private bool $interactive = false; + + public function setCommand(string $command): void + { + $this->command = $command; + } + + public function setInteractive(bool $interactive): void + { + $this->interactive = $interactive; + } + + public function initialize(): void + { + $descriptorSpec = [ + 0 => ['pipe', 'r'], + 1 => ['pipe', 'w'], + 2 => ['pipe', '\\' === \DIRECTORY_SEPARATOR ? 'a' : 'w'], + ]; + $pipes = []; + $this->stream = proc_open($this->command, $descriptorSpec, $pipes); + stream_set_blocking($pipes[2], false); + if ($err = stream_get_contents($pipes[2])) { + throw new TransportException('Process could not be started: '.$err); + } + $this->in = &$pipes[0]; + $this->out = &$pipes[1]; + $this->err = &$pipes[2]; + } + + public function terminate(): void + { + if (null !== $this->stream) { + fclose($this->in); + $out = stream_get_contents($this->out); + fclose($this->out); + $err = stream_get_contents($this->err); + fclose($this->err); + if (0 !== $exitCode = proc_close($this->stream)) { + $errorMessage = 'Process failed with exit code '.$exitCode.': '.$out.$err; + } + } + + parent::terminate(); + + if (!$this->interactive && isset($errorMessage)) { + throw new TransportException($errorMessage); + } + } + + protected function getReadConnectionDescription(): string + { + return 'process '.$this->command; + } +} diff --git a/tools/mailer/symfony/mailer/Transport/Smtp/Stream/SocketStream.php b/tools/mailer/symfony/mailer/Transport/Smtp/Stream/SocketStream.php new file mode 100644 index 000000000..49e6ea499 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/Smtp/Stream/SocketStream.php @@ -0,0 +1,193 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Stream; + +use Symfony\Component\Mailer\Exception\TransportException; + +/** + * A stream supporting remote sockets. + * + * @author Fabien Potencier + * @author Chris Corbyn + * + * @internal + */ +final class SocketStream extends AbstractStream +{ + private string $url; + private string $host = 'localhost'; + private int $port = 465; + private float $timeout; + private bool $tls = true; + private ?string $sourceIp = null; + private array $streamContextOptions = []; + + /** + * @return $this + */ + public function setTimeout(float $timeout): static + { + $this->timeout = $timeout; + + return $this; + } + + public function getTimeout(): float + { + return $this->timeout ?? (float) \ini_get('default_socket_timeout'); + } + + /** + * Literal IPv6 addresses should be wrapped in square brackets. + * + * @return $this + */ + public function setHost(string $host): static + { + $this->host = $host; + + return $this; + } + + public function getHost(): string + { + return $this->host; + } + + /** + * @return $this + */ + public function setPort(int $port): static + { + $this->port = $port; + + return $this; + } + + public function getPort(): int + { + return $this->port; + } + + /** + * Sets the TLS/SSL on the socket (disables STARTTLS). + * + * @return $this + */ + public function disableTls(): static + { + $this->tls = false; + + return $this; + } + + public function isTLS(): bool + { + return $this->tls; + } + + /** + * @return $this + */ + public function setStreamOptions(array $options): static + { + $this->streamContextOptions = $options; + + return $this; + } + + public function getStreamOptions(): array + { + return $this->streamContextOptions; + } + + /** + * Sets the source IP. + * + * IPv6 addresses should be wrapped in square brackets. + * + * @return $this + */ + public function setSourceIp(string $ip): static + { + $this->sourceIp = $ip; + + return $this; + } + + /** + * Returns the IP used to connect to the destination. + */ + public function getSourceIp(): ?string + { + return $this->sourceIp; + } + + public function initialize(): void + { + $this->url = $this->host.':'.$this->port; + if ($this->tls) { + $this->url = 'ssl://'.$this->url; + } + $options = []; + if ($this->sourceIp) { + $options['socket']['bindto'] = $this->sourceIp.':0'; + } + if ($this->streamContextOptions) { + $options = array_merge($options, $this->streamContextOptions); + } + // do it unconditionally as it will be used by STARTTLS as well if supported + $options['ssl']['crypto_method'] ??= \STREAM_CRYPTO_METHOD_TLS_CLIENT | \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT | \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; + $streamContext = stream_context_create($options); + + $timeout = $this->getTimeout(); + set_error_handler(function ($type, $msg) { + throw new TransportException(sprintf('Connection could not be established with host "%s": ', $this->url).$msg); + }); + try { + $this->stream = stream_socket_client($this->url, $errno, $errstr, $timeout, \STREAM_CLIENT_CONNECT, $streamContext); + } finally { + restore_error_handler(); + } + + stream_set_blocking($this->stream, true); + stream_set_timeout($this->stream, (int) $timeout, (int) (($timeout - (int) $timeout) * 1000000)); + $this->in = &$this->stream; + $this->out = &$this->stream; + } + + public function startTLS(): bool + { + set_error_handler(function ($type, $msg) { + throw new TransportException('Unable to connect with STARTTLS: '.$msg); + }); + try { + return stream_socket_enable_crypto($this->stream, true); + } finally { + restore_error_handler(); + } + } + + public function terminate(): void + { + if (null !== $this->stream) { + fclose($this->stream); + } + + parent::terminate(); + } + + protected function getReadConnectionDescription(): string + { + return $this->url; + } +} diff --git a/tools/mailer/symfony/mailer/Transport/TransportFactoryInterface.php b/tools/mailer/symfony/mailer/Transport/TransportFactoryInterface.php new file mode 100644 index 000000000..9785ae81a --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/TransportFactoryInterface.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Exception\IncompleteDsnException; +use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; + +/** + * @author Konstantin Myakshin + */ +interface TransportFactoryInterface +{ + /** + * @throws UnsupportedSchemeException + * @throws IncompleteDsnException + */ + public function create(Dsn $dsn): TransportInterface; + + public function supports(Dsn $dsn): bool; +} diff --git a/tools/mailer/symfony/mailer/Transport/TransportInterface.php b/tools/mailer/symfony/mailer/Transport/TransportInterface.php new file mode 100644 index 000000000..01570cab4 --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/TransportInterface.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mime\RawMessage; + +/** + * Interface for all mailer transports. + * + * When sending emails, you should prefer MailerInterface implementations + * as they allow asynchronous sending. + * + * @author Fabien Potencier + */ +interface TransportInterface extends \Stringable +{ + /** + * @throws TransportExceptionInterface + */ + public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMessage; +} diff --git a/tools/mailer/symfony/mailer/Transport/Transports.php b/tools/mailer/symfony/mailer/Transport/Transports.php new file mode 100644 index 000000000..f02b9bc9b --- /dev/null +++ b/tools/mailer/symfony/mailer/Transport/Transports.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Exception\InvalidArgumentException; +use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + */ +final class Transports implements TransportInterface +{ + /** + * @var array + */ + private array $transports = []; + private TransportInterface $default; + + /** + * @param iterable $transports + */ + public function __construct(iterable $transports) + { + foreach ($transports as $name => $transport) { + $this->default ??= $transport; + $this->transports[$name] = $transport; + } + + if (!$this->transports) { + throw new LogicException(sprintf('"%s" must have at least one transport configured.', __CLASS__)); + } + } + + public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMessage + { + /** @var Message $message */ + if (RawMessage::class === $message::class || !$message->getHeaders()->has('X-Transport')) { + return $this->default->send($message, $envelope); + } + + $headers = $message->getHeaders(); + $transport = $headers->get('X-Transport')->getBody(); + $headers->remove('X-Transport'); + + if (!isset($this->transports[$transport])) { + throw new InvalidArgumentException(sprintf('The "%s" transport does not exist (available transports: "%s").', $transport, implode('", "', array_keys($this->transports)))); + } + + try { + return $this->transports[$transport]->send($message, $envelope); + } catch (\Throwable $e) { + $headers->addTextHeader('X-Transport', $transport); + + throw $e; + } + } + + public function __toString(): string + { + return '['.implode(',', array_keys($this->transports)).']'; + } +} diff --git a/tools/mailer/symfony/mailer/composer.json b/tools/mailer/symfony/mailer/composer.json new file mode 100644 index 000000000..28dcb9196 --- /dev/null +++ b/tools/mailer/symfony/mailer/composer.json @@ -0,0 +1,47 @@ +{ + "name": "symfony/mailer", + "type": "library", + "description": "Helps sending emails", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.1", + "egulias/email-validator": "^2.1.10|^3|^4", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/mime": "^6.2|^7.0", + "symfony/service-contracts": "^2.5|^3" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/messenger": "^6.2|^7.0", + "symfony/twig-bridge": "^6.2|^7.0" + }, + "conflict": { + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<5.4", + "symfony/messenger": "<6.2", + "symfony/mime": "<6.2", + "symfony/twig-bridge": "<6.2.1" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Mailer\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/tools/mailer/symfony/mime/Address.php b/tools/mailer/symfony/mime/Address.php new file mode 100644 index 000000000..ce57f77ee --- /dev/null +++ b/tools/mailer/symfony/mime/Address.php @@ -0,0 +1,120 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Egulias\EmailValidator\EmailValidator; +use Egulias\EmailValidator\Validation\MessageIDValidation; +use Egulias\EmailValidator\Validation\RFCValidation; +use Symfony\Component\Mime\Encoder\IdnAddressEncoder; +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * @author Fabien Potencier + */ +final class Address +{ + /** + * A regex that matches a structure like 'Name '. + * It matches anything between the first < and last > as email address. + * This allows to use a single string to construct an Address, which can be convenient to use in + * config, and allows to have more readable config. + * This does not try to cover all edge cases for address. + */ + private const FROM_STRING_PATTERN = '~(?[^<]*)<(?.*)>[^>]*~'; + + private static EmailValidator $validator; + private static IdnAddressEncoder $encoder; + + private string $address; + private string $name; + + public function __construct(string $address, string $name = '') + { + if (!class_exists(EmailValidator::class)) { + throw new LogicException(sprintf('The "%s" class cannot be used as it needs "%s". Try running "composer require egulias/email-validator".', __CLASS__, EmailValidator::class)); + } + + self::$validator ??= new EmailValidator(); + + $this->address = trim($address); + $this->name = trim(str_replace(["\n", "\r"], '', $name)); + + if (!self::$validator->isValid($this->address, class_exists(MessageIDValidation::class) ? new MessageIDValidation() : new RFCValidation())) { + throw new RfcComplianceException(sprintf('Email "%s" does not comply with addr-spec of RFC 2822.', $address)); + } + } + + public function getAddress(): string + { + return $this->address; + } + + public function getName(): string + { + return $this->name; + } + + public function getEncodedAddress(): string + { + self::$encoder ??= new IdnAddressEncoder(); + + return self::$encoder->encodeString($this->address); + } + + public function toString(): string + { + return ($n = $this->getEncodedName()) ? $n.' <'.$this->getEncodedAddress().'>' : $this->getEncodedAddress(); + } + + public function getEncodedName(): string + { + if ('' === $this->getName()) { + return ''; + } + + return sprintf('"%s"', preg_replace('/"/u', '\"', $this->getName())); + } + + public static function create(self|string $address): self + { + if ($address instanceof self) { + return $address; + } + + if (!str_contains($address, '<')) { + return new self($address); + } + + if (!preg_match(self::FROM_STRING_PATTERN, $address, $matches)) { + throw new InvalidArgumentException(sprintf('Could not parse "%s" to a "%s" instance.', $address, self::class)); + } + + return new self($matches['addrSpec'], trim($matches['displayName'], ' \'"')); + } + + /** + * @param array $addresses + * + * @return Address[] + */ + public static function createArray(array $addresses): array + { + $addrs = []; + foreach ($addresses as $address) { + $addrs[] = self::create($address); + } + + return $addrs; + } +} diff --git a/tools/mailer/symfony/mime/BodyRendererInterface.php b/tools/mailer/symfony/mime/BodyRendererInterface.php new file mode 100644 index 000000000..d69217265 --- /dev/null +++ b/tools/mailer/symfony/mime/BodyRendererInterface.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * @author Fabien Potencier + */ +interface BodyRendererInterface +{ + public function render(Message $message): void; +} diff --git a/tools/mailer/symfony/mime/CHANGELOG.md b/tools/mailer/symfony/mime/CHANGELOG.md new file mode 100644 index 000000000..8d593e6ff --- /dev/null +++ b/tools/mailer/symfony/mime/CHANGELOG.md @@ -0,0 +1,57 @@ +CHANGELOG +========= + +7.0 +--- + + * Remove `Email::attachPart()`, use `Email::addPart()` instead + * Argument `$body` is now required (at least null) in `Message::setBody()` + * Require explicit argument when calling `Message::setBody()` + +6.3 +--- + + * Support detection of related parts if `Content-Id` is used instead of the name + * Add `TextPart::getDisposition()` + +6.2 +--- + + * Add `File` + * Deprecate `Email::attachPart()`, use `addPart()` instead + * Deprecate calling `Message::setBody()` without arguments + +6.1 +--- + + * Add `DataPart::getFilename()` and `DataPart::getContentType()` + +6.0 +--- + + * Remove `Address::fromString()`, use `Address::create()` instead + * Remove `Serializable` interface from `RawMessage` + +5.2.0 +----- + + * Add support for DKIM + * Deprecated `Address::fromString()`, use `Address::create()` instead + +4.4.0 +----- + + * [BC BREAK] Removed `NamedAddress` (`Address` now supports a name) + * Added PHPUnit constraints + * Added `AbstractPart::asDebugString()` + * Added `Address::fromString()` + +4.3.3 +----- + + * [BC BREAK] Renamed method `Headers::getAll()` to `Headers::all()`. + +4.3.0 +----- + + * Introduced the component as experimental diff --git a/tools/mailer/symfony/mime/CharacterStream.php b/tools/mailer/symfony/mime/CharacterStream.php new file mode 100644 index 000000000..572cf820b --- /dev/null +++ b/tools/mailer/symfony/mime/CharacterStream.php @@ -0,0 +1,211 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * @author Fabien Potencier + * @author Xavier De Cock + * + * @internal + */ +final class CharacterStream +{ + /** Pre-computed for optimization */ + private const UTF8_LENGTH_MAP = [ + "\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1, + "\x08" => 1, "\x09" => 1, "\x0a" => 1, "\x0b" => 1, "\x0c" => 1, "\x0d" => 1, "\x0e" => 1, "\x0f" => 1, + "\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1, + "\x18" => 1, "\x19" => 1, "\x1a" => 1, "\x1b" => 1, "\x1c" => 1, "\x1d" => 1, "\x1e" => 1, "\x1f" => 1, + "\x20" => 1, "\x21" => 1, "\x22" => 1, "\x23" => 1, "\x24" => 1, "\x25" => 1, "\x26" => 1, "\x27" => 1, + "\x28" => 1, "\x29" => 1, "\x2a" => 1, "\x2b" => 1, "\x2c" => 1, "\x2d" => 1, "\x2e" => 1, "\x2f" => 1, + "\x30" => 1, "\x31" => 1, "\x32" => 1, "\x33" => 1, "\x34" => 1, "\x35" => 1, "\x36" => 1, "\x37" => 1, + "\x38" => 1, "\x39" => 1, "\x3a" => 1, "\x3b" => 1, "\x3c" => 1, "\x3d" => 1, "\x3e" => 1, "\x3f" => 1, + "\x40" => 1, "\x41" => 1, "\x42" => 1, "\x43" => 1, "\x44" => 1, "\x45" => 1, "\x46" => 1, "\x47" => 1, + "\x48" => 1, "\x49" => 1, "\x4a" => 1, "\x4b" => 1, "\x4c" => 1, "\x4d" => 1, "\x4e" => 1, "\x4f" => 1, + "\x50" => 1, "\x51" => 1, "\x52" => 1, "\x53" => 1, "\x54" => 1, "\x55" => 1, "\x56" => 1, "\x57" => 1, + "\x58" => 1, "\x59" => 1, "\x5a" => 1, "\x5b" => 1, "\x5c" => 1, "\x5d" => 1, "\x5e" => 1, "\x5f" => 1, + "\x60" => 1, "\x61" => 1, "\x62" => 1, "\x63" => 1, "\x64" => 1, "\x65" => 1, "\x66" => 1, "\x67" => 1, + "\x68" => 1, "\x69" => 1, "\x6a" => 1, "\x6b" => 1, "\x6c" => 1, "\x6d" => 1, "\x6e" => 1, "\x6f" => 1, + "\x70" => 1, "\x71" => 1, "\x72" => 1, "\x73" => 1, "\x74" => 1, "\x75" => 1, "\x76" => 1, "\x77" => 1, + "\x78" => 1, "\x79" => 1, "\x7a" => 1, "\x7b" => 1, "\x7c" => 1, "\x7d" => 1, "\x7e" => 1, "\x7f" => 1, + "\x80" => 0, "\x81" => 0, "\x82" => 0, "\x83" => 0, "\x84" => 0, "\x85" => 0, "\x86" => 0, "\x87" => 0, + "\x88" => 0, "\x89" => 0, "\x8a" => 0, "\x8b" => 0, "\x8c" => 0, "\x8d" => 0, "\x8e" => 0, "\x8f" => 0, + "\x90" => 0, "\x91" => 0, "\x92" => 0, "\x93" => 0, "\x94" => 0, "\x95" => 0, "\x96" => 0, "\x97" => 0, + "\x98" => 0, "\x99" => 0, "\x9a" => 0, "\x9b" => 0, "\x9c" => 0, "\x9d" => 0, "\x9e" => 0, "\x9f" => 0, + "\xa0" => 0, "\xa1" => 0, "\xa2" => 0, "\xa3" => 0, "\xa4" => 0, "\xa5" => 0, "\xa6" => 0, "\xa7" => 0, + "\xa8" => 0, "\xa9" => 0, "\xaa" => 0, "\xab" => 0, "\xac" => 0, "\xad" => 0, "\xae" => 0, "\xaf" => 0, + "\xb0" => 0, "\xb1" => 0, "\xb2" => 0, "\xb3" => 0, "\xb4" => 0, "\xb5" => 0, "\xb6" => 0, "\xb7" => 0, + "\xb8" => 0, "\xb9" => 0, "\xba" => 0, "\xbb" => 0, "\xbc" => 0, "\xbd" => 0, "\xbe" => 0, "\xbf" => 0, + "\xc0" => 2, "\xc1" => 2, "\xc2" => 2, "\xc3" => 2, "\xc4" => 2, "\xc5" => 2, "\xc6" => 2, "\xc7" => 2, + "\xc8" => 2, "\xc9" => 2, "\xca" => 2, "\xcb" => 2, "\xcc" => 2, "\xcd" => 2, "\xce" => 2, "\xcf" => 2, + "\xd0" => 2, "\xd1" => 2, "\xd2" => 2, "\xd3" => 2, "\xd4" => 2, "\xd5" => 2, "\xd6" => 2, "\xd7" => 2, + "\xd8" => 2, "\xd9" => 2, "\xda" => 2, "\xdb" => 2, "\xdc" => 2, "\xdd" => 2, "\xde" => 2, "\xdf" => 2, + "\xe0" => 3, "\xe1" => 3, "\xe2" => 3, "\xe3" => 3, "\xe4" => 3, "\xe5" => 3, "\xe6" => 3, "\xe7" => 3, + "\xe8" => 3, "\xe9" => 3, "\xea" => 3, "\xeb" => 3, "\xec" => 3, "\xed" => 3, "\xee" => 3, "\xef" => 3, + "\xf0" => 4, "\xf1" => 4, "\xf2" => 4, "\xf3" => 4, "\xf4" => 4, "\xf5" => 4, "\xf6" => 4, "\xf7" => 4, + "\xf8" => 5, "\xf9" => 5, "\xfa" => 5, "\xfb" => 5, "\xfc" => 6, "\xfd" => 6, "\xfe" => 0, "\xff" => 0, + ]; + + private string $data = ''; + private int $dataSize = 0; + private array $map = []; + private int $charCount = 0; + private int $currentPos = 0; + private int $fixedWidth = 0; + + /** + * @param resource|string $input + */ + public function __construct($input, ?string $charset = 'utf-8') + { + $charset = strtolower(trim($charset)) ?: 'utf-8'; + if ('utf-8' === $charset || 'utf8' === $charset) { + $this->fixedWidth = 0; + $this->map = ['p' => [], 'i' => []]; + } else { + $this->fixedWidth = match ($charset) { + // 16 bits + 'ucs2', + 'ucs-2', + 'utf16', + 'utf-16' => 2, + // 32 bits + 'ucs4', + 'ucs-4', + 'utf32', + 'utf-32' => 4, + // 7-8 bit charsets: (us-)?ascii, (iso|iec)-?8859-?[0-9]+, windows-?125[0-9], cp-?[0-9]+, ansi, macintosh, + // koi-?7, koi-?8-?.+, mik, (cork|t1), v?iscii + // and fallback + default => 1, + }; + } + if (\is_resource($input)) { + $blocks = 16372; + while (false !== $read = fread($input, $blocks)) { + $this->write($read); + } + } else { + $this->write($input); + } + } + + public function read(int $length): ?string + { + if ($this->currentPos >= $this->charCount) { + return null; + } + $length = ($this->currentPos + $length > $this->charCount) ? $this->charCount - $this->currentPos : $length; + if ($this->fixedWidth > 0) { + $len = $length * $this->fixedWidth; + $ret = substr($this->data, $this->currentPos * $this->fixedWidth, $len); + $this->currentPos += $length; + } else { + $end = $this->currentPos + $length; + $end = min($end, $this->charCount); + $ret = ''; + $start = 0; + if ($this->currentPos > 0) { + $start = $this->map['p'][$this->currentPos - 1]; + } + $to = $start; + for (; $this->currentPos < $end; ++$this->currentPos) { + if (isset($this->map['i'][$this->currentPos])) { + $ret .= substr($this->data, $start, $to - $start).'?'; + $start = $this->map['p'][$this->currentPos]; + } else { + $to = $this->map['p'][$this->currentPos]; + } + } + $ret .= substr($this->data, $start, $to - $start); + } + + return $ret; + } + + public function readBytes(int $length): ?array + { + if (null !== $read = $this->read($length)) { + return array_map('ord', str_split($read, 1)); + } + + return null; + } + + public function setPointer(int $charOffset): void + { + if ($this->charCount < $charOffset) { + $charOffset = $this->charCount; + } + $this->currentPos = $charOffset; + } + + public function write(string $chars): void + { + $ignored = ''; + $this->data .= $chars; + if ($this->fixedWidth > 0) { + $strlen = \strlen($chars); + $ignoredL = $strlen % $this->fixedWidth; + $ignored = $ignoredL ? substr($chars, -$ignoredL) : ''; + $this->charCount += ($strlen - $ignoredL) / $this->fixedWidth; + } else { + $this->charCount += $this->getUtf8CharPositions($chars, $this->dataSize, $ignored); + } + $this->dataSize = \strlen($this->data) - \strlen($ignored); + } + + private function getUtf8CharPositions(string $string, int $startOffset, string &$ignoredChars): int + { + $strlen = \strlen($string); + $charPos = \count($this->map['p']); + $foundChars = 0; + $invalid = false; + for ($i = 0; $i < $strlen; ++$i) { + $char = $string[$i]; + $size = self::UTF8_LENGTH_MAP[$char]; + if (0 == $size) { + /* char is invalid, we must wait for a resync */ + $invalid = true; + continue; + } + + if ($invalid) { + /* We mark the chars as invalid and start a new char */ + $this->map['p'][$charPos + $foundChars] = $startOffset + $i; + $this->map['i'][$charPos + $foundChars] = true; + ++$foundChars; + $invalid = false; + } + if (($i + $size) > $strlen) { + $ignoredChars = substr($string, $i); + break; + } + for ($j = 1; $j < $size; ++$j) { + $char = $string[$i + $j]; + if ($char > "\x7F" && $char < "\xC0") { + // Valid - continue parsing + } else { + /* char is invalid, we must wait for a resync */ + $invalid = true; + continue 2; + } + } + /* Ok we got a complete char here */ + $this->map['p'][$charPos + $foundChars] = $startOffset + $i + $size; + $i += $j - 1; + ++$foundChars; + } + + return $foundChars; + } +} diff --git a/tools/mailer/symfony/mime/Crypto/DkimOptions.php b/tools/mailer/symfony/mime/Crypto/DkimOptions.php new file mode 100644 index 000000000..cee4e7cb8 --- /dev/null +++ b/tools/mailer/symfony/mime/Crypto/DkimOptions.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Crypto; + +/** + * A helper providing autocompletion for available DkimSigner options. + * + * @author Fabien Potencier + */ +final class DkimOptions +{ + private array $options = []; + + public function toArray(): array + { + return $this->options; + } + + /** + * @return $this + */ + public function algorithm(string $algo): static + { + $this->options['algorithm'] = $algo; + + return $this; + } + + /** + * @return $this + */ + public function signatureExpirationDelay(int $show): static + { + $this->options['signature_expiration_delay'] = $show; + + return $this; + } + + /** + * @return $this + */ + public function bodyMaxLength(int $max): static + { + $this->options['body_max_length'] = $max; + + return $this; + } + + /** + * @return $this + */ + public function bodyShowLength(bool $show): static + { + $this->options['body_show_length'] = $show; + + return $this; + } + + /** + * @return $this + */ + public function headerCanon(string $canon): static + { + $this->options['header_canon'] = $canon; + + return $this; + } + + /** + * @return $this + */ + public function bodyCanon(string $canon): static + { + $this->options['body_canon'] = $canon; + + return $this; + } + + /** + * @return $this + */ + public function headersToIgnore(array $headers): static + { + $this->options['headers_to_ignore'] = $headers; + + return $this; + } +} diff --git a/tools/mailer/symfony/mime/Crypto/DkimSigner.php b/tools/mailer/symfony/mime/Crypto/DkimSigner.php new file mode 100644 index 000000000..93a59b4f5 --- /dev/null +++ b/tools/mailer/symfony/mime/Crypto/DkimSigner.php @@ -0,0 +1,217 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Crypto; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Exception\RuntimeException; +use Symfony\Component\Mime\Header\UnstructuredHeader; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\Part\AbstractPart; + +/** + * @author Fabien Potencier + * + * RFC 6376 and 8301 + */ +final class DkimSigner +{ + public const CANON_SIMPLE = 'simple'; + public const CANON_RELAXED = 'relaxed'; + + public const ALGO_SHA256 = 'rsa-sha256'; + public const ALGO_ED25519 = 'ed25519-sha256'; // RFC 8463 + + private \OpenSSLAsymmetricKey $key; + + /** + * @param string $pk The private key as a string or the path to the file containing the private key, should be prefixed with file:// (in PEM format) + * @param string $passphrase A passphrase of the private key (if any) + */ + public function __construct( + string $pk, + private string $domainName, + private string $selector, + private array $defaultOptions = [], + string $passphrase = '', + ) { + if (!\extension_loaded('openssl')) { + throw new \LogicException('PHP extension "openssl" is required to use DKIM.'); + } + $this->key = openssl_pkey_get_private($pk, $passphrase) ?: throw new InvalidArgumentException('Unable to load DKIM private key: '.openssl_error_string()); + $this->defaultOptions += [ + 'algorithm' => self::ALGO_SHA256, + 'signature_expiration_delay' => 0, + 'body_max_length' => \PHP_INT_MAX, + 'body_show_length' => false, + 'header_canon' => self::CANON_RELAXED, + 'body_canon' => self::CANON_RELAXED, + 'headers_to_ignore' => [], + ]; + } + + public function sign(Message $message, array $options = []): Message + { + $options += $this->defaultOptions; + if (!\in_array($options['algorithm'], [self::ALGO_SHA256, self::ALGO_ED25519], true)) { + throw new InvalidArgumentException(sprintf('Invalid DKIM signing algorithm "%s".', $options['algorithm'])); + } + $headersToIgnore['return-path'] = true; + $headersToIgnore['x-transport'] = true; + foreach ($options['headers_to_ignore'] as $name) { + $headersToIgnore[strtolower($name)] = true; + } + unset($headersToIgnore['from']); + $signedHeaderNames = []; + $headerCanonData = ''; + $headers = $message->getPreparedHeaders(); + foreach ($headers->getNames() as $name) { + foreach ($headers->all($name) as $header) { + if (isset($headersToIgnore[strtolower($header->getName())])) { + continue; + } + + if ('' !== $header->getBodyAsString()) { + $headerCanonData .= $this->canonicalizeHeader($header->toString(), $options['header_canon']); + $signedHeaderNames[] = $header->getName(); + } + } + } + + [$bodyHash, $bodyLength] = $this->hashBody($message->getBody(), $options['body_canon'], $options['body_max_length']); + + $params = [ + 'v' => '1', + 'q' => 'dns/txt', + 'a' => $options['algorithm'], + 'bh' => base64_encode($bodyHash), + 'd' => $this->domainName, + 'h' => implode(': ', $signedHeaderNames), + 'i' => '@'.$this->domainName, + 's' => $this->selector, + 't' => time(), + 'c' => $options['header_canon'].'/'.$options['body_canon'], + ]; + + if ($options['body_show_length']) { + $params['l'] = $bodyLength; + } + if ($options['signature_expiration_delay']) { + $params['x'] = $params['t'] + $options['signature_expiration_delay']; + } + $value = ''; + foreach ($params as $k => $v) { + $value .= $k.'='.$v.'; '; + } + $value = trim($value); + $header = new UnstructuredHeader('DKIM-Signature', $value); + $headerCanonData .= rtrim($this->canonicalizeHeader($header->toString()."\r\n b=", $options['header_canon'])); + if (self::ALGO_SHA256 === $options['algorithm']) { + if (!openssl_sign($headerCanonData, $signature, $this->key, \OPENSSL_ALGO_SHA256)) { + throw new RuntimeException('Unable to sign DKIM hash: '.openssl_error_string()); + } + } else { + throw new \RuntimeException(sprintf('The "%s" DKIM signing algorithm is not supported yet.', self::ALGO_ED25519)); + } + $header->setValue($value.' b='.trim(chunk_split(base64_encode($signature), 73, ' '))); + $headers->add($header); + + return new Message($headers, $message->getBody()); + } + + private function canonicalizeHeader(string $header, string $headerCanon): string + { + if (self::CANON_RELAXED !== $headerCanon) { + return $header."\r\n"; + } + + $exploded = explode(':', $header, 2); + $name = strtolower(trim($exploded[0])); + $value = str_replace("\r\n", '', $exploded[1]); + $value = trim(preg_replace("/[ \t][ \t]+/", ' ', $value)); + + return $name.':'.$value."\r\n"; + } + + private function hashBody(AbstractPart $body, string $bodyCanon, int $maxLength): array + { + $hash = hash_init('sha256'); + $relaxed = self::CANON_RELAXED === $bodyCanon; + $currentLine = ''; + $emptyCounter = 0; + $isSpaceSequence = false; + $length = 0; + foreach ($body->bodyToIterable() as $chunk) { + $canon = ''; + for ($i = 0, $len = \strlen($chunk); $i < $len; ++$i) { + switch ($chunk[$i]) { + case "\r": + break; + case "\n": + // previous char is always \r + if ($relaxed) { + $isSpaceSequence = false; + } + if ('' === $currentLine) { + ++$emptyCounter; + } else { + $currentLine = ''; + $canon .= "\r\n"; + } + break; + case ' ': + case "\t": + if ($relaxed) { + $isSpaceSequence = true; + break; + } + // no break + default: + if ($emptyCounter > 0) { + $canon .= str_repeat("\r\n", $emptyCounter); + $emptyCounter = 0; + } + if ($isSpaceSequence) { + $currentLine .= ' '; + $canon .= ' '; + $isSpaceSequence = false; + } + $currentLine .= $chunk[$i]; + $canon .= $chunk[$i]; + } + } + + if ($length + \strlen($canon) >= $maxLength) { + $canon = substr($canon, 0, $maxLength - $length); + $length += \strlen($canon); + hash_update($hash, $canon); + + break; + } + + $length += \strlen($canon); + hash_update($hash, $canon); + } + + // Add trailing Line return if last line is non empty + if ('' !== $currentLine) { + hash_update($hash, "\r\n"); + $length += \strlen("\r\n"); + } + + if (!$relaxed && 0 === $length) { + hash_update($hash, "\r\n"); + $length = 2; + } + + return [hash_final($hash, true), $length]; + } +} diff --git a/tools/mailer/symfony/mime/Crypto/SMime.php b/tools/mailer/symfony/mime/Crypto/SMime.php new file mode 100644 index 000000000..cba95f210 --- /dev/null +++ b/tools/mailer/symfony/mime/Crypto/SMime.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Crypto; + +use Symfony\Component\Mime\Exception\RuntimeException; +use Symfony\Component\Mime\Part\SMimePart; + +/** + * @author Sebastiaan Stok + * + * @internal + */ +abstract class SMime +{ + protected function normalizeFilePath(string $path): string + { + if (!file_exists($path)) { + throw new RuntimeException(sprintf('File does not exist: "%s".', $path)); + } + + return 'file://'.str_replace('\\', '/', realpath($path)); + } + + protected function iteratorToFile(iterable $iterator, $stream): void + { + foreach ($iterator as $chunk) { + fwrite($stream, $chunk); + } + } + + protected function convertMessageToSMimePart($stream, string $type, string $subtype): SMimePart + { + rewind($stream); + + $headers = ''; + + while (!feof($stream)) { + $buffer = fread($stream, 78); + $headers .= $buffer; + + // Detect ending of header list + if (preg_match('/(\r\n\r\n|\n\n)/', $headers, $match)) { + $headersPosEnd = strpos($headers, $headerBodySeparator = $match[0]); + + break; + } + } + + $headers = $this->getMessageHeaders(trim(substr($headers, 0, $headersPosEnd))); + + fseek($stream, $headersPosEnd + \strlen($headerBodySeparator)); + + return new SMimePart($this->getStreamIterator($stream), $type, $subtype, $this->getParametersFromHeader($headers['content-type'])); + } + + protected function getStreamIterator($stream): iterable + { + while (!feof($stream)) { + yield str_replace("\n", "\r\n", str_replace("\r\n", "\n", fread($stream, 16372))); + } + } + + private function getMessageHeaders(string $headerData): array + { + $headers = []; + $headerLines = explode("\r\n", str_replace("\n", "\r\n", str_replace("\r\n", "\n", $headerData))); + $currentHeaderName = ''; + + // Transform header lines into an associative array + foreach ($headerLines as $headerLine) { + // Empty lines between headers indicate a new mime-entity + if ('' === $headerLine) { + break; + } + + // Handle headers that span multiple lines + if (!str_contains($headerLine, ':')) { + $headers[$currentHeaderName] .= ' '.trim($headerLine); + continue; + } + + $header = explode(':', $headerLine, 2); + $currentHeaderName = strtolower($header[0]); + $headers[$currentHeaderName] = trim($header[1]); + } + + return $headers; + } + + private function getParametersFromHeader(string $header): array + { + $params = []; + + preg_match_all('/(?P[a-z-0-9]+)=(?P"[^"]+"|(?:[^\s;]+|$))(?:\s+;)?/i', $header, $matches); + + foreach ($matches['value'] as $pos => $paramValue) { + $params[$matches['name'][$pos]] = trim($paramValue, '"'); + } + + return $params; + } +} diff --git a/tools/mailer/symfony/mime/Crypto/SMimeEncrypter.php b/tools/mailer/symfony/mime/Crypto/SMimeEncrypter.php new file mode 100644 index 000000000..c7c05452c --- /dev/null +++ b/tools/mailer/symfony/mime/Crypto/SMimeEncrypter.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Crypto; + +use Symfony\Component\Mime\Exception\RuntimeException; +use Symfony\Component\Mime\Message; + +/** + * @author Sebastiaan Stok + */ +final class SMimeEncrypter extends SMime +{ + private string|array $certs; + private int $cipher; + + /** + * @param string|string[] $certificate The path (or array of paths) of the file(s) containing the X.509 certificate(s) + * @param int|null $cipher A set of algorithms used to encrypt the message. Must be one of these PHP constants: https://www.php.net/manual/en/openssl.ciphers.php + */ + public function __construct(string|array $certificate, ?int $cipher = null) + { + if (!\extension_loaded('openssl')) { + throw new \LogicException('PHP extension "openssl" is required to use SMime.'); + } + + if (\is_array($certificate)) { + $this->certs = array_map($this->normalizeFilePath(...), $certificate); + } else { + $this->certs = $this->normalizeFilePath($certificate); + } + + $this->cipher = $cipher ?? \OPENSSL_CIPHER_AES_256_CBC; + } + + public function encrypt(Message $message): Message + { + $bufferFile = tmpfile(); + $outputFile = tmpfile(); + + $this->iteratorToFile($message->toIterable(), $bufferFile); + + if (!@openssl_pkcs7_encrypt(stream_get_meta_data($bufferFile)['uri'], stream_get_meta_data($outputFile)['uri'], $this->certs, [], 0, $this->cipher)) { + throw new RuntimeException(sprintf('Failed to encrypt S/Mime message. Error: "%s".', openssl_error_string())); + } + + $mimePart = $this->convertMessageToSMimePart($outputFile, 'application', 'pkcs7-mime'); + $mimePart->getHeaders() + ->addTextHeader('Content-Transfer-Encoding', 'base64') + ->addParameterizedHeader('Content-Disposition', 'attachment', ['name' => 'smime.p7m']) + ; + + return new Message($message->getHeaders(), $mimePart); + } +} diff --git a/tools/mailer/symfony/mime/Crypto/SMimeSigner.php b/tools/mailer/symfony/mime/Crypto/SMimeSigner.php new file mode 100644 index 000000000..eaa423d8c --- /dev/null +++ b/tools/mailer/symfony/mime/Crypto/SMimeSigner.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Crypto; + +use Symfony\Component\Mime\Exception\RuntimeException; +use Symfony\Component\Mime\Message; + +/** + * @author Sebastiaan Stok + */ +final class SMimeSigner extends SMime +{ + private string $signCertificate; + private string|array $signPrivateKey; + private int $signOptions; + private ?string $extraCerts; + + /** + * @param string $certificate The path of the file containing the signing certificate (in PEM format) + * @param string $privateKey The path of the file containing the private key (in PEM format) + * @param string|null $privateKeyPassphrase A passphrase of the private key (if any) + * @param string|null $extraCerts The path of the file containing intermediate certificates (in PEM format) needed by the signing certificate + * @param int|null $signOptions Bitwise operator options for openssl_pkcs7_sign() (@see https://secure.php.net/manual/en/openssl.pkcs7.flags.php) + */ + public function __construct(string $certificate, string $privateKey, ?string $privateKeyPassphrase = null, ?string $extraCerts = null, ?int $signOptions = null) + { + if (!\extension_loaded('openssl')) { + throw new \LogicException('PHP extension "openssl" is required to use SMime.'); + } + + $this->signCertificate = $this->normalizeFilePath($certificate); + + if (null !== $privateKeyPassphrase) { + $this->signPrivateKey = [$this->normalizeFilePath($privateKey), $privateKeyPassphrase]; + } else { + $this->signPrivateKey = $this->normalizeFilePath($privateKey); + } + + $this->signOptions = $signOptions ?? \PKCS7_DETACHED; + $this->extraCerts = $extraCerts ? realpath($extraCerts) : null; + } + + public function sign(Message $message): Message + { + $bufferFile = tmpfile(); + $outputFile = tmpfile(); + + $this->iteratorToFile($message->getBody()->toIterable(), $bufferFile); + + if (!@openssl_pkcs7_sign(stream_get_meta_data($bufferFile)['uri'], stream_get_meta_data($outputFile)['uri'], $this->signCertificate, $this->signPrivateKey, [], $this->signOptions, $this->extraCerts)) { + throw new RuntimeException(sprintf('Failed to sign S/Mime message. Error: "%s".', openssl_error_string())); + } + + return new Message($message->getHeaders(), $this->convertMessageToSMimePart($outputFile, 'multipart', 'signed')); + } +} diff --git a/tools/mailer/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php b/tools/mailer/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php new file mode 100644 index 000000000..897743fbd --- /dev/null +++ b/tools/mailer/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Registers custom mime types guessers. + * + * @author Fabien Potencier + */ +class AddMimeTypeGuesserPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container): void + { + if ($container->has('mime_types')) { + $definition = $container->findDefinition('mime_types'); + foreach ($container->findTaggedServiceIds('mime.mime_type_guesser', true) as $id => $attributes) { + $definition->addMethodCall('registerGuesser', [new Reference($id)]); + } + } + } +} diff --git a/tools/mailer/symfony/mime/DraftEmail.php b/tools/mailer/symfony/mime/DraftEmail.php new file mode 100644 index 000000000..82ce76369 --- /dev/null +++ b/tools/mailer/symfony/mime/DraftEmail.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Part\AbstractPart; + +/** + * @author Kevin Bond + */ +class DraftEmail extends Email +{ + public function __construct(?Headers $headers = null, ?AbstractPart $body = null) + { + parent::__construct($headers, $body); + + $this->getHeaders()->addTextHeader('X-Unsent', '1'); + } + + /** + * Override default behavior as draft emails do not require From/Sender/Date/Message-ID headers. + * These are added by the client that actually sends the email. + */ + public function getPreparedHeaders(): Headers + { + $headers = clone $this->getHeaders(); + + if (!$headers->has('MIME-Version')) { + $headers->addTextHeader('MIME-Version', '1.0'); + } + + $headers->remove('Bcc'); + + return $headers; + } +} diff --git a/tools/mailer/symfony/mime/Email.php b/tools/mailer/symfony/mime/Email.php new file mode 100644 index 000000000..233afc075 --- /dev/null +++ b/tools/mailer/symfony/mime/Email.php @@ -0,0 +1,576 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\Part\AbstractPart; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\File; +use Symfony\Component\Mime\Part\Multipart\AlternativePart; +use Symfony\Component\Mime\Part\Multipart\MixedPart; +use Symfony\Component\Mime\Part\Multipart\RelatedPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * @author Fabien Potencier + */ +class Email extends Message +{ + public const PRIORITY_HIGHEST = 1; + public const PRIORITY_HIGH = 2; + public const PRIORITY_NORMAL = 3; + public const PRIORITY_LOW = 4; + public const PRIORITY_LOWEST = 5; + + private const PRIORITY_MAP = [ + self::PRIORITY_HIGHEST => 'Highest', + self::PRIORITY_HIGH => 'High', + self::PRIORITY_NORMAL => 'Normal', + self::PRIORITY_LOW => 'Low', + self::PRIORITY_LOWEST => 'Lowest', + ]; + + /** + * @var resource|string|null + */ + private $text; + + private ?string $textCharset = null; + + /** + * @var resource|string|null + */ + private $html; + + private ?string $htmlCharset = null; + private array $attachments = []; + private ?AbstractPart $cachedBody = null; // Used to avoid wrong body hash in DKIM signatures with multiple parts (e.g. HTML + TEXT) due to multiple boundaries. + + /** + * @return $this + */ + public function subject(string $subject): static + { + return $this->setHeaderBody('Text', 'Subject', $subject); + } + + public function getSubject(): ?string + { + return $this->getHeaders()->getHeaderBody('Subject'); + } + + /** + * @return $this + */ + public function date(\DateTimeInterface $dateTime): static + { + return $this->setHeaderBody('Date', 'Date', $dateTime); + } + + public function getDate(): ?\DateTimeImmutable + { + return $this->getHeaders()->getHeaderBody('Date'); + } + + /** + * @return $this + */ + public function returnPath(Address|string $address): static + { + return $this->setHeaderBody('Path', 'Return-Path', Address::create($address)); + } + + public function getReturnPath(): ?Address + { + return $this->getHeaders()->getHeaderBody('Return-Path'); + } + + /** + * @return $this + */ + public function sender(Address|string $address): static + { + return $this->setHeaderBody('Mailbox', 'Sender', Address::create($address)); + } + + public function getSender(): ?Address + { + return $this->getHeaders()->getHeaderBody('Sender'); + } + + /** + * @return $this + */ + public function addFrom(Address|string ...$addresses): static + { + return $this->addListAddressHeaderBody('From', $addresses); + } + + /** + * @return $this + */ + public function from(Address|string ...$addresses): static + { + if (!$addresses) { + throw new LogicException('"from()" must be called with at least one address.'); + } + + return $this->setListAddressHeaderBody('From', $addresses); + } + + /** + * @return Address[] + */ + public function getFrom(): array + { + return $this->getHeaders()->getHeaderBody('From') ?: []; + } + + /** + * @return $this + */ + public function addReplyTo(Address|string ...$addresses): static + { + return $this->addListAddressHeaderBody('Reply-To', $addresses); + } + + /** + * @return $this + */ + public function replyTo(Address|string ...$addresses): static + { + return $this->setListAddressHeaderBody('Reply-To', $addresses); + } + + /** + * @return Address[] + */ + public function getReplyTo(): array + { + return $this->getHeaders()->getHeaderBody('Reply-To') ?: []; + } + + /** + * @return $this + */ + public function addTo(Address|string ...$addresses): static + { + return $this->addListAddressHeaderBody('To', $addresses); + } + + /** + * @return $this + */ + public function to(Address|string ...$addresses): static + { + return $this->setListAddressHeaderBody('To', $addresses); + } + + /** + * @return Address[] + */ + public function getTo(): array + { + return $this->getHeaders()->getHeaderBody('To') ?: []; + } + + /** + * @return $this + */ + public function addCc(Address|string ...$addresses): static + { + return $this->addListAddressHeaderBody('Cc', $addresses); + } + + /** + * @return $this + */ + public function cc(Address|string ...$addresses): static + { + return $this->setListAddressHeaderBody('Cc', $addresses); + } + + /** + * @return Address[] + */ + public function getCc(): array + { + return $this->getHeaders()->getHeaderBody('Cc') ?: []; + } + + /** + * @return $this + */ + public function addBcc(Address|string ...$addresses): static + { + return $this->addListAddressHeaderBody('Bcc', $addresses); + } + + /** + * @return $this + */ + public function bcc(Address|string ...$addresses): static + { + return $this->setListAddressHeaderBody('Bcc', $addresses); + } + + /** + * @return Address[] + */ + public function getBcc(): array + { + return $this->getHeaders()->getHeaderBody('Bcc') ?: []; + } + + /** + * Sets the priority of this message. + * + * The value is an integer where 1 is the highest priority and 5 is the lowest. + * + * @return $this + */ + public function priority(int $priority): static + { + if ($priority > 5) { + $priority = 5; + } elseif ($priority < 1) { + $priority = 1; + } + + return $this->setHeaderBody('Text', 'X-Priority', sprintf('%d (%s)', $priority, self::PRIORITY_MAP[$priority])); + } + + /** + * Get the priority of this message. + * + * The returned value is an integer where 1 is the highest priority and 5 + * is the lowest. + */ + public function getPriority(): int + { + [$priority] = sscanf($this->getHeaders()->getHeaderBody('X-Priority') ?? '', '%[1-5]'); + + return $priority ?? 3; + } + + /** + * @param resource|string|null $body + * + * @return $this + */ + public function text($body, string $charset = 'utf-8'): static + { + if (null !== $body && !\is_string($body) && !\is_resource($body)) { + throw new \TypeError(sprintf('The body must be a string, a resource or null (got "%s").', get_debug_type($body))); + } + + $this->cachedBody = null; + $this->text = $body; + $this->textCharset = $charset; + + return $this; + } + + /** + * @return resource|string|null + */ + public function getTextBody() + { + return $this->text; + } + + public function getTextCharset(): ?string + { + return $this->textCharset; + } + + /** + * @param resource|string|null $body + * + * @return $this + */ + public function html($body, string $charset = 'utf-8'): static + { + if (null !== $body && !\is_string($body) && !\is_resource($body)) { + throw new \TypeError(sprintf('The body must be a string, a resource or null (got "%s").', get_debug_type($body))); + } + + $this->cachedBody = null; + $this->html = $body; + $this->htmlCharset = $charset; + + return $this; + } + + /** + * @return resource|string|null + */ + public function getHtmlBody() + { + return $this->html; + } + + public function getHtmlCharset(): ?string + { + return $this->htmlCharset; + } + + /** + * @param resource|string $body + * + * @return $this + */ + public function attach($body, ?string $name = null, ?string $contentType = null): static + { + return $this->addPart(new DataPart($body, $name, $contentType)); + } + + /** + * @return $this + */ + public function attachFromPath(string $path, ?string $name = null, ?string $contentType = null): static + { + return $this->addPart(new DataPart(new File($path), $name, $contentType)); + } + + /** + * @param resource|string $body + * + * @return $this + */ + public function embed($body, ?string $name = null, ?string $contentType = null): static + { + return $this->addPart((new DataPart($body, $name, $contentType))->asInline()); + } + + /** + * @return $this + */ + public function embedFromPath(string $path, ?string $name = null, ?string $contentType = null): static + { + return $this->addPart((new DataPart(new File($path), $name, $contentType))->asInline()); + } + + /** + * @return $this + */ + public function addPart(DataPart $part): static + { + $this->cachedBody = null; + $this->attachments[] = $part; + + return $this; + } + + /** + * @return DataPart[] + */ + public function getAttachments(): array + { + return $this->attachments; + } + + public function getBody(): AbstractPart + { + if (null !== $body = parent::getBody()) { + return $body; + } + + return $this->generateBody(); + } + + public function ensureValidity(): void + { + $this->ensureBodyValid(); + + if ('1' === $this->getHeaders()->getHeaderBody('X-Unsent')) { + throw new LogicException('Cannot send messages marked as "draft".'); + } + + parent::ensureValidity(); + } + + private function ensureBodyValid(): void + { + if (null === $this->text && null === $this->html && !$this->attachments) { + throw new LogicException('A message must have a text or an HTML part or attachments.'); + } + } + + /** + * Generates an AbstractPart based on the raw body of a message. + * + * The most "complex" part generated by this method is when there is text and HTML bodies + * with related images for the HTML part and some attachments: + * + * multipart/mixed + * | + * |------------> multipart/related + * | | + * | |------------> multipart/alternative + * | | | + * | | ------------> text/plain (with content) + * | | | + * | | ------------> text/html (with content) + * | | + * | ------------> image/png (with content) + * | + * ------------> application/pdf (with content) + */ + private function generateBody(): AbstractPart + { + if (null !== $this->cachedBody) { + return $this->cachedBody; + } + + $this->ensureBodyValid(); + + [$htmlPart, $otherParts, $relatedParts] = $this->prepareParts(); + + $part = null === $this->text ? null : new TextPart($this->text, $this->textCharset); + if (null !== $htmlPart) { + if (null !== $part) { + $part = new AlternativePart($part, $htmlPart); + } else { + $part = $htmlPart; + } + } + + if ($relatedParts) { + $part = new RelatedPart($part, ...$relatedParts); + } + + if ($otherParts) { + if ($part) { + $part = new MixedPart($part, ...$otherParts); + } else { + $part = new MixedPart(...$otherParts); + } + } + + return $this->cachedBody = $part; + } + + private function prepareParts(): ?array + { + $names = []; + $htmlPart = null; + $html = $this->html; + if (null !== $html) { + $htmlPart = new TextPart($html, $this->htmlCharset, 'html'); + $html = $htmlPart->getBody(); + + $regexes = [ + ']*src\s*=\s*(?:([\'"])cid:(.+?)\\1|cid:([^>\s]+))', + '<\w+\s+[^>]*background\s*=\s*(?:([\'"])cid:(.+?)\\1|cid:([^>\s]+))', + ]; + $tmpMatches = []; + foreach ($regexes as $regex) { + preg_match_all('/'.$regex.'/i', $html, $tmpMatches); + $names = array_merge($names, $tmpMatches[2], $tmpMatches[3]); + } + $names = array_filter(array_unique($names)); + } + + $otherParts = $relatedParts = []; + foreach ($this->attachments as $part) { + foreach ($names as $name) { + if ($name !== $part->getName() && (!$part->hasContentId() || $name !== $part->getContentId())) { + continue; + } + if (isset($relatedParts[$name])) { + continue 2; + } + + if ($name !== $part->getContentId()) { + $html = str_replace('cid:'.$name, 'cid:'.$part->getContentId(), $html, $count); + } + $relatedParts[$name] = $part; + $part->setName($part->getContentId())->asInline(); + + continue 2; + } + + $otherParts[] = $part; + } + if (null !== $htmlPart) { + $htmlPart = new TextPart($html, $this->htmlCharset, 'html'); + } + + return [$htmlPart, $otherParts, array_values($relatedParts)]; + } + + /** + * @return $this + */ + private function setHeaderBody(string $type, string $name, $body): static + { + $this->getHeaders()->setHeaderBody($type, $name, $body); + + return $this; + } + + /** + * @return $this + */ + private function addListAddressHeaderBody(string $name, array $addresses): static + { + if (!$header = $this->getHeaders()->get($name)) { + return $this->setListAddressHeaderBody($name, $addresses); + } + $header->addAddresses(Address::createArray($addresses)); + + return $this; + } + + /** + * @return $this + */ + private function setListAddressHeaderBody(string $name, array $addresses): static + { + $addresses = Address::createArray($addresses); + $headers = $this->getHeaders(); + if ($header = $headers->get($name)) { + $header->setAddresses($addresses); + } else { + $headers->addMailboxListHeader($name, $addresses); + } + + return $this; + } + + /** + * @internal + */ + public function __serialize(): array + { + if (\is_resource($this->text)) { + $this->text = (new TextPart($this->text))->getBody(); + } + + if (\is_resource($this->html)) { + $this->html = (new TextPart($this->html))->getBody(); + } + + return [$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, parent::__serialize()]; + } + + /** + * @internal + */ + public function __unserialize(array $data): void + { + [$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, $parentData] = $data; + + parent::__unserialize($parentData); + } +} diff --git a/tools/mailer/symfony/mime/Encoder/AddressEncoderInterface.php b/tools/mailer/symfony/mime/Encoder/AddressEncoderInterface.php new file mode 100644 index 000000000..de477d884 --- /dev/null +++ b/tools/mailer/symfony/mime/Encoder/AddressEncoderInterface.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\Exception\AddressEncoderException; + +/** + * @author Christian Schmidt + */ +interface AddressEncoderInterface +{ + /** + * Encodes an email address. + * + * @throws AddressEncoderException if the email cannot be represented in + * the encoding implemented by this class + */ + public function encodeString(string $address): string; +} diff --git a/tools/mailer/symfony/mime/Encoder/Base64ContentEncoder.php b/tools/mailer/symfony/mime/Encoder/Base64ContentEncoder.php new file mode 100644 index 000000000..440868af7 --- /dev/null +++ b/tools/mailer/symfony/mime/Encoder/Base64ContentEncoder.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\Exception\RuntimeException; + +/** + * @author Fabien Potencier + */ +final class Base64ContentEncoder extends Base64Encoder implements ContentEncoderInterface +{ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable + { + if (!\is_resource($stream)) { + throw new \TypeError(sprintf('Method "%s" takes a stream as a first argument.', __METHOD__)); + } + + $filter = stream_filter_append($stream, 'convert.base64-encode', \STREAM_FILTER_READ, [ + 'line-length' => 0 >= $maxLineLength || 76 < $maxLineLength ? 76 : $maxLineLength, + 'line-break-chars' => "\r\n", + ]); + if (!\is_resource($filter)) { + throw new RuntimeException('Unable to set the base64 content encoder to the filter.'); + } + + while (!feof($stream)) { + yield fread($stream, 16372); + } + stream_filter_remove($filter); + } + + public function getName(): string + { + return 'base64'; + } +} diff --git a/tools/mailer/symfony/mime/Encoder/Base64Encoder.php b/tools/mailer/symfony/mime/Encoder/Base64Encoder.php new file mode 100644 index 000000000..710647857 --- /dev/null +++ b/tools/mailer/symfony/mime/Encoder/Base64Encoder.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + */ +class Base64Encoder implements EncoderInterface +{ + /** + * Takes an unencoded string and produces a Base64 encoded string from it. + * + * Base64 encoded strings have a maximum line length of 76 characters. + * If the first line needs to be shorter, indicate the difference with + * $firstLineOffset. + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + if (0 >= $maxLineLength || 76 < $maxLineLength) { + $maxLineLength = 76; + } + + $encodedString = base64_encode($string); + $firstLine = ''; + if (0 !== $firstLineOffset) { + $firstLine = substr($encodedString, 0, $maxLineLength - $firstLineOffset)."\r\n"; + $encodedString = substr($encodedString, $maxLineLength - $firstLineOffset); + } + + return $firstLine.trim(chunk_split($encodedString, $maxLineLength, "\r\n")); + } +} diff --git a/tools/mailer/symfony/mime/Encoder/Base64MimeHeaderEncoder.php b/tools/mailer/symfony/mime/Encoder/Base64MimeHeaderEncoder.php new file mode 100644 index 000000000..5c06f6d9a --- /dev/null +++ b/tools/mailer/symfony/mime/Encoder/Base64MimeHeaderEncoder.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + */ +final class Base64MimeHeaderEncoder extends Base64Encoder implements MimeHeaderEncoderInterface +{ + public function getName(): string + { + return 'B'; + } + + /** + * Takes an unencoded string and produces a Base64 encoded string from it. + * + * If the charset is iso-2022-jp, it uses mb_encode_mimeheader instead of + * default encodeString, otherwise pass to the parent method. + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + if ('iso-2022-jp' === strtolower($charset)) { + $old = mb_internal_encoding(); + mb_internal_encoding('utf-8'); + $newstring = mb_encode_mimeheader($string, 'iso-2022-jp', $this->getName(), "\r\n"); + mb_internal_encoding($old); + + return $newstring; + } + + return parent::encodeString($string, $charset, $firstLineOffset, $maxLineLength); + } +} diff --git a/tools/mailer/symfony/mime/Encoder/ContentEncoderInterface.php b/tools/mailer/symfony/mime/Encoder/ContentEncoderInterface.php new file mode 100644 index 000000000..a45ad04c2 --- /dev/null +++ b/tools/mailer/symfony/mime/Encoder/ContentEncoderInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + */ +interface ContentEncoderInterface extends EncoderInterface +{ + /** + * Encodes the stream to a Generator. + * + * @param resource $stream + */ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable; + + /** + * Gets the MIME name of this content encoding scheme. + */ + public function getName(): string; +} diff --git a/tools/mailer/symfony/mime/Encoder/EightBitContentEncoder.php b/tools/mailer/symfony/mime/Encoder/EightBitContentEncoder.php new file mode 100644 index 000000000..82831209e --- /dev/null +++ b/tools/mailer/symfony/mime/Encoder/EightBitContentEncoder.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Fabien Potencier + */ +final class EightBitContentEncoder implements ContentEncoderInterface +{ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable + { + while (!feof($stream)) { + yield fread($stream, 16372); + } + } + + public function getName(): string + { + return '8bit'; + } + + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + return $string; + } +} diff --git a/tools/mailer/symfony/mime/Encoder/EncoderInterface.php b/tools/mailer/symfony/mime/Encoder/EncoderInterface.php new file mode 100644 index 000000000..bbf6d4886 --- /dev/null +++ b/tools/mailer/symfony/mime/Encoder/EncoderInterface.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + */ +interface EncoderInterface +{ + /** + * Encode a given string to produce an encoded string. + * + * @param int $firstLineOffset if first line needs to be shorter + * @param int $maxLineLength - 0 indicates the default length for this encoding + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string; +} diff --git a/tools/mailer/symfony/mime/Encoder/IdnAddressEncoder.php b/tools/mailer/symfony/mime/Encoder/IdnAddressEncoder.php new file mode 100644 index 000000000..b56e7e396 --- /dev/null +++ b/tools/mailer/symfony/mime/Encoder/IdnAddressEncoder.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * An IDN email address encoder. + * + * Encodes the domain part of an address using IDN. This is compatible will all + * SMTP servers. + * + * Note: It leaves the local part as is. In case there are non-ASCII characters + * in the local part then it depends on the SMTP Server if this is supported. + * + * @author Christian Schmidt + */ +final class IdnAddressEncoder implements AddressEncoderInterface +{ + /** + * Encodes the domain part of an address using IDN. + */ + public function encodeString(string $address): string + { + $i = strrpos($address, '@'); + if (false !== $i) { + $local = substr($address, 0, $i); + $domain = substr($address, $i + 1); + + if (preg_match('/[^\x00-\x7F]/', $domain)) { + $address = sprintf('%s@%s', $local, idn_to_ascii($domain, \IDNA_DEFAULT | \IDNA_USE_STD3_RULES | \IDNA_CHECK_BIDI | \IDNA_CHECK_CONTEXTJ | \IDNA_NONTRANSITIONAL_TO_ASCII, \INTL_IDNA_VARIANT_UTS46)); + } + } + + return $address; + } +} diff --git a/tools/swift/classes/Swift/Mime/HeaderEncoder.php b/tools/mailer/symfony/mime/Encoder/MimeHeaderEncoderInterface.php similarity index 52% rename from tools/swift/classes/Swift/Mime/HeaderEncoder.php rename to tools/mailer/symfony/mime/Encoder/MimeHeaderEncoderInterface.php index 08fd453d6..fff2c782b 100644 --- a/tools/swift/classes/Swift/Mime/HeaderEncoder.php +++ b/tools/mailer/symfony/mime/Encoder/MimeHeaderEncoderInterface.php @@ -1,24 +1,23 @@ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +namespace Symfony\Component\Mime\Encoder; + /** - * Interface for all Header Encoding schemes. - * * @author Chris Corbyn */ -interface Swift_Mime_HeaderEncoder extends Swift_Encoder +interface MimeHeaderEncoderInterface { /** * Get the MIME name of this content encoding scheme. - * - * @return string */ - public function getName(); + public function getName(): string; } diff --git a/tools/mailer/symfony/mime/Encoder/QpContentEncoder.php b/tools/mailer/symfony/mime/Encoder/QpContentEncoder.php new file mode 100644 index 000000000..6f420fff3 --- /dev/null +++ b/tools/mailer/symfony/mime/Encoder/QpContentEncoder.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Lars Strojny + */ +final class QpContentEncoder implements ContentEncoderInterface +{ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable + { + if (!\is_resource($stream)) { + throw new \TypeError(sprintf('Method "%s" takes a stream as a first argument.', __METHOD__)); + } + + // we don't use PHP stream filters here as the content should be small enough + yield $this->encodeString(stream_get_contents($stream), 'utf-8', 0, $maxLineLength); + } + + public function getName(): string + { + return 'quoted-printable'; + } + + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + return $this->standardize(quoted_printable_encode($string)); + } + + /** + * Make sure CRLF is correct and HT/SPACE are in valid places. + */ + private function standardize(string $string): string + { + // transform CR or LF to CRLF + $string = preg_replace('~=0D(?!=0A)|(? substr_replace($string, '=09', -1), + 0x20 => substr_replace($string, '=20', -1), + default => $string, + }; + } +} diff --git a/tools/swift/classes/Swift/Encoder/QpEncoder.php b/tools/mailer/symfony/mime/Encoder/QpEncoder.php similarity index 55% rename from tools/swift/classes/Swift/Encoder/QpEncoder.php rename to tools/mailer/symfony/mime/Encoder/QpEncoder.php index edec10c51..160dde329 100644 --- a/tools/swift/classes/Swift/Encoder/QpEncoder.php +++ b/tools/mailer/symfony/mime/Encoder/QpEncoder.php @@ -1,42 +1,27 @@ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\CharacterStream; + /** - * Handles Quoted Printable (QP) Encoding in Swift Mailer. - * - * Possibly the most accurate RFC 2045 QP implementation found in PHP. - * * @author Chris Corbyn */ -class Swift_Encoder_QpEncoder implements Swift_Encoder +class QpEncoder implements EncoderInterface { - /** - * The CharacterStream used for reading characters (as opposed to bytes). - * - * @var Swift_CharacterStream - */ - protected $_charStream; - - /** - * A filter used if input should be canonicalized. - * - * @var Swift_StreamFilter - */ - protected $_filter; - /** * Pre-computed QP for HUGE optimization. - * - * @var string[] */ - protected static $_qpMap = array( + private const QP_MAP = [ 0 => '=00', 1 => '=01', 2 => '=02', 3 => '=03', 4 => '=04', 5 => '=05', 6 => '=06', 7 => '=07', 8 => '=08', 9 => '=09', 10 => '=0A', 11 => '=0B', 12 => '=0C', 13 => '=0D', 14 => '=0E', @@ -89,60 +74,34 @@ class Swift_Encoder_QpEncoder implements Swift_Encoder 245 => '=F5', 246 => '=F6', 247 => '=F7', 248 => '=F8', 249 => '=F9', 250 => '=FA', 251 => '=FB', 252 => '=FC', 253 => '=FD', 254 => '=FE', 255 => '=FF', - ); + ]; - protected static $_safeMapShare = array(); + private static array $safeMapShare = []; /** * A map of non-encoded ascii characters. * * @var string[] - */ - protected $_safeMap = array(); - - /** - * Creates a new QpEncoder for the given CharacterStream. * - * @param Swift_CharacterStream $charStream to use for reading characters - * @param Swift_StreamFilter $filter if input should be canonicalized + * @internal */ - public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null) - { - $this->_charStream = $charStream; - if (!isset(self::$_safeMapShare[$this->getSafeMapShareId()])) { - $this->initSafeMap(); - self::$_safeMapShare[$this->getSafeMapShareId()] = $this->_safeMap; - } else { - $this->_safeMap = self::$_safeMapShare[$this->getSafeMapShareId()]; - } - $this->_filter = $filter; - } + protected array $safeMap = []; - public function __sleep() + public function __construct() { - return array('_charStream', '_filter'); - } - - public function __wakeup() - { - if (!isset(self::$_safeMapShare[$this->getSafeMapShareId()])) { + $id = static::class; + if (!isset(self::$safeMapShare[$id])) { $this->initSafeMap(); - self::$_safeMapShare[$this->getSafeMapShareId()] = $this->_safeMap; + self::$safeMapShare[$id] = $this->safeMap; } else { - $this->_safeMap = self::$_safeMapShare[$this->getSafeMapShareId()]; + $this->safeMap = self::$safeMapShare[$id]; } } - protected function getSafeMapShareId() + protected function initSafeMap(): void { - return get_class($this); - } - - protected function initSafeMap() - { - foreach (array_merge( - array(0x09, 0x20), range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte) { - $this->_safeMap[$byte] = chr($byte); + foreach (array_merge([0x09, 0x20], range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte) { + $this->safeMap[$byte] = \chr($byte); } } @@ -152,14 +111,8 @@ class Swift_Encoder_QpEncoder implements Swift_Encoder * QP encoded strings have a maximum line length of 76 characters. * If the first line needs to be shorter, indicate the difference with * $firstLineOffset. - * - * @param string $string to encode - * @param int $firstLineOffset, optional - * @param int $maxLineLength, optional 0 indicates the default of 76 chars - * - * @return string */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string { if ($maxLineLength > 76 || $maxLineLength <= 0) { $maxLineLength = 76; @@ -167,40 +120,21 @@ class Swift_Encoder_QpEncoder implements Swift_Encoder $thisLineLength = $maxLineLength - $firstLineOffset; - $lines = array(); + $lines = []; $lNo = 0; $lines[$lNo] = ''; $currentLine = &$lines[$lNo++]; $size = $lineLen = 0; - - $this->_charStream->flushContents(); - $this->_charStream->importString($string); + $charStream = new CharacterStream($string, $charset); // Fetching more than 4 chars at one is slower, as is fetching fewer bytes // Conveniently 4 chars is the UTF-8 safe number since UTF-8 has up to 6 // bytes per char and (6 * 4 * 3 = 72 chars per line) * =NN is 3 bytes - while (false !== $bytes = $this->_nextSequence()) { - // If we're filtering the input - if (isset($this->_filter)) { - // If we can't filter because we need more bytes - while ($this->_filter->shouldBuffer($bytes)) { - // Then collect bytes into the buffer - if (false === $moreBytes = $this->_nextSequence(1)) { - break; - } - - foreach ($moreBytes as $b) { - $bytes[] = $b; - } - } - // And filter them - $bytes = $this->_filter->filter($bytes); - } - - $enc = $this->_encodeByteSequence($bytes, $size); + while (null !== $bytes = $charStream->readBytes(4)) { + $enc = $this->encodeByteSequence($bytes, $size); $i = strpos($enc, '=0D=0A'); - $newLineLength = $lineLen + ($i === false ? $size : $i); + $newLineLength = $lineLen + (false === $i ? $size : $i); if ($currentLine && $newLineLength >= $thisLineLength) { $lines[$lNo] = ''; @@ -211,7 +145,7 @@ class Swift_Encoder_QpEncoder implements Swift_Encoder $currentLine .= $enc; - if ($i === false) { + if (false === $i) { $lineLen += $size; } else { // 6 is the length of '=0D=0A'. @@ -219,37 +153,22 @@ class Swift_Encoder_QpEncoder implements Swift_Encoder } } - return $this->_standardize(implode("=\r\n", $lines)); - } - - /** - * Updates the charset used. - * - * @param string $charset - */ - public function charsetChanged($charset) - { - $this->_charStream->setCharacterSet($charset); + return $this->standardize(implode("=\r\n", $lines)); } /** * Encode the given byte array into a verbatim QP form. - * - * @param int[] $bytes - * @param int $size - * - * @return string */ - protected function _encodeByteSequence(array $bytes, &$size) + private function encodeByteSequence(array $bytes, int &$size): string { $ret = ''; $size = 0; foreach ($bytes as $b) { - if (isset($this->_safeMap[$b])) { - $ret .= $this->_safeMap[$b]; + if (isset($this->safeMap[$b])) { + $ret .= $this->safeMap[$b]; ++$size; } else { - $ret .= self::$_qpMap[$b]; + $ret .= self::QP_MAP[$b]; $size += 3; } } @@ -257,44 +176,17 @@ class Swift_Encoder_QpEncoder implements Swift_Encoder return $ret; } - /** - * Get the next sequence of bytes to read from the char stream. - * - * @param int $size number of bytes to read - * - * @return int[] - */ - protected function _nextSequence($size = 4) - { - return $this->_charStream->readBytes($size); - } - /** * Make sure CRLF is correct and HT/SPACE are in valid places. - * - * @param string $string - * - * @return string */ - protected function _standardize($string) + private function standardize(string $string): string { - $string = str_replace(array("\t=0D=0A", ' =0D=0A', '=0D=0A'), - array("=09\r\n", "=20\r\n", "\r\n"), $string - ); - switch ($end = ord(substr($string, -1))) { - case 0x09: - case 0x20: - $string = substr_replace($string, self::$_qpMap[$end], -1); - } + $string = str_replace(["\t=0D=0A", ' =0D=0A', '=0D=0A'], ["=09\r\n", "=20\r\n", "\r\n"], $string); - return $string; - } - - /** - * Make a deep copy of object. - */ - public function __clone() - { - $this->_charStream = clone $this->_charStream; + return match ($end = \ord(substr($string, -1))) { + 0x09, + 0x20 => substr_replace($string, self::QP_MAP[$end], -1), + default => $string, + }; } } diff --git a/tools/mailer/symfony/mime/Encoder/QpMimeHeaderEncoder.php b/tools/mailer/symfony/mime/Encoder/QpMimeHeaderEncoder.php new file mode 100644 index 000000000..d1d38375f --- /dev/null +++ b/tools/mailer/symfony/mime/Encoder/QpMimeHeaderEncoder.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + */ +final class QpMimeHeaderEncoder extends QpEncoder implements MimeHeaderEncoderInterface +{ + protected function initSafeMap(): void + { + foreach (array_merge( + range(0x61, 0x7A), range(0x41, 0x5A), + range(0x30, 0x39), [0x20, 0x21, 0x2A, 0x2B, 0x2D, 0x2F] + ) as $byte) { + $this->safeMap[$byte] = \chr($byte); + } + } + + public function getName(): string + { + return 'Q'; + } + + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + return str_replace([' ', '=20', "=\r\n"], ['_', '_', "\r\n"], + parent::encodeString($string, $charset, $firstLineOffset, $maxLineLength) + ); + } +} diff --git a/tools/mailer/symfony/mime/Encoder/Rfc2231Encoder.php b/tools/mailer/symfony/mime/Encoder/Rfc2231Encoder.php new file mode 100644 index 000000000..4d93dc641 --- /dev/null +++ b/tools/mailer/symfony/mime/Encoder/Rfc2231Encoder.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\CharacterStream; + +/** + * @author Chris Corbyn + */ +final class Rfc2231Encoder implements EncoderInterface +{ + /** + * Takes an unencoded string and produces a string encoded according to RFC 2231 from it. + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + $lines = []; + $lineCount = 0; + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + + if (0 >= $maxLineLength) { + $maxLineLength = 75; + } + + $charStream = new CharacterStream($string, $charset); + $thisLineLength = $maxLineLength - $firstLineOffset; + + while (null !== $char = $charStream->read(4)) { + $encodedChar = rawurlencode($char); + if ('' !== $currentLine && \strlen($currentLine.$encodedChar) > $thisLineLength) { + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + $thisLineLength = $maxLineLength; + } + $currentLine .= $encodedChar; + } + + return implode("\r\n", $lines); + } +} diff --git a/tools/mailer/symfony/mime/Exception/AddressEncoderException.php b/tools/mailer/symfony/mime/Exception/AddressEncoderException.php new file mode 100644 index 000000000..51ee2e06f --- /dev/null +++ b/tools/mailer/symfony/mime/Exception/AddressEncoderException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + */ +class AddressEncoderException extends RfcComplianceException +{ +} diff --git a/tools/mailer/symfony/mime/Exception/ExceptionInterface.php b/tools/mailer/symfony/mime/Exception/ExceptionInterface.php new file mode 100644 index 000000000..11933900f --- /dev/null +++ b/tools/mailer/symfony/mime/Exception/ExceptionInterface.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/tools/mailer/symfony/mime/Exception/InvalidArgumentException.php b/tools/mailer/symfony/mime/Exception/InvalidArgumentException.php new file mode 100644 index 000000000..e89ebae20 --- /dev/null +++ b/tools/mailer/symfony/mime/Exception/InvalidArgumentException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/tools/mailer/symfony/mime/Exception/LogicException.php b/tools/mailer/symfony/mime/Exception/LogicException.php new file mode 100644 index 000000000..0508ee73c --- /dev/null +++ b/tools/mailer/symfony/mime/Exception/LogicException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/tools/mailer/symfony/mime/Exception/RfcComplianceException.php b/tools/mailer/symfony/mime/Exception/RfcComplianceException.php new file mode 100644 index 000000000..26e4a5099 --- /dev/null +++ b/tools/mailer/symfony/mime/Exception/RfcComplianceException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + */ +class RfcComplianceException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/tools/mailer/symfony/mime/Exception/RuntimeException.php b/tools/mailer/symfony/mime/Exception/RuntimeException.php new file mode 100644 index 000000000..fb018b006 --- /dev/null +++ b/tools/mailer/symfony/mime/Exception/RuntimeException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/tools/mailer/symfony/mime/FileBinaryMimeTypeGuesser.php b/tools/mailer/symfony/mime/FileBinaryMimeTypeGuesser.php new file mode 100644 index 000000000..363ac81c4 --- /dev/null +++ b/tools/mailer/symfony/mime/FileBinaryMimeTypeGuesser.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Exception\LogicException; + +/** + * Guesses the MIME type with the binary "file" (only available on *nix). + * + * @author Bernhard Schussek + */ +class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface +{ + /** + * The $cmd pattern must contain a "%s" string that will be replaced + * with the file name to guess. + * + * The command output must start with the MIME type of the file. + * + * @param string $cmd The command to run to get the MIME type of a file + */ + public function __construct( + private string $cmd = 'file -b --mime -- %s 2>/dev/null', + ) { + } + + public function isGuesserSupported(): bool + { + static $supported = null; + + if (null !== $supported) { + return $supported; + } + + if ('\\' === \DIRECTORY_SEPARATOR || !\function_exists('passthru') || !\function_exists('escapeshellarg')) { + return $supported = false; + } + + ob_start(); + passthru('command -v file', $exitStatus); + $binPath = trim(ob_get_clean()); + + return $supported = 0 === $exitStatus && '' !== $binPath; + } + + public function guessMimeType(string $path): ?string + { + if (!is_file($path) || !is_readable($path)) { + throw new InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); + } + + if (!$this->isGuesserSupported()) { + throw new LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); + } + + ob_start(); + + // need to use --mime instead of -i. see #6641 + passthru(sprintf($this->cmd, escapeshellarg((str_starts_with($path, '-') ? './' : '').$path)), $return); + if ($return > 0) { + ob_end_clean(); + + return null; + } + + $type = trim(ob_get_clean()); + + if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-\+\.]+)#i', $type, $match)) { + // it's not a type, but an error message + return null; + } + + return $match[1]; + } +} diff --git a/tools/mailer/symfony/mime/FileinfoMimeTypeGuesser.php b/tools/mailer/symfony/mime/FileinfoMimeTypeGuesser.php new file mode 100644 index 000000000..89a9d3e05 --- /dev/null +++ b/tools/mailer/symfony/mime/FileinfoMimeTypeGuesser.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Exception\LogicException; + +/** + * Guesses the MIME type using the PECL extension FileInfo. + * + * @author Bernhard Schussek + */ +class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface +{ + /** + * @param string|null $magicFile A magic file to use with the finfo instance + * + * @see http://www.php.net/manual/en/function.finfo-open.php + */ + public function __construct( + private ?string $magicFile = null, + ) { + } + + public function isGuesserSupported(): bool + { + return \function_exists('finfo_open'); + } + + public function guessMimeType(string $path): ?string + { + if (!is_file($path) || !is_readable($path)) { + throw new InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); + } + + if (!$this->isGuesserSupported()) { + throw new LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); + } + + if (false === $finfo = new \finfo(\FILEINFO_MIME_TYPE, $this->magicFile)) { + return null; + } + $mimeType = $finfo->file($path); + + if ($mimeType && 0 === (\strlen($mimeType) % 2)) { + $mimeStart = substr($mimeType, 0, \strlen($mimeType) >> 1); + $mimeType = $mimeStart.$mimeStart === $mimeType ? $mimeStart : $mimeType; + } + + return $mimeType; + } +} diff --git a/tools/mailer/symfony/mime/Header/AbstractHeader.php b/tools/mailer/symfony/mime/Header/AbstractHeader.php new file mode 100644 index 000000000..556c0aa0b --- /dev/null +++ b/tools/mailer/symfony/mime/Header/AbstractHeader.php @@ -0,0 +1,294 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Encoder\QpMimeHeaderEncoder; + +/** + * An abstract base MIME Header. + * + * @author Chris Corbyn + */ +abstract class AbstractHeader implements HeaderInterface +{ + public const PHRASE_PATTERN = '(?:(?:(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]+(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?)|(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?"((?:(?:[ \t]*(?:\r\n))?[ \t])?(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21\x23-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])))*(?:(?:[ \t]*(?:\r\n))?[ \t])?"(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?))+?)'; + + private static QpMimeHeaderEncoder $encoder; + + private string $name; + private int $lineLength = 76; + private ?string $lang = null; + private string $charset = 'utf-8'; + + public function __construct(string $name) + { + $this->name = $name; + } + + public function setCharset(string $charset): void + { + $this->charset = $charset; + } + + public function getCharset(): ?string + { + return $this->charset; + } + + /** + * Set the language used in this Header. + * + * For example, for US English, 'en-us'. + */ + public function setLanguage(string $lang): void + { + $this->lang = $lang; + } + + public function getLanguage(): ?string + { + return $this->lang; + } + + public function getName(): string + { + return $this->name; + } + + public function setMaxLineLength(int $lineLength): void + { + $this->lineLength = $lineLength; + } + + public function getMaxLineLength(): int + { + return $this->lineLength; + } + + public function toString(): string + { + return $this->tokensToString($this->toTokens()); + } + + /** + * Produces a compliant, formatted RFC 2822 'phrase' based on the string given. + * + * @param string $string as displayed + * @param bool $shorten the first line to make remove for header name + */ + protected function createPhrase(HeaderInterface $header, string $string, string $charset, bool $shorten = false): string + { + // Treat token as exactly what was given + $phraseStr = $string; + + // If it's not valid + if (!preg_match('/^'.self::PHRASE_PATTERN.'$/D', $phraseStr)) { + // .. but it is just ascii text, try escaping some characters + // and make it a quoted-string + if (preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $phraseStr)) { + foreach (['\\', '"'] as $char) { + $phraseStr = str_replace($char, '\\'.$char, $phraseStr); + } + $phraseStr = '"'.$phraseStr.'"'; + } else { + // ... otherwise it needs encoding + // Determine space remaining on line if first line + if ($shorten) { + $usedLength = \strlen($header->getName().': '); + } else { + $usedLength = 0; + } + $phraseStr = $this->encodeWords($header, $string, $usedLength); + } + } elseif (str_contains($phraseStr, '(')) { + foreach (['\\', '"'] as $char) { + $phraseStr = str_replace($char, '\\'.$char, $phraseStr); + } + $phraseStr = '"'.$phraseStr.'"'; + } + + return $phraseStr; + } + + /** + * Encode needed word tokens within a string of input. + */ + protected function encodeWords(HeaderInterface $header, string $input, int $usedLength = -1): string + { + $value = ''; + $tokens = $this->getEncodableWordTokens($input); + foreach ($tokens as $token) { + // See RFC 2822, Sect 2.2 (really 2.2 ??) + if ($this->tokenNeedsEncoding($token)) { + // Don't encode starting WSP + $firstChar = substr($token, 0, 1); + switch ($firstChar) { + case ' ': + case "\t": + $value .= $firstChar; + $token = substr($token, 1); + } + + if (-1 == $usedLength) { + $usedLength = \strlen($header->getName().': ') + \strlen($value); + } + $value .= $this->getTokenAsEncodedWord($token, $usedLength); + } else { + $value .= $token; + } + } + + return $value; + } + + protected function tokenNeedsEncoding(string $token): bool + { + return (bool) preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token); + } + + /** + * Splits a string into tokens in blocks of words which can be encoded quickly. + * + * @return string[] + */ + protected function getEncodableWordTokens(string $string): array + { + $tokens = []; + $encodedToken = ''; + // Split at all whitespace boundaries + foreach (preg_split('~(?=[\t ])~', $string) as $token) { + if ($this->tokenNeedsEncoding($token)) { + $encodedToken .= $token; + } else { + if ('' !== $encodedToken) { + $tokens[] = $encodedToken; + $encodedToken = ''; + } + $tokens[] = $token; + } + } + if ('' !== $encodedToken) { + $tokens[] = $encodedToken; + } + + foreach ($tokens as $i => $token) { + // whitespace(s) between 2 encoded tokens + if ( + 0 < $i + && isset($tokens[$i + 1]) + && preg_match('~^[\t ]+$~', $token) + && $this->tokenNeedsEncoding($tokens[$i - 1]) + && $this->tokenNeedsEncoding($tokens[$i + 1]) + ) { + $tokens[$i - 1] .= $token.$tokens[$i + 1]; + array_splice($tokens, $i, 2); + } + } + + return $tokens; + } + + /** + * Get a token as an encoded word for safe insertion into headers. + */ + protected function getTokenAsEncodedWord(string $token, int $firstLineOffset = 0): string + { + self::$encoder ??= new QpMimeHeaderEncoder(); + + // Adjust $firstLineOffset to account for space needed for syntax + $charsetDecl = $this->charset; + if (null !== $this->lang) { + $charsetDecl .= '*'.$this->lang; + } + $encodingWrapperLength = \strlen('=?'.$charsetDecl.'?'.self::$encoder->getName().'??='); + + if ($firstLineOffset >= 75) { + // Does this logic need to be here? + $firstLineOffset = 0; + } + + $encodedTextLines = explode("\r\n", + self::$encoder->encodeString($token, $this->charset, $firstLineOffset, 75 - $encodingWrapperLength) + ); + + if ('iso-2022-jp' !== strtolower($this->charset)) { + // special encoding for iso-2022-jp using mb_encode_mimeheader + foreach ($encodedTextLines as $lineNum => $line) { + $encodedTextLines[$lineNum] = '=?'.$charsetDecl.'?'.self::$encoder->getName().'?'.$line.'?='; + } + } + + return implode("\r\n ", $encodedTextLines); + } + + /** + * Generates tokens from the given string which include CRLF as individual tokens. + * + * @return string[] + */ + protected function generateTokenLines(string $token): array + { + return preg_split('~(\r\n)~', $token, -1, \PREG_SPLIT_DELIM_CAPTURE); + } + + /** + * Generate a list of all tokens in the final header. + */ + protected function toTokens(?string $string = null): array + { + $string ??= $this->getBodyAsString(); + + $tokens = []; + // Generate atoms; split at all invisible boundaries followed by WSP + foreach (preg_split('~(?=[ \t])~', $string) as $token) { + $newTokens = $this->generateTokenLines($token); + foreach ($newTokens as $newToken) { + $tokens[] = $newToken; + } + } + + return $tokens; + } + + /** + * Takes an array of tokens which appear in the header and turns them into + * an RFC 2822 compliant string, adding FWSP where needed. + * + * @param string[] $tokens + */ + private function tokensToString(array $tokens): string + { + $lineCount = 0; + $headerLines = []; + $headerLines[] = $this->name.': '; + $currentLine = &$headerLines[$lineCount++]; + + // Build all tokens back into compliant header + foreach ($tokens as $i => $token) { + // Line longer than specified maximum or token was just a new line + if (("\r\n" === $token) + || ($i > 0 && \strlen($currentLine.$token) > $this->lineLength) + && '' !== $currentLine) { + $headerLines[] = ''; + $currentLine = &$headerLines[$lineCount++]; + } + + // Append token to the line + if ("\r\n" !== $token) { + $currentLine .= $token; + } + } + + // Implode with FWS (RFC 2822, 2.2.3) + return implode("\r\n", $headerLines); + } +} diff --git a/tools/mailer/symfony/mime/Header/DateHeader.php b/tools/mailer/symfony/mime/Header/DateHeader.php new file mode 100644 index 000000000..2b361802f --- /dev/null +++ b/tools/mailer/symfony/mime/Header/DateHeader.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +/** + * A Date MIME Header. + * + * @author Chris Corbyn + */ +final class DateHeader extends AbstractHeader +{ + private \DateTimeImmutable $dateTime; + + public function __construct(string $name, \DateTimeInterface $date) + { + parent::__construct($name); + + $this->setDateTime($date); + } + + /** + * @param \DateTimeInterface $body + */ + public function setBody(mixed $body): void + { + $this->setDateTime($body); + } + + public function getBody(): \DateTimeImmutable + { + return $this->getDateTime(); + } + + public function getDateTime(): \DateTimeImmutable + { + return $this->dateTime; + } + + /** + * Set the date-time of the Date in this Header. + * + * If a DateTime instance is provided, it is converted to DateTimeImmutable. + */ + public function setDateTime(\DateTimeInterface $dateTime): void + { + $this->dateTime = \DateTimeImmutable::createFromInterface($dateTime); + } + + public function getBodyAsString(): string + { + return $this->dateTime->format(\DateTimeInterface::RFC2822); + } +} diff --git a/tools/mailer/symfony/mime/Header/HeaderInterface.php b/tools/mailer/symfony/mime/Header/HeaderInterface.php new file mode 100644 index 000000000..6bb1d5dcb --- /dev/null +++ b/tools/mailer/symfony/mime/Header/HeaderInterface.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +/** + * A MIME Header. + * + * @author Chris Corbyn + */ +interface HeaderInterface +{ + /** + * Sets the body. + * + * The type depends on the Header concrete class. + */ + public function setBody(mixed $body): void; + + /** + * Gets the body. + * + * The return type depends on the Header concrete class. + */ + public function getBody(): mixed; + + public function setCharset(string $charset): void; + + public function getCharset(): ?string; + + public function setLanguage(string $lang): void; + + public function getLanguage(): ?string; + + public function getName(): string; + + public function setMaxLineLength(int $lineLength): void; + + public function getMaxLineLength(): int; + + /** + * Gets this Header rendered as a compliant string. + */ + public function toString(): string; + + /** + * Gets the header's body, prepared for folding into a final header value. + * + * This is not necessarily RFC 2822 compliant since folding white space is + * not added at this stage (see {@link toString()} for that). + */ + public function getBodyAsString(): string; +} diff --git a/tools/mailer/symfony/mime/Header/Headers.php b/tools/mailer/symfony/mime/Header/Headers.php new file mode 100644 index 000000000..164f4ac33 --- /dev/null +++ b/tools/mailer/symfony/mime/Header/Headers.php @@ -0,0 +1,316 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\LogicException; + +/** + * A collection of headers. + * + * @author Fabien Potencier + */ +final class Headers +{ + private const UNIQUE_HEADERS = [ + 'date', 'from', 'sender', 'reply-to', 'to', 'cc', 'bcc', + 'message-id', 'in-reply-to', 'references', 'subject', + ]; + private const HEADER_CLASS_MAP = [ + 'date' => DateHeader::class, + 'from' => MailboxListHeader::class, + 'sender' => MailboxHeader::class, + 'reply-to' => MailboxListHeader::class, + 'to' => MailboxListHeader::class, + 'cc' => MailboxListHeader::class, + 'bcc' => MailboxListHeader::class, + 'message-id' => IdentificationHeader::class, + 'in-reply-to' => [UnstructuredHeader::class, IdentificationHeader::class], // `In-Reply-To` and `References` are less strict than RFC 2822 (3.6.4) to allow users entering the original email's ... + 'references' => [UnstructuredHeader::class, IdentificationHeader::class], // ... `Message-ID`, even if that is no valid `msg-id` + 'return-path' => PathHeader::class, + ]; + + /** + * @var HeaderInterface[][] + */ + private array $headers = []; + private int $lineLength = 76; + + public function __construct(HeaderInterface ...$headers) + { + foreach ($headers as $header) { + $this->add($header); + } + } + + public function __clone() + { + foreach ($this->headers as $name => $collection) { + foreach ($collection as $i => $header) { + $this->headers[$name][$i] = clone $header; + } + } + } + + public function setMaxLineLength(int $lineLength): void + { + $this->lineLength = $lineLength; + foreach ($this->all() as $header) { + $header->setMaxLineLength($lineLength); + } + } + + public function getMaxLineLength(): int + { + return $this->lineLength; + } + + /** + * @param array $addresses + * + * @return $this + */ + public function addMailboxListHeader(string $name, array $addresses): static + { + return $this->add(new MailboxListHeader($name, Address::createArray($addresses))); + } + + /** + * @return $this + */ + public function addMailboxHeader(string $name, Address|string $address): static + { + return $this->add(new MailboxHeader($name, Address::create($address))); + } + + /** + * @return $this + */ + public function addIdHeader(string $name, string|array $ids): static + { + return $this->add(new IdentificationHeader($name, $ids)); + } + + /** + * @return $this + */ + public function addPathHeader(string $name, Address|string $path): static + { + return $this->add(new PathHeader($name, $path instanceof Address ? $path : new Address($path))); + } + + /** + * @return $this + */ + public function addDateHeader(string $name, \DateTimeInterface $dateTime): static + { + return $this->add(new DateHeader($name, $dateTime)); + } + + /** + * @return $this + */ + public function addTextHeader(string $name, string $value): static + { + return $this->add(new UnstructuredHeader($name, $value)); + } + + /** + * @return $this + */ + public function addParameterizedHeader(string $name, string $value, array $params = []): static + { + return $this->add(new ParameterizedHeader($name, $value, $params)); + } + + /** + * @return $this + */ + public function addHeader(string $name, mixed $argument, array $more = []): static + { + $headerClass = self::HEADER_CLASS_MAP[strtolower($name)] ?? UnstructuredHeader::class; + if (\is_array($headerClass)) { + $headerClass = $headerClass[0]; + } + $parts = explode('\\', $headerClass); + $method = 'add'.ucfirst(array_pop($parts)); + if ('addUnstructuredHeader' === $method) { + $method = 'addTextHeader'; + } elseif ('addIdentificationHeader' === $method) { + $method = 'addIdHeader'; + } elseif ('addMailboxListHeader' === $method && !\is_array($argument)) { + $argument = [$argument]; + } + + return $this->$method($name, $argument, $more); + } + + public function has(string $name): bool + { + return isset($this->headers[strtolower($name)]); + } + + /** + * @return $this + */ + public function add(HeaderInterface $header): static + { + self::checkHeaderClass($header); + + $header->setMaxLineLength($this->lineLength); + $name = strtolower($header->getName()); + + if (\in_array($name, self::UNIQUE_HEADERS, true) && isset($this->headers[$name]) && \count($this->headers[$name]) > 0) { + throw new LogicException(sprintf('Impossible to set header "%s" as it\'s already defined and must be unique.', $header->getName())); + } + + $this->headers[$name][] = $header; + + return $this; + } + + public function get(string $name): ?HeaderInterface + { + $name = strtolower($name); + if (!isset($this->headers[$name])) { + return null; + } + + $values = array_values($this->headers[$name]); + + return array_shift($values); + } + + public function all(?string $name = null): iterable + { + if (null === $name) { + foreach ($this->headers as $name => $collection) { + foreach ($collection as $header) { + yield $name => $header; + } + } + } elseif (isset($this->headers[strtolower($name)])) { + foreach ($this->headers[strtolower($name)] as $header) { + yield $header; + } + } + } + + public function getNames(): array + { + return array_keys($this->headers); + } + + public function remove(string $name): void + { + unset($this->headers[strtolower($name)]); + } + + public static function isUniqueHeader(string $name): bool + { + return \in_array(strtolower($name), self::UNIQUE_HEADERS, true); + } + + /** + * @throws LogicException if the header name and class are not compatible + */ + public static function checkHeaderClass(HeaderInterface $header): void + { + $name = strtolower($header->getName()); + $headerClasses = self::HEADER_CLASS_MAP[$name] ?? []; + if (!\is_array($headerClasses)) { + $headerClasses = [$headerClasses]; + } + + if (!$headerClasses) { + return; + } + + foreach ($headerClasses as $c) { + if ($header instanceof $c) { + return; + } + } + + throw new LogicException(sprintf('The "%s" header must be an instance of "%s" (got "%s").', $header->getName(), implode('" or "', $headerClasses), get_debug_type($header))); + } + + public function toString(): string + { + $string = ''; + foreach ($this->toArray() as $str) { + $string .= $str."\r\n"; + } + + return $string; + } + + public function toArray(): array + { + $arr = []; + foreach ($this->all() as $header) { + if ('' !== $header->getBodyAsString()) { + $arr[] = $header->toString(); + } + } + + return $arr; + } + + public function getHeaderBody(string $name): mixed + { + return $this->has($name) ? $this->get($name)->getBody() : null; + } + + /** + * @internal + */ + public function setHeaderBody(string $type, string $name, mixed $body): void + { + if ($this->has($name)) { + $this->get($name)->setBody($body); + } else { + $this->{'add'.$type.'Header'}($name, $body); + } + } + + public function getHeaderParameter(string $name, string $parameter): ?string + { + if (!$this->has($name)) { + return null; + } + + $header = $this->get($name); + if (!$header instanceof ParameterizedHeader) { + throw new LogicException(sprintf('Unable to get parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class)); + } + + return $header->getParameter($parameter); + } + + /** + * @internal + */ + public function setHeaderParameter(string $name, string $parameter, ?string $value): void + { + if (!$this->has($name)) { + throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not defined.', $parameter, $name)); + } + + $header = $this->get($name); + if (!$header instanceof ParameterizedHeader) { + throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class)); + } + + $header->setParameter($parameter, $value); + } +} diff --git a/tools/mailer/symfony/mime/Header/IdentificationHeader.php b/tools/mailer/symfony/mime/Header/IdentificationHeader.php new file mode 100644 index 000000000..14e18bf25 --- /dev/null +++ b/tools/mailer/symfony/mime/Header/IdentificationHeader.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * An ID MIME Header for something like Message-ID or Content-ID (one or more addresses). + * + * @author Chris Corbyn + */ +final class IdentificationHeader extends AbstractHeader +{ + private array $ids = []; + private array $idsAsAddresses = []; + + public function __construct(string $name, string|array $ids) + { + parent::__construct($name); + + $this->setId($ids); + } + + /** + * @param string|string[] $body a string ID or an array of IDs + * + * @throws RfcComplianceException + */ + public function setBody(mixed $body): void + { + $this->setId($body); + } + + public function getBody(): array + { + return $this->getIds(); + } + + /** + * Set the ID used in the value of this header. + * + * @param string|string[] $id + * + * @throws RfcComplianceException + */ + public function setId(string|array $id): void + { + $this->setIds(\is_array($id) ? $id : [$id]); + } + + /** + * Get the ID used in the value of this Header. + * + * If multiple IDs are set only the first is returned. + */ + public function getId(): ?string + { + return $this->ids[0] ?? null; + } + + /** + * Set a collection of IDs to use in the value of this Header. + * + * @param string[] $ids + * + * @throws RfcComplianceException + */ + public function setIds(array $ids): void + { + $this->ids = []; + $this->idsAsAddresses = []; + foreach ($ids as $id) { + $this->idsAsAddresses[] = new Address($id); + $this->ids[] = $id; + } + } + + /** + * Get the list of IDs used in this Header. + * + * @return string[] + */ + public function getIds(): array + { + return $this->ids; + } + + public function getBodyAsString(): string + { + $addrs = []; + foreach ($this->idsAsAddresses as $address) { + $addrs[] = '<'.$address->toString().'>'; + } + + return implode(' ', $addrs); + } +} diff --git a/tools/mailer/symfony/mime/Header/MailboxHeader.php b/tools/mailer/symfony/mime/Header/MailboxHeader.php new file mode 100644 index 000000000..8ba964b53 --- /dev/null +++ b/tools/mailer/symfony/mime/Header/MailboxHeader.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * A Mailbox MIME Header for something like Sender (one named address). + * + * @author Fabien Potencier + */ +final class MailboxHeader extends AbstractHeader +{ + private Address $address; + + public function __construct(string $name, Address $address) + { + parent::__construct($name); + + $this->setAddress($address); + } + + /** + * @param Address $body + * + * @throws RfcComplianceException + */ + public function setBody(mixed $body): void + { + $this->setAddress($body); + } + + /** + * @throws RfcComplianceException + */ + public function getBody(): Address + { + return $this->getAddress(); + } + + /** + * @throws RfcComplianceException + */ + public function setAddress(Address $address): void + { + $this->address = $address; + } + + public function getAddress(): Address + { + return $this->address; + } + + public function getBodyAsString(): string + { + $str = $this->address->getEncodedAddress(); + if ($name = $this->address->getName()) { + $str = $this->createPhrase($this, $name, $this->getCharset(), true).' <'.$str.'>'; + } + + return $str; + } + + /** + * Redefine the encoding requirements for an address. + * + * All "specials" must be encoded as the full header value will not be quoted + * + * @see RFC 2822 3.2.1 + */ + protected function tokenNeedsEncoding(string $token): bool + { + return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); + } +} diff --git a/tools/mailer/symfony/mime/Header/MailboxListHeader.php b/tools/mailer/symfony/mime/Header/MailboxListHeader.php new file mode 100644 index 000000000..8d902fb75 --- /dev/null +++ b/tools/mailer/symfony/mime/Header/MailboxListHeader.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * A Mailbox list MIME Header for something like From, To, Cc, and Bcc (one or more named addresses). + * + * @author Chris Corbyn + */ +final class MailboxListHeader extends AbstractHeader +{ + private array $addresses = []; + + /** + * @param Address[] $addresses + */ + public function __construct(string $name, array $addresses) + { + parent::__construct($name); + + $this->setAddresses($addresses); + } + + /** + * @param Address[] $body + * + * @throws RfcComplianceException + */ + public function setBody(mixed $body): void + { + $this->setAddresses($body); + } + + /** + * @return Address[] + * + * @throws RfcComplianceException + */ + public function getBody(): array + { + return $this->getAddresses(); + } + + /** + * Sets a list of addresses to be shown in this Header. + * + * @param Address[] $addresses + * + * @throws RfcComplianceException + */ + public function setAddresses(array $addresses): void + { + $this->addresses = []; + $this->addAddresses($addresses); + } + + /** + * Sets a list of addresses to be shown in this Header. + * + * @param Address[] $addresses + * + * @throws RfcComplianceException + */ + public function addAddresses(array $addresses): void + { + foreach ($addresses as $address) { + $this->addAddress($address); + } + } + + /** + * @throws RfcComplianceException + */ + public function addAddress(Address $address): void + { + $this->addresses[] = $address; + } + + /** + * @return Address[] + */ + public function getAddresses(): array + { + return $this->addresses; + } + + /** + * Gets the full mailbox list of this Header as an array of valid RFC 2822 strings. + * + * @return string[] + * + * @throws RfcComplianceException + */ + public function getAddressStrings(): array + { + $strings = []; + foreach ($this->addresses as $address) { + $str = $address->getEncodedAddress(); + if ($name = $address->getName()) { + $str = $this->createPhrase($this, $name, $this->getCharset(), !$strings).' <'.$str.'>'; + } + $strings[] = $str; + } + + return $strings; + } + + public function getBodyAsString(): string + { + return implode(', ', $this->getAddressStrings()); + } + + /** + * Redefine the encoding requirements for addresses. + * + * All "specials" must be encoded as the full header value will not be quoted + * + * @see RFC 2822 3.2.1 + */ + protected function tokenNeedsEncoding(string $token): bool + { + return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); + } +} diff --git a/tools/mailer/symfony/mime/Header/ParameterizedHeader.php b/tools/mailer/symfony/mime/Header/ParameterizedHeader.php new file mode 100644 index 000000000..5ef4f2120 --- /dev/null +++ b/tools/mailer/symfony/mime/Header/ParameterizedHeader.php @@ -0,0 +1,191 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Encoder\Rfc2231Encoder; + +/** + * @author Chris Corbyn + */ +final class ParameterizedHeader extends UnstructuredHeader +{ + /** + * RFC 2231's definition of a token. + * + * @var string + */ + public const TOKEN_REGEX = '(?:[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E]+)'; + + private ?Rfc2231Encoder $encoder = null; + private array $parameters = []; + + public function __construct(string $name, string $value, array $parameters = []) + { + parent::__construct($name, $value); + + foreach ($parameters as $k => $v) { + $this->setParameter($k, $v); + } + + if ('content-type' !== strtolower($name)) { + $this->encoder = new Rfc2231Encoder(); + } + } + + public function setParameter(string $parameter, ?string $value): void + { + $this->setParameters(array_merge($this->getParameters(), [$parameter => $value])); + } + + public function getParameter(string $parameter): string + { + return $this->getParameters()[$parameter] ?? ''; + } + + /** + * @param string[] $parameters + */ + public function setParameters(array $parameters): void + { + $this->parameters = $parameters; + } + + /** + * @return string[] + */ + public function getParameters(): array + { + return $this->parameters; + } + + public function getBodyAsString(): string + { + $body = parent::getBodyAsString(); + foreach ($this->parameters as $name => $value) { + if (null !== $value) { + $body .= '; '.$this->createParameter($name, $value); + } + } + + return $body; + } + + /** + * Generate a list of all tokens in the final header. + * + * This doesn't need to be overridden in theory, but it is for implementation + * reasons to prevent potential breakage of attributes. + */ + protected function toTokens(?string $string = null): array + { + $tokens = parent::toTokens(parent::getBodyAsString()); + + // Try creating any parameters + foreach ($this->parameters as $name => $value) { + if (null !== $value) { + // Add the semi-colon separator + $tokens[\count($tokens) - 1] .= ';'; + $tokens = array_merge($tokens, $this->generateTokenLines(' '.$this->createParameter($name, $value))); + } + } + + return $tokens; + } + + /** + * Render an RFC 2047 compliant header parameter from the $name and $value. + */ + private function createParameter(string $name, string $value): string + { + $origValue = $value; + + $encoded = false; + // Allow room for parameter name, indices, "=" and DQUOTEs + $maxValueLength = $this->getMaxLineLength() - \strlen($name.'=*N"";') - 1; + $firstLineOffset = 0; + + // If it's not already a valid parameter value... + if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { + // TODO: text, or something else?? + // ... and it's not ascii + if (!preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $value)) { + $encoded = true; + // Allow space for the indices, charset and language + $maxValueLength = $this->getMaxLineLength() - \strlen($name.'*N*="";') - 1; + $firstLineOffset = \strlen($this->getCharset()."'".$this->getLanguage()."'"); + } + + if (\in_array($name, ['name', 'filename'], true) && 'form-data' === $this->getValue() && 'content-disposition' === strtolower($this->getName()) && preg_match('//u', $value)) { + // WHATWG HTML living standard 4.10.21.8 2 specifies: + // For field names and filenames for file fields, the result of the + // encoding in the previous bullet point must be escaped by replacing + // any 0x0A (LF) bytes with the byte sequence `%0A`, 0x0D (CR) with `%0D` + // and 0x22 (") with `%22`. + // The user agent must not perform any other escapes. + $value = str_replace(['"', "\r", "\n"], ['%22', '%0D', '%0A'], $value); + + if (\strlen($value) <= $maxValueLength) { + return $name.'="'.$value.'"'; + } + + $value = $origValue; + } + } + + // Encode if we need to + if ($encoded || \strlen($value) > $maxValueLength) { + if (null !== $this->encoder) { + $value = $this->encoder->encodeString($origValue, $this->getCharset(), $firstLineOffset, $maxValueLength); + } else { + // We have to go against RFC 2183/2231 in some areas for interoperability + $value = $this->getTokenAsEncodedWord($origValue); + $encoded = false; + } + } + + $valueLines = $this->encoder ? explode("\r\n", $value) : [$value]; + + // Need to add indices + if (\count($valueLines) > 1) { + $paramLines = []; + foreach ($valueLines as $i => $line) { + $paramLines[] = $name.'*'.$i.$this->getEndOfParameterValue($line, true, 0 === $i); + } + + return implode(";\r\n ", $paramLines); + } else { + return $name.$this->getEndOfParameterValue($valueLines[0], $encoded, true); + } + } + + /** + * Returns the parameter value from the "=" and beyond. + * + * @param string $value to append + */ + private function getEndOfParameterValue(string $value, bool $encoded = false, bool $firstLine = false): string + { + $forceHttpQuoting = 'form-data' === $this->getValue() && 'content-disposition' === strtolower($this->getName()); + if ($forceHttpQuoting || !preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { + $value = '"'.$value.'"'; + } + $prepend = '='; + if ($encoded) { + $prepend = '*='; + if ($firstLine) { + $prepend = '*='.$this->getCharset()."'".$this->getLanguage()."'"; + } + } + + return $prepend.$value; + } +} diff --git a/tools/mailer/symfony/mime/Header/PathHeader.php b/tools/mailer/symfony/mime/Header/PathHeader.php new file mode 100644 index 000000000..63eb30af0 --- /dev/null +++ b/tools/mailer/symfony/mime/Header/PathHeader.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * A Path Header, such a Return-Path (one address). + * + * @author Chris Corbyn + */ +final class PathHeader extends AbstractHeader +{ + private Address $address; + + public function __construct(string $name, Address $address) + { + parent::__construct($name); + + $this->setAddress($address); + } + + /** + * @param Address $body + * + * @throws RfcComplianceException + */ + public function setBody(mixed $body): void + { + $this->setAddress($body); + } + + public function getBody(): Address + { + return $this->getAddress(); + } + + public function setAddress(Address $address): void + { + $this->address = $address; + } + + public function getAddress(): Address + { + return $this->address; + } + + public function getBodyAsString(): string + { + return '<'.$this->address->toString().'>'; + } +} diff --git a/tools/mailer/symfony/mime/Header/UnstructuredHeader.php b/tools/mailer/symfony/mime/Header/UnstructuredHeader.php new file mode 100644 index 000000000..88ed46692 --- /dev/null +++ b/tools/mailer/symfony/mime/Header/UnstructuredHeader.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +/** + * A Simple MIME Header. + * + * @author Chris Corbyn + */ +class UnstructuredHeader extends AbstractHeader +{ + private string $value; + + public function __construct(string $name, string $value) + { + parent::__construct($name); + + $this->setValue($value); + } + + /** + * @param string $body + */ + public function setBody(mixed $body): void + { + $this->setValue($body); + } + + public function getBody(): string + { + return $this->getValue(); + } + + /** + * Get the (unencoded) value of this header. + */ + public function getValue(): string + { + return $this->value; + } + + /** + * Set the (unencoded) value of this header. + */ + public function setValue(string $value): void + { + $this->value = $value; + } + + /** + * Get the value of this header prepared for rendering. + */ + public function getBodyAsString(): string + { + return $this->encodeWords($this, $this->value); + } +} diff --git a/tools/mailer/symfony/mime/HtmlToTextConverter/DefaultHtmlToTextConverter.php b/tools/mailer/symfony/mime/HtmlToTextConverter/DefaultHtmlToTextConverter.php new file mode 100644 index 000000000..2aaf8e6c4 --- /dev/null +++ b/tools/mailer/symfony/mime/HtmlToTextConverter/DefaultHtmlToTextConverter.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\HtmlToTextConverter; + +/** + * @author Fabien Potencier + */ +class DefaultHtmlToTextConverter implements HtmlToTextConverterInterface +{ + public function convert(string $html, string $charset): string + { + return strip_tags(preg_replace('{<(head|style)\b.*?}is', '', $html)); + } +} diff --git a/tools/mailer/symfony/mime/HtmlToTextConverter/HtmlToTextConverterInterface.php b/tools/mailer/symfony/mime/HtmlToTextConverter/HtmlToTextConverterInterface.php new file mode 100644 index 000000000..696f37ccf --- /dev/null +++ b/tools/mailer/symfony/mime/HtmlToTextConverter/HtmlToTextConverterInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\HtmlToTextConverter; + +/** + * @author Fabien Potencier + */ +interface HtmlToTextConverterInterface +{ + /** + * Converts an HTML representation of a Message to a text representation. + * + * The output must use the same charset as the HTML one. + */ + public function convert(string $html, string $charset): string; +} diff --git a/tools/mailer/symfony/mime/HtmlToTextConverter/LeagueHtmlToMarkdownConverter.php b/tools/mailer/symfony/mime/HtmlToTextConverter/LeagueHtmlToMarkdownConverter.php new file mode 100644 index 000000000..253a7b19f --- /dev/null +++ b/tools/mailer/symfony/mime/HtmlToTextConverter/LeagueHtmlToMarkdownConverter.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\HtmlToTextConverter; + +use League\HTMLToMarkdown\HtmlConverter; +use League\HTMLToMarkdown\HtmlConverterInterface; + +/** + * @author Fabien Potencier + */ +class LeagueHtmlToMarkdownConverter implements HtmlToTextConverterInterface +{ + public function __construct( + private HtmlConverterInterface $converter = new HtmlConverter([ + 'hard_break' => true, + 'strip_tags' => true, + 'remove_nodes' => 'head style', + ]), + ) { + } + + public function convert(string $html, string $charset): string + { + return $this->converter->convert($html); + } +} diff --git a/tools/mailer/symfony/mime/LICENSE b/tools/mailer/symfony/mime/LICENSE new file mode 100644 index 000000000..4dd83ce0f --- /dev/null +++ b/tools/mailer/symfony/mime/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010-present Fabien Potencier + +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/tools/mailer/symfony/mime/Message.php b/tools/mailer/symfony/mime/Message.php new file mode 100644 index 000000000..0374ae7a0 --- /dev/null +++ b/tools/mailer/symfony/mime/Message.php @@ -0,0 +1,163 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Part\AbstractPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * @author Fabien Potencier + */ +class Message extends RawMessage +{ + private Headers $headers; + + public function __construct( + ?Headers $headers = null, + private ?AbstractPart $body = null, + ) { + $this->headers = $headers ? clone $headers : new Headers(); + } + + public function __clone() + { + $this->headers = clone $this->headers; + + if (null !== $this->body) { + $this->body = clone $this->body; + } + } + + /** + * @return $this + */ + public function setBody(?AbstractPart $body): static + { + $this->body = $body; + + return $this; + } + + public function getBody(): ?AbstractPart + { + return $this->body; + } + + /** + * @return $this + */ + public function setHeaders(Headers $headers): static + { + $this->headers = $headers; + + return $this; + } + + public function getHeaders(): Headers + { + return $this->headers; + } + + public function getPreparedHeaders(): Headers + { + $headers = clone $this->headers; + + if (!$headers->has('From')) { + if (!$headers->has('Sender')) { + throw new LogicException('An email must have a "From" or a "Sender" header.'); + } + $headers->addMailboxListHeader('From', [$headers->get('Sender')->getAddress()]); + } + + if (!$headers->has('MIME-Version')) { + $headers->addTextHeader('MIME-Version', '1.0'); + } + + if (!$headers->has('Date')) { + $headers->addDateHeader('Date', new \DateTimeImmutable()); + } + + // determine the "real" sender + if (!$headers->has('Sender') && \count($froms = $headers->get('From')->getAddresses()) > 1) { + $headers->addMailboxHeader('Sender', $froms[0]); + } + + if (!$headers->has('Message-ID')) { + $headers->addIdHeader('Message-ID', $this->generateMessageId()); + } + + // remove the Bcc field which should NOT be part of the sent message + $headers->remove('Bcc'); + + return $headers; + } + + public function toString(): string + { + if (null === $body = $this->getBody()) { + $body = new TextPart(''); + } + + return $this->getPreparedHeaders()->toString().$body->toString(); + } + + public function toIterable(): iterable + { + if (null === $body = $this->getBody()) { + $body = new TextPart(''); + } + + yield $this->getPreparedHeaders()->toString(); + yield from $body->toIterable(); + } + + public function ensureValidity(): void + { + if (!$this->headers->get('To')?->getBody() && !$this->headers->get('Cc')?->getBody() && !$this->headers->get('Bcc')?->getBody()) { + throw new LogicException('An email must have a "To", "Cc", or "Bcc" header.'); + } + + if (!$this->headers->get('From')?->getBody() && !$this->headers->get('Sender')?->getBody()) { + throw new LogicException('An email must have a "From" or a "Sender" header.'); + } + + parent::ensureValidity(); + } + + public function generateMessageId(): string + { + if ($this->headers->has('Sender')) { + $sender = $this->headers->get('Sender')->getAddress(); + } elseif ($this->headers->has('From')) { + if (!$froms = $this->headers->get('From')->getAddresses()) { + throw new LogicException('A "From" header must have at least one email address.'); + } + $sender = $froms[0]; + } else { + throw new LogicException('An email must have a "From" or a "Sender" header.'); + } + + return bin2hex(random_bytes(16)).strstr($sender->getAddress(), '@'); + } + + public function __serialize(): array + { + return [$this->headers, $this->body]; + } + + public function __unserialize(array $data): void + { + [$this->headers, $this->body] = $data; + } +} diff --git a/tools/mailer/symfony/mime/MessageConverter.php b/tools/mailer/symfony/mime/MessageConverter.php new file mode 100644 index 000000000..bdce921af --- /dev/null +++ b/tools/mailer/symfony/mime/MessageConverter.php @@ -0,0 +1,122 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\RuntimeException; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\AlternativePart; +use Symfony\Component\Mime\Part\Multipart\MixedPart; +use Symfony\Component\Mime\Part\Multipart\RelatedPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * @author Fabien Potencier + */ +final class MessageConverter +{ + /** + * @throws RuntimeException when unable to convert the message to an email + */ + public static function toEmail(Message $message): Email + { + if ($message instanceof Email) { + return $message; + } + + // try to convert to a "simple" Email instance + $body = $message->getBody(); + if ($body instanceof TextPart) { + return self::createEmailFromTextPart($message, $body); + } + + if ($body instanceof AlternativePart) { + return self::createEmailFromAlternativePart($message, $body); + } + + if ($body instanceof RelatedPart) { + return self::createEmailFromRelatedPart($message, $body); + } + + if ($body instanceof MixedPart) { + $parts = $body->getParts(); + if ($parts[0] instanceof RelatedPart) { + $email = self::createEmailFromRelatedPart($message, $parts[0]); + } elseif ($parts[0] instanceof AlternativePart) { + $email = self::createEmailFromAlternativePart($message, $parts[0]); + } elseif ($parts[0] instanceof TextPart) { + $email = self::createEmailFromTextPart($message, $parts[0]); + } else { + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + } + + return self::addParts($email, \array_slice($parts, 1)); + } + + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + } + + private static function createEmailFromTextPart(Message $message, TextPart $part): Email + { + if ('text' === $part->getMediaType() && 'plain' === $part->getMediaSubtype()) { + return (new Email(clone $message->getHeaders()))->text($part->getBody(), $part->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8'); + } + if ('text' === $part->getMediaType() && 'html' === $part->getMediaSubtype()) { + return (new Email(clone $message->getHeaders()))->html($part->getBody(), $part->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8'); + } + + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + } + + private static function createEmailFromAlternativePart(Message $message, AlternativePart $part): Email + { + $parts = $part->getParts(); + if ( + 2 === \count($parts) + && $parts[0] instanceof TextPart && 'text' === $parts[0]->getMediaType() && 'plain' === $parts[0]->getMediaSubtype() + && $parts[1] instanceof TextPart && 'text' === $parts[1]->getMediaType() && 'html' === $parts[1]->getMediaSubtype() + ) { + return (new Email(clone $message->getHeaders())) + ->text($parts[0]->getBody(), $parts[0]->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8') + ->html($parts[1]->getBody(), $parts[1]->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8') + ; + } + + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + } + + private static function createEmailFromRelatedPart(Message $message, RelatedPart $part): Email + { + $parts = $part->getParts(); + if ($parts[0] instanceof AlternativePart) { + $email = self::createEmailFromAlternativePart($message, $parts[0]); + } elseif ($parts[0] instanceof TextPart) { + $email = self::createEmailFromTextPart($message, $parts[0]); + } else { + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + } + + return self::addParts($email, \array_slice($parts, 1)); + } + + private static function addParts(Email $email, array $parts): Email + { + foreach ($parts as $part) { + if (!$part instanceof DataPart) { + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($email))); + } + + $email->addPart($part); + } + + return $email; + } +} diff --git a/tools/mailer/symfony/mime/MimeTypeGuesserInterface.php b/tools/mailer/symfony/mime/MimeTypeGuesserInterface.php new file mode 100644 index 000000000..30ee3b64a --- /dev/null +++ b/tools/mailer/symfony/mime/MimeTypeGuesserInterface.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * Guesses the MIME type of a file. + * + * @author Fabien Potencier + */ +interface MimeTypeGuesserInterface +{ + /** + * Returns true if this guesser is supported. + */ + public function isGuesserSupported(): bool; + + /** + * Guesses the MIME type of the file with the given path. + * + * @throws \LogicException If the guesser is not supported + * @throws \InvalidArgumentException If the file does not exist or is not readable + */ + public function guessMimeType(string $path): ?string; +} diff --git a/tools/mailer/symfony/mime/MimeTypes.php b/tools/mailer/symfony/mime/MimeTypes.php new file mode 100644 index 000000000..59fd2d903 --- /dev/null +++ b/tools/mailer/symfony/mime/MimeTypes.php @@ -0,0 +1,3703 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\LogicException; + +/** + * Manages MIME types and file extensions. + * + * For MIME type guessing, you can register custom guessers + * by calling the registerGuesser() method. + * Custom guessers are always called before any default ones: + * + * $guesser = new MimeTypes(); + * $guesser->registerGuesser(new MyCustomMimeTypeGuesser()); + * + * If you want to change the order of the default guessers, just re-register your + * preferred one as a custom one. The last registered guesser is preferred over + * previously registered ones. + * + * Re-registering a built-in guesser also allows you to configure it: + * + * $guesser = new MimeTypes(); + * $guesser->registerGuesser(new FileinfoMimeTypeGuesser('/path/to/magic/file')); + * + * @author Fabien Potencier + */ +final class MimeTypes implements MimeTypesInterface +{ + private array $extensions = []; + private array $mimeTypes = []; + + /** + * @var MimeTypeGuesserInterface[] + */ + private array $guessers = []; + private static MimeTypes $default; + + public function __construct(array $map = []) + { + foreach ($map as $mimeType => $extensions) { + $this->extensions[$mimeType] = $extensions; + + foreach ($extensions as $extension) { + $this->mimeTypes[$extension][] = $mimeType; + } + } + $this->registerGuesser(new FileBinaryMimeTypeGuesser()); + $this->registerGuesser(new FileinfoMimeTypeGuesser()); + } + + public static function setDefault(self $default): void + { + self::$default = $default; + } + + public static function getDefault(): self + { + return self::$default ??= new self(); + } + + /** + * Registers a MIME type guesser. + * + * The last registered guesser has precedence over the other ones. + */ + public function registerGuesser(MimeTypeGuesserInterface $guesser): void + { + array_unshift($this->guessers, $guesser); + } + + public function getExtensions(string $mimeType): array + { + if ($this->extensions) { + $extensions = $this->extensions[$mimeType] ?? $this->extensions[$lcMimeType = strtolower($mimeType)] ?? null; + } + + return $extensions ?? self::MAP[$mimeType] ?? self::MAP[$lcMimeType ?? strtolower($mimeType)] ?? []; + } + + public function getMimeTypes(string $ext): array + { + if ($this->mimeTypes) { + $mimeTypes = $this->mimeTypes[$ext] ?? $this->mimeTypes[$lcExt = strtolower($ext)] ?? null; + } + + return $mimeTypes ?? self::REVERSE_MAP[$ext] ?? self::REVERSE_MAP[$lcExt ?? strtolower($ext)] ?? []; + } + + public function isGuesserSupported(): bool + { + foreach ($this->guessers as $guesser) { + if ($guesser->isGuesserSupported()) { + return true; + } + } + + return false; + } + + /** + * The file is passed to each registered MIME type guesser in reverse order + * of their registration (last registered is queried first). Once a guesser + * returns a value that is not null, this method terminates and returns the + * value. + */ + public function guessMimeType(string $path): ?string + { + foreach ($this->guessers as $guesser) { + if (!$guesser->isGuesserSupported()) { + continue; + } + + if (null !== $mimeType = $guesser->guessMimeType($path)) { + return $mimeType; + } + } + + if (!$this->isGuesserSupported()) { + throw new LogicException('Unable to guess the MIME type as no guessers are available (have you enabled the php_fileinfo extension?).'); + } + + return null; + } + + /** + * A map of MIME types and their default extensions. + * + * Updated from upstream on 2024-03-17. + * + * @see Resources/bin/update_mime_types.php + */ + private const MAP = [ + 'application/acrobat' => ['pdf'], + 'application/andrew-inset' => ['ez'], + 'application/annodex' => ['anx'], + 'application/appinstaller' => ['appinstaller'], + 'application/applixware' => ['aw'], + 'application/appx' => ['appx'], + 'application/appxbundle' => ['appxbundle'], + 'application/atom+xml' => ['atom'], + 'application/atomcat+xml' => ['atomcat'], + 'application/atomdeleted+xml' => ['atomdeleted'], + 'application/atomsvc+xml' => ['atomsvc'], + 'application/atsc-dwd+xml' => ['dwd'], + 'application/atsc-held+xml' => ['held'], + 'application/atsc-rsat+xml' => ['rsat'], + 'application/bat' => ['bat'], + 'application/bdoc' => ['bdoc'], + 'application/bzip2' => ['bz2', 'bz'], + 'application/calendar+xml' => ['xcs'], + 'application/cbor' => ['cbor'], + 'application/ccxml+xml' => ['ccxml'], + 'application/cdfx+xml' => ['cdfx'], + 'application/cdmi-capability' => ['cdmia'], + 'application/cdmi-container' => ['cdmic'], + 'application/cdmi-domain' => ['cdmid'], + 'application/cdmi-object' => ['cdmio'], + 'application/cdmi-queue' => ['cdmiq'], + 'application/cdr' => ['cdr'], + 'application/coreldraw' => ['cdr'], + 'application/cpl+xml' => ['cpl'], + 'application/csv' => ['csv'], + 'application/cu-seeme' => ['cu'], + 'application/dash+xml' => ['mpd'], + 'application/dash-patch+xml' => ['mpp'], + 'application/davmount+xml' => ['davmount'], + 'application/dbase' => ['dbf'], + 'application/dbf' => ['dbf'], + 'application/dicom' => ['dcm'], + 'application/docbook+xml' => ['dbk', 'docbook'], + 'application/dssc+der' => ['dssc'], + 'application/dssc+xml' => ['xdssc'], + 'application/ecmascript' => ['ecma', 'es'], + 'application/emf' => ['emf'], + 'application/emma+xml' => ['emma'], + 'application/emotionml+xml' => ['emotionml'], + 'application/epub+zip' => ['epub'], + 'application/exi' => ['exi'], + 'application/express' => ['exp'], + 'application/fdt+xml' => ['fdt'], + 'application/fits' => ['fits', 'fit', 'fts'], + 'application/font-tdpfr' => ['pfr'], + 'application/font-woff' => ['woff'], + 'application/futuresplash' => ['swf', 'spl'], + 'application/geo+json' => ['geojson', 'geo.json'], + 'application/gml+xml' => ['gml'], + 'application/gnunet-directory' => ['gnd'], + 'application/gpx' => ['gpx'], + 'application/gpx+xml' => ['gpx'], + 'application/gxf' => ['gxf'], + 'application/gzip' => ['gz'], + 'application/hjson' => ['hjson'], + 'application/hta' => ['hta'], + 'application/hyperstudio' => ['stk'], + 'application/ico' => ['ico'], + 'application/ics' => ['vcs', 'ics'], + 'application/illustrator' => ['ai'], + 'application/inkml+xml' => ['ink', 'inkml'], + 'application/ipfix' => ['ipfix'], + 'application/its+xml' => ['its'], + 'application/java' => ['class'], + 'application/java-archive' => ['jar', 'war', 'ear'], + 'application/java-byte-code' => ['class'], + 'application/java-serialized-object' => ['ser'], + 'application/java-vm' => ['class'], + 'application/javascript' => ['js', 'mjs', 'jsm'], + 'application/jrd+json' => ['jrd'], + 'application/json' => ['json', 'map'], + 'application/json-patch+json' => ['json-patch'], + 'application/json5' => ['json5'], + 'application/jsonml+json' => ['jsonml'], + 'application/ld+json' => ['jsonld'], + 'application/lgr+xml' => ['lgr'], + 'application/lost+xml' => ['lostxml'], + 'application/lotus123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'application/m3u' => ['m3u', 'm3u8', 'vlc'], + 'application/mac-binhex40' => ['hqx'], + 'application/mac-compactpro' => ['cpt'], + 'application/mads+xml' => ['mads'], + 'application/manifest+json' => ['webmanifest'], + 'application/marc' => ['mrc'], + 'application/marcxml+xml' => ['mrcx'], + 'application/mathematica' => ['ma', 'nb', 'mb'], + 'application/mathml+xml' => ['mathml', 'mml'], + 'application/mbox' => ['mbox'], + 'application/mdb' => ['mdb'], + 'application/media-policy-dataset+xml' => ['mpf'], + 'application/mediaservercontrol+xml' => ['mscml'], + 'application/metalink+xml' => ['metalink'], + 'application/metalink4+xml' => ['meta4'], + 'application/mets+xml' => ['mets'], + 'application/microsoftpatch' => ['msp'], + 'application/microsoftupdate' => ['msu'], + 'application/mmt-aei+xml' => ['maei'], + 'application/mmt-usd+xml' => ['musd'], + 'application/mods+xml' => ['mods'], + 'application/mp21' => ['m21', 'mp21'], + 'application/mp4' => ['mp4s', 'm4p'], + 'application/mrb-consumer+xml' => ['xdf'], + 'application/mrb-publish+xml' => ['xdf'], + 'application/ms-tnef' => ['tnef', 'tnf'], + 'application/msaccess' => ['mdb'], + 'application/msexcel' => ['xls', 'xlc', 'xll', 'xlm', 'xlw', 'xla', 'xlt', 'xld'], + 'application/msix' => ['msix'], + 'application/msixbundle' => ['msixbundle'], + 'application/mspowerpoint' => ['ppz', 'ppt', 'pps', 'pot'], + 'application/msword' => ['doc', 'dot'], + 'application/msword-template' => ['dot'], + 'application/mxf' => ['mxf'], + 'application/n-quads' => ['nq'], + 'application/n-triples' => ['nt'], + 'application/nappdf' => ['pdf'], + 'application/node' => ['cjs'], + 'application/octet-stream' => ['bin', 'dms', 'lrf', 'mar', 'so', 'dist', 'distz', 'pkg', 'bpk', 'dump', 'elc', 'deploy', 'exe', 'dll', 'deb', 'dmg', 'iso', 'img', 'msi', 'msp', 'msm', 'buffer'], + 'application/oda' => ['oda'], + 'application/oebps-package+xml' => ['opf'], + 'application/ogg' => ['ogx'], + 'application/omdoc+xml' => ['omdoc'], + 'application/onenote' => ['onetoc', 'onetoc2', 'onetmp', 'onepkg'], + 'application/ovf' => ['ova'], + 'application/owl+xml' => ['owx'], + 'application/oxps' => ['oxps'], + 'application/p2p-overlay+xml' => ['relo'], + 'application/patch-ops-error+xml' => ['xer'], + 'application/pcap' => ['pcap', 'cap', 'dmp'], + 'application/pdf' => ['pdf'], + 'application/pgp' => ['pgp', 'gpg', 'asc'], + 'application/pgp-encrypted' => ['pgp', 'gpg', 'asc'], + 'application/pgp-keys' => ['asc', 'skr', 'pkr', 'pgp', 'gpg', 'key'], + 'application/pgp-signature' => ['asc', 'sig', 'pgp', 'gpg'], + 'application/photoshop' => ['psd'], + 'application/pics-rules' => ['prf'], + 'application/pkcs10' => ['p10'], + 'application/pkcs12' => ['p12', 'pfx'], + 'application/pkcs7-mime' => ['p7m', 'p7c'], + 'application/pkcs7-signature' => ['p7s'], + 'application/pkcs8' => ['p8'], + 'application/pkcs8-encrypted' => ['p8e'], + 'application/pkix-attr-cert' => ['ac'], + 'application/pkix-cert' => ['cer'], + 'application/pkix-crl' => ['crl'], + 'application/pkix-pkipath' => ['pkipath'], + 'application/pkixcmp' => ['pki'], + 'application/pls' => ['pls'], + 'application/pls+xml' => ['pls'], + 'application/postscript' => ['ai', 'eps', 'ps'], + 'application/powerpoint' => ['ppz', 'ppt', 'pps', 'pot'], + 'application/provenance+xml' => ['provx'], + 'application/prs.cww' => ['cww'], + 'application/prs.wavefront-obj' => ['obj'], + 'application/pskc+xml' => ['pskcxml'], + 'application/ram' => ['ram'], + 'application/raml+yaml' => ['raml'], + 'application/rdf+xml' => ['rdf', 'owl', 'rdfs'], + 'application/reginfo+xml' => ['rif'], + 'application/relax-ng-compact-syntax' => ['rnc'], + 'application/resource-lists+xml' => ['rl'], + 'application/resource-lists-diff+xml' => ['rld'], + 'application/rls-services+xml' => ['rs'], + 'application/route-apd+xml' => ['rapd'], + 'application/route-s-tsid+xml' => ['sls'], + 'application/route-usd+xml' => ['rusd'], + 'application/rpki-ghostbusters' => ['gbr'], + 'application/rpki-manifest' => ['mft'], + 'application/rpki-roa' => ['roa'], + 'application/rsd+xml' => ['rsd'], + 'application/rss+xml' => ['rss'], + 'application/rtf' => ['rtf'], + 'application/sbml+xml' => ['sbml'], + 'application/schema+json' => ['json'], + 'application/scvp-cv-request' => ['scq'], + 'application/scvp-cv-response' => ['scs'], + 'application/scvp-vp-request' => ['spq'], + 'application/scvp-vp-response' => ['spp'], + 'application/sdp' => ['sdp'], + 'application/senml+xml' => ['senmlx'], + 'application/sensml+xml' => ['sensmlx'], + 'application/set-payment-initiation' => ['setpay'], + 'application/set-registration-initiation' => ['setreg'], + 'application/shf+xml' => ['shf'], + 'application/sieve' => ['siv', 'sieve'], + 'application/smil' => ['smil', 'smi', 'sml', 'kino'], + 'application/smil+xml' => ['smi', 'smil', 'sml', 'kino'], + 'application/sparql-query' => ['rq', 'qs'], + 'application/sparql-results+xml' => ['srx'], + 'application/sql' => ['sql'], + 'application/srgs' => ['gram'], + 'application/srgs+xml' => ['grxml'], + 'application/sru+xml' => ['sru'], + 'application/ssdl+xml' => ['ssdl'], + 'application/ssml+xml' => ['ssml'], + 'application/stuffit' => ['sit', 'hqx'], + 'application/swid+xml' => ['swidtag'], + 'application/tei+xml' => ['tei', 'teicorpus'], + 'application/tga' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'application/thraud+xml' => ['tfi'], + 'application/timestamped-data' => ['tsd'], + 'application/toml' => ['toml'], + 'application/trig' => ['trig'], + 'application/ttml+xml' => ['ttml'], + 'application/ubjson' => ['ubj'], + 'application/urc-ressheet+xml' => ['rsheet'], + 'application/urc-targetdesc+xml' => ['td'], + 'application/vnd.1000minds.decision-model+xml' => ['1km'], + 'application/vnd.3gpp.pic-bw-large' => ['plb'], + 'application/vnd.3gpp.pic-bw-small' => ['psb'], + 'application/vnd.3gpp.pic-bw-var' => ['pvb'], + 'application/vnd.3gpp2.tcap' => ['tcap'], + 'application/vnd.3m.post-it-notes' => ['pwn'], + 'application/vnd.accpac.simply.aso' => ['aso'], + 'application/vnd.accpac.simply.imp' => ['imp'], + 'application/vnd.acucobol' => ['acu'], + 'application/vnd.acucorp' => ['atc', 'acutc'], + 'application/vnd.adobe.air-application-installer-package+zip' => ['air'], + 'application/vnd.adobe.flash.movie' => ['swf', 'spl'], + 'application/vnd.adobe.formscentral.fcdt' => ['fcdt'], + 'application/vnd.adobe.fxp' => ['fxp', 'fxpl'], + 'application/vnd.adobe.illustrator' => ['ai'], + 'application/vnd.adobe.xdp+xml' => ['xdp'], + 'application/vnd.adobe.xfdf' => ['xfdf'], + 'application/vnd.age' => ['age'], + 'application/vnd.ahead.space' => ['ahead'], + 'application/vnd.airzip.filesecure.azf' => ['azf'], + 'application/vnd.airzip.filesecure.azs' => ['azs'], + 'application/vnd.amazon.ebook' => ['azw'], + 'application/vnd.amazon.mobi8-ebook' => ['azw3', 'kfx'], + 'application/vnd.americandynamics.acc' => ['acc'], + 'application/vnd.amiga.ami' => ['ami'], + 'application/vnd.android.package-archive' => ['apk'], + 'application/vnd.anser-web-certificate-issue-initiation' => ['cii'], + 'application/vnd.anser-web-funds-transfer-initiation' => ['fti'], + 'application/vnd.antix.game-component' => ['atx'], + 'application/vnd.appimage' => ['appimage'], + 'application/vnd.apple.installer+xml' => ['mpkg'], + 'application/vnd.apple.keynote' => ['key', 'keynote'], + 'application/vnd.apple.mpegurl' => ['m3u8', 'm3u'], + 'application/vnd.apple.numbers' => ['numbers'], + 'application/vnd.apple.pages' => ['pages'], + 'application/vnd.apple.pkpass' => ['pkpass'], + 'application/vnd.aristanetworks.swi' => ['swi'], + 'application/vnd.astraea-software.iota' => ['iota'], + 'application/vnd.audiograph' => ['aep'], + 'application/vnd.balsamiq.bmml+xml' => ['bmml'], + 'application/vnd.blueice.multipass' => ['mpm'], + 'application/vnd.bmi' => ['bmi'], + 'application/vnd.businessobjects' => ['rep'], + 'application/vnd.chemdraw+xml' => ['cdxml'], + 'application/vnd.chess-pgn' => ['pgn'], + 'application/vnd.chipnuts.karaoke-mmd' => ['mmd'], + 'application/vnd.cinderella' => ['cdy'], + 'application/vnd.citationstyles.style+xml' => ['csl'], + 'application/vnd.claymore' => ['cla'], + 'application/vnd.cloanto.rp9' => ['rp9'], + 'application/vnd.clonk.c4group' => ['c4g', 'c4d', 'c4f', 'c4p', 'c4u'], + 'application/vnd.cluetrust.cartomobile-config' => ['c11amc'], + 'application/vnd.cluetrust.cartomobile-config-pkg' => ['c11amz'], + 'application/vnd.coffeescript' => ['coffee'], + 'application/vnd.comicbook+zip' => ['cbz'], + 'application/vnd.comicbook-rar' => ['cbr'], + 'application/vnd.commonspace' => ['csp'], + 'application/vnd.contact.cmsg' => ['cdbcmsg'], + 'application/vnd.corel-draw' => ['cdr'], + 'application/vnd.cosmocaller' => ['cmc'], + 'application/vnd.crick.clicker' => ['clkx'], + 'application/vnd.crick.clicker.keyboard' => ['clkk'], + 'application/vnd.crick.clicker.palette' => ['clkp'], + 'application/vnd.crick.clicker.template' => ['clkt'], + 'application/vnd.crick.clicker.wordbank' => ['clkw'], + 'application/vnd.criticaltools.wbs+xml' => ['wbs'], + 'application/vnd.ctc-posml' => ['pml'], + 'application/vnd.cups-ppd' => ['ppd'], + 'application/vnd.curl.car' => ['car'], + 'application/vnd.curl.pcurl' => ['pcurl'], + 'application/vnd.dart' => ['dart'], + 'application/vnd.data-vision.rdz' => ['rdz'], + 'application/vnd.dbf' => ['dbf'], + 'application/vnd.debian.binary-package' => ['deb', 'udeb'], + 'application/vnd.dece.data' => ['uvf', 'uvvf', 'uvd', 'uvvd'], + 'application/vnd.dece.ttml+xml' => ['uvt', 'uvvt'], + 'application/vnd.dece.unspecified' => ['uvx', 'uvvx'], + 'application/vnd.dece.zip' => ['uvz', 'uvvz'], + 'application/vnd.denovo.fcselayout-link' => ['fe_launch'], + 'application/vnd.dna' => ['dna'], + 'application/vnd.dolby.mlp' => ['mlp'], + 'application/vnd.dpgraph' => ['dpg'], + 'application/vnd.dreamfactory' => ['dfac'], + 'application/vnd.ds-keypoint' => ['kpxx'], + 'application/vnd.dvb.ait' => ['ait'], + 'application/vnd.dvb.service' => ['svc'], + 'application/vnd.dynageo' => ['geo'], + 'application/vnd.ecowin.chart' => ['mag'], + 'application/vnd.efi.img' => ['raw-disk-image', 'img'], + 'application/vnd.efi.iso' => ['iso', 'iso9660'], + 'application/vnd.emusic-emusic_package' => ['emp'], + 'application/vnd.enliven' => ['nml'], + 'application/vnd.epson.esf' => ['esf'], + 'application/vnd.epson.msf' => ['msf'], + 'application/vnd.epson.quickanime' => ['qam'], + 'application/vnd.epson.salt' => ['slt'], + 'application/vnd.epson.ssf' => ['ssf'], + 'application/vnd.eszigno3+xml' => ['es3', 'et3'], + 'application/vnd.etsi.asic-e+zip' => ['asice'], + 'application/vnd.ezpix-album' => ['ez2'], + 'application/vnd.ezpix-package' => ['ez3'], + 'application/vnd.fdf' => ['fdf'], + 'application/vnd.fdsn.mseed' => ['mseed'], + 'application/vnd.fdsn.seed' => ['seed', 'dataless'], + 'application/vnd.flatpak' => ['flatpak', 'xdgapp'], + 'application/vnd.flatpak.ref' => ['flatpakref'], + 'application/vnd.flatpak.repo' => ['flatpakrepo'], + 'application/vnd.flographit' => ['gph'], + 'application/vnd.fluxtime.clip' => ['ftc'], + 'application/vnd.framemaker' => ['fm', 'frame', 'maker', 'book'], + 'application/vnd.frogans.fnc' => ['fnc'], + 'application/vnd.frogans.ltf' => ['ltf'], + 'application/vnd.fsc.weblaunch' => ['fsc'], + 'application/vnd.fujitsu.oasys' => ['oas'], + 'application/vnd.fujitsu.oasys2' => ['oa2'], + 'application/vnd.fujitsu.oasys3' => ['oa3'], + 'application/vnd.fujitsu.oasysgp' => ['fg5'], + 'application/vnd.fujitsu.oasysprs' => ['bh2'], + 'application/vnd.fujixerox.ddd' => ['ddd'], + 'application/vnd.fujixerox.docuworks' => ['xdw'], + 'application/vnd.fujixerox.docuworks.binder' => ['xbd'], + 'application/vnd.fuzzysheet' => ['fzs'], + 'application/vnd.genomatix.tuxedo' => ['txd'], + 'application/vnd.geo+json' => ['geojson', 'geo.json'], + 'application/vnd.geogebra.file' => ['ggb'], + 'application/vnd.geogebra.tool' => ['ggt'], + 'application/vnd.geometry-explorer' => ['gex', 'gre'], + 'application/vnd.geonext' => ['gxt'], + 'application/vnd.geoplan' => ['g2w'], + 'application/vnd.geospace' => ['g3w'], + 'application/vnd.gerber' => ['gbr'], + 'application/vnd.gmx' => ['gmx'], + 'application/vnd.google-apps.document' => ['gdoc'], + 'application/vnd.google-apps.presentation' => ['gslides'], + 'application/vnd.google-apps.spreadsheet' => ['gsheet'], + 'application/vnd.google-earth.kml+xml' => ['kml'], + 'application/vnd.google-earth.kmz' => ['kmz'], + 'application/vnd.grafeq' => ['gqf', 'gqs'], + 'application/vnd.groove-account' => ['gac'], + 'application/vnd.groove-help' => ['ghf'], + 'application/vnd.groove-identity-message' => ['gim'], + 'application/vnd.groove-injector' => ['grv'], + 'application/vnd.groove-tool-message' => ['gtm'], + 'application/vnd.groove-tool-template' => ['tpl'], + 'application/vnd.groove-vcard' => ['vcg'], + 'application/vnd.haansoft-hwp' => ['hwp'], + 'application/vnd.haansoft-hwt' => ['hwt'], + 'application/vnd.hal+xml' => ['hal'], + 'application/vnd.handheld-entertainment+xml' => ['zmm'], + 'application/vnd.hbci' => ['hbci'], + 'application/vnd.hhe.lesson-player' => ['les'], + 'application/vnd.hp-hpgl' => ['hpgl'], + 'application/vnd.hp-hpid' => ['hpid'], + 'application/vnd.hp-hps' => ['hps'], + 'application/vnd.hp-jlyt' => ['jlt'], + 'application/vnd.hp-pcl' => ['pcl'], + 'application/vnd.hp-pclxl' => ['pclxl'], + 'application/vnd.hydrostatix.sof-data' => ['sfd-hdstx'], + 'application/vnd.ibm.minipay' => ['mpy'], + 'application/vnd.ibm.modcap' => ['afp', 'listafp', 'list3820'], + 'application/vnd.ibm.rights-management' => ['irm'], + 'application/vnd.ibm.secure-container' => ['sc'], + 'application/vnd.iccprofile' => ['icc', 'icm'], + 'application/vnd.igloader' => ['igl'], + 'application/vnd.immervision-ivp' => ['ivp'], + 'application/vnd.immervision-ivu' => ['ivu'], + 'application/vnd.insors.igm' => ['igm'], + 'application/vnd.intercon.formnet' => ['xpw', 'xpx'], + 'application/vnd.intergeo' => ['i2g'], + 'application/vnd.intu.qbo' => ['qbo'], + 'application/vnd.intu.qfx' => ['qfx'], + 'application/vnd.ipunplugged.rcprofile' => ['rcprofile'], + 'application/vnd.irepository.package+xml' => ['irp'], + 'application/vnd.is-xpr' => ['xpr'], + 'application/vnd.isac.fcs' => ['fcs'], + 'application/vnd.jam' => ['jam'], + 'application/vnd.jcp.javame.midlet-rms' => ['rms'], + 'application/vnd.jisp' => ['jisp'], + 'application/vnd.joost.joda-archive' => ['joda'], + 'application/vnd.kahootz' => ['ktz', 'ktr'], + 'application/vnd.kde.karbon' => ['karbon'], + 'application/vnd.kde.kchart' => ['chrt'], + 'application/vnd.kde.kformula' => ['kfo'], + 'application/vnd.kde.kivio' => ['flw'], + 'application/vnd.kde.kontour' => ['kon'], + 'application/vnd.kde.kpresenter' => ['kpr', 'kpt'], + 'application/vnd.kde.kspread' => ['ksp'], + 'application/vnd.kde.kword' => ['kwd', 'kwt'], + 'application/vnd.kenameaapp' => ['htke'], + 'application/vnd.kidspiration' => ['kia'], + 'application/vnd.kinar' => ['kne', 'knp'], + 'application/vnd.koan' => ['skp', 'skd', 'skt', 'skm'], + 'application/vnd.kodak-descriptor' => ['sse'], + 'application/vnd.las.las+xml' => ['lasxml'], + 'application/vnd.llamagraphics.life-balance.desktop' => ['lbd'], + 'application/vnd.llamagraphics.life-balance.exchange+xml' => ['lbe'], + 'application/vnd.lotus-1-2-3' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'application/vnd.lotus-approach' => ['apr'], + 'application/vnd.lotus-freelance' => ['pre'], + 'application/vnd.lotus-notes' => ['nsf'], + 'application/vnd.lotus-organizer' => ['org'], + 'application/vnd.lotus-screencam' => ['scm'], + 'application/vnd.lotus-wordpro' => ['lwp'], + 'application/vnd.macports.portpkg' => ['portpkg'], + 'application/vnd.mapbox-vector-tile' => ['mvt'], + 'application/vnd.mcd' => ['mcd'], + 'application/vnd.medcalcdata' => ['mc1'], + 'application/vnd.mediastation.cdkey' => ['cdkey'], + 'application/vnd.mfer' => ['mwf'], + 'application/vnd.mfmp' => ['mfm'], + 'application/vnd.micrografx.flo' => ['flo'], + 'application/vnd.micrografx.igx' => ['igx'], + 'application/vnd.microsoft.portable-executable' => ['exe', 'dll', 'cpl', 'drv', 'scr', 'efi', 'ocx', 'sys', 'lib'], + 'application/vnd.mif' => ['mif'], + 'application/vnd.mobius.daf' => ['daf'], + 'application/vnd.mobius.dis' => ['dis'], + 'application/vnd.mobius.mbk' => ['mbk'], + 'application/vnd.mobius.mqy' => ['mqy'], + 'application/vnd.mobius.msl' => ['msl'], + 'application/vnd.mobius.plc' => ['plc'], + 'application/vnd.mobius.txf' => ['txf'], + 'application/vnd.mophun.application' => ['mpn'], + 'application/vnd.mophun.certificate' => ['mpc'], + 'application/vnd.mozilla.xul+xml' => ['xul'], + 'application/vnd.ms-3mfdocument' => ['3mf'], + 'application/vnd.ms-access' => ['mdb'], + 'application/vnd.ms-artgalry' => ['cil'], + 'application/vnd.ms-asf' => ['asf'], + 'application/vnd.ms-cab-compressed' => ['cab'], + 'application/vnd.ms-excel' => ['xls', 'xlm', 'xla', 'xlc', 'xlt', 'xlw', 'xll', 'xld'], + 'application/vnd.ms-excel.addin.macroenabled.12' => ['xlam'], + 'application/vnd.ms-excel.sheet.binary.macroenabled.12' => ['xlsb'], + 'application/vnd.ms-excel.sheet.macroenabled.12' => ['xlsm'], + 'application/vnd.ms-excel.template.macroenabled.12' => ['xltm'], + 'application/vnd.ms-fontobject' => ['eot'], + 'application/vnd.ms-htmlhelp' => ['chm'], + 'application/vnd.ms-ims' => ['ims'], + 'application/vnd.ms-lrm' => ['lrm'], + 'application/vnd.ms-officetheme' => ['thmx'], + 'application/vnd.ms-outlook' => ['msg'], + 'application/vnd.ms-pki.seccat' => ['cat'], + 'application/vnd.ms-pki.stl' => ['stl'], + 'application/vnd.ms-powerpoint' => ['ppt', 'pps', 'pot', 'ppz'], + 'application/vnd.ms-powerpoint.addin.macroenabled.12' => ['ppam'], + 'application/vnd.ms-powerpoint.presentation.macroenabled.12' => ['pptm'], + 'application/vnd.ms-powerpoint.slide.macroenabled.12' => ['sldm'], + 'application/vnd.ms-powerpoint.slideshow.macroenabled.12' => ['ppsm'], + 'application/vnd.ms-powerpoint.template.macroenabled.12' => ['potm'], + 'application/vnd.ms-project' => ['mpp', 'mpt'], + 'application/vnd.ms-publisher' => ['pub'], + 'application/vnd.ms-tnef' => ['tnef', 'tnf'], + 'application/vnd.ms-visio.drawing.macroenabled.main+xml' => ['vsdm'], + 'application/vnd.ms-visio.drawing.main+xml' => ['vsdx'], + 'application/vnd.ms-visio.stencil.macroenabled.main+xml' => ['vssm'], + 'application/vnd.ms-visio.stencil.main+xml' => ['vssx'], + 'application/vnd.ms-visio.template.macroenabled.main+xml' => ['vstm'], + 'application/vnd.ms-visio.template.main+xml' => ['vstx'], + 'application/vnd.ms-word' => ['doc'], + 'application/vnd.ms-word.document.macroenabled.12' => ['docm'], + 'application/vnd.ms-word.template.macroenabled.12' => ['dotm'], + 'application/vnd.ms-works' => ['wps', 'wks', 'wcm', 'wdb', 'xlr'], + 'application/vnd.ms-wpl' => ['wpl'], + 'application/vnd.ms-xpsdocument' => ['xps'], + 'application/vnd.msaccess' => ['mdb'], + 'application/vnd.mseq' => ['mseq'], + 'application/vnd.musician' => ['mus'], + 'application/vnd.muvee.style' => ['msty'], + 'application/vnd.mynfc' => ['taglet'], + 'application/vnd.neurolanguage.nlu' => ['nlu'], + 'application/vnd.nintendo.snes.rom' => ['sfc', 'smc'], + 'application/vnd.nitf' => ['ntf', 'nitf'], + 'application/vnd.noblenet-directory' => ['nnd'], + 'application/vnd.noblenet-sealer' => ['nns'], + 'application/vnd.noblenet-web' => ['nnw'], + 'application/vnd.nokia.n-gage.ac+xml' => ['ac'], + 'application/vnd.nokia.n-gage.data' => ['ngdat'], + 'application/vnd.nokia.n-gage.symbian.install' => ['n-gage'], + 'application/vnd.nokia.radio-preset' => ['rpst'], + 'application/vnd.nokia.radio-presets' => ['rpss'], + 'application/vnd.novadigm.edm' => ['edm'], + 'application/vnd.novadigm.edx' => ['edx'], + 'application/vnd.novadigm.ext' => ['ext'], + 'application/vnd.oasis.docbook+xml' => ['dbk', 'docbook'], + 'application/vnd.oasis.opendocument.chart' => ['odc'], + 'application/vnd.oasis.opendocument.chart-template' => ['otc'], + 'application/vnd.oasis.opendocument.database' => ['odb'], + 'application/vnd.oasis.opendocument.formula' => ['odf'], + 'application/vnd.oasis.opendocument.formula-template' => ['odft', 'otf'], + 'application/vnd.oasis.opendocument.graphics' => ['odg'], + 'application/vnd.oasis.opendocument.graphics-flat-xml' => ['fodg'], + 'application/vnd.oasis.opendocument.graphics-template' => ['otg'], + 'application/vnd.oasis.opendocument.image' => ['odi'], + 'application/vnd.oasis.opendocument.image-template' => ['oti'], + 'application/vnd.oasis.opendocument.presentation' => ['odp'], + 'application/vnd.oasis.opendocument.presentation-flat-xml' => ['fodp'], + 'application/vnd.oasis.opendocument.presentation-template' => ['otp'], + 'application/vnd.oasis.opendocument.spreadsheet' => ['ods'], + 'application/vnd.oasis.opendocument.spreadsheet-flat-xml' => ['fods'], + 'application/vnd.oasis.opendocument.spreadsheet-template' => ['ots'], + 'application/vnd.oasis.opendocument.text' => ['odt'], + 'application/vnd.oasis.opendocument.text-flat-xml' => ['fodt'], + 'application/vnd.oasis.opendocument.text-master' => ['odm'], + 'application/vnd.oasis.opendocument.text-template' => ['ott'], + 'application/vnd.oasis.opendocument.text-web' => ['oth'], + 'application/vnd.olpc-sugar' => ['xo'], + 'application/vnd.oma.dd2+xml' => ['dd2'], + 'application/vnd.openblox.game+xml' => ['obgx'], + 'application/vnd.openofficeorg.extension' => ['oxt'], + 'application/vnd.openstreetmap.data+xml' => ['osm'], + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => ['pptx'], + 'application/vnd.openxmlformats-officedocument.presentationml.slide' => ['sldx'], + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => ['ppsx'], + 'application/vnd.openxmlformats-officedocument.presentationml.template' => ['potx'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => ['xlsx'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => ['xltx'], + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => ['docx'], + 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => ['dotx'], + 'application/vnd.osgeo.mapguide.package' => ['mgp'], + 'application/vnd.osgi.dp' => ['dp'], + 'application/vnd.osgi.subsystem' => ['esa'], + 'application/vnd.palm' => ['pdb', 'pqa', 'oprc', 'prc'], + 'application/vnd.pawaafile' => ['paw'], + 'application/vnd.pg.format' => ['str'], + 'application/vnd.pg.osasli' => ['ei6'], + 'application/vnd.picsel' => ['efif'], + 'application/vnd.pmi.widget' => ['wg'], + 'application/vnd.pocketlearn' => ['plf'], + 'application/vnd.powerbuilder6' => ['pbd'], + 'application/vnd.previewsystems.box' => ['box'], + 'application/vnd.proteus.magazine' => ['mgz'], + 'application/vnd.publishare-delta-tree' => ['qps'], + 'application/vnd.pvi.ptid1' => ['ptid'], + 'application/vnd.quark.quarkxpress' => ['qxd', 'qxt', 'qwd', 'qwt', 'qxl', 'qxb'], + 'application/vnd.rar' => ['rar'], + 'application/vnd.realvnc.bed' => ['bed'], + 'application/vnd.recordare.musicxml' => ['mxl'], + 'application/vnd.recordare.musicxml+xml' => ['musicxml'], + 'application/vnd.rig.cryptonote' => ['cryptonote'], + 'application/vnd.rim.cod' => ['cod'], + 'application/vnd.rn-realmedia' => ['rm', 'rmj', 'rmm', 'rms', 'rmx', 'rmvb'], + 'application/vnd.rn-realmedia-vbr' => ['rmvb', 'rm', 'rmj', 'rmm', 'rms', 'rmx'], + 'application/vnd.route66.link66+xml' => ['link66'], + 'application/vnd.sailingtracker.track' => ['st'], + 'application/vnd.sdp' => ['sdp'], + 'application/vnd.seemail' => ['see'], + 'application/vnd.sema' => ['sema'], + 'application/vnd.semd' => ['semd'], + 'application/vnd.semf' => ['semf'], + 'application/vnd.shana.informed.formdata' => ['ifm'], + 'application/vnd.shana.informed.formtemplate' => ['itp'], + 'application/vnd.shana.informed.interchange' => ['iif'], + 'application/vnd.shana.informed.package' => ['ipk'], + 'application/vnd.simtech-mindmapper' => ['twd', 'twds'], + 'application/vnd.smaf' => ['mmf', 'smaf'], + 'application/vnd.smart.teacher' => ['teacher'], + 'application/vnd.snap' => ['snap'], + 'application/vnd.software602.filler.form+xml' => ['fo'], + 'application/vnd.solent.sdkm+xml' => ['sdkm', 'sdkd'], + 'application/vnd.spotfire.dxp' => ['dxp'], + 'application/vnd.spotfire.sfs' => ['sfs'], + 'application/vnd.sqlite3' => ['sqlite3'], + 'application/vnd.squashfs' => ['sqsh'], + 'application/vnd.stardivision.calc' => ['sdc'], + 'application/vnd.stardivision.chart' => ['sds'], + 'application/vnd.stardivision.draw' => ['sda'], + 'application/vnd.stardivision.impress' => ['sdd', 'sdp'], + 'application/vnd.stardivision.mail' => ['smd'], + 'application/vnd.stardivision.math' => ['smf'], + 'application/vnd.stardivision.writer' => ['sdw', 'vor', 'sgl'], + 'application/vnd.stardivision.writer-global' => ['sgl', 'sdw', 'vor'], + 'application/vnd.stepmania.package' => ['smzip'], + 'application/vnd.stepmania.stepchart' => ['sm'], + 'application/vnd.sun.wadl+xml' => ['wadl'], + 'application/vnd.sun.xml.base' => ['odb'], + 'application/vnd.sun.xml.calc' => ['sxc'], + 'application/vnd.sun.xml.calc.template' => ['stc'], + 'application/vnd.sun.xml.draw' => ['sxd'], + 'application/vnd.sun.xml.draw.template' => ['std'], + 'application/vnd.sun.xml.impress' => ['sxi'], + 'application/vnd.sun.xml.impress.template' => ['sti'], + 'application/vnd.sun.xml.math' => ['sxm'], + 'application/vnd.sun.xml.writer' => ['sxw'], + 'application/vnd.sun.xml.writer.global' => ['sxg'], + 'application/vnd.sun.xml.writer.template' => ['stw'], + 'application/vnd.sus-calendar' => ['sus', 'susp'], + 'application/vnd.svd' => ['svd'], + 'application/vnd.symbian.install' => ['sis', 'sisx'], + 'application/vnd.syncml+xml' => ['xsm'], + 'application/vnd.syncml.dm+wbxml' => ['bdm'], + 'application/vnd.syncml.dm+xml' => ['xdm'], + 'application/vnd.syncml.dmddf+xml' => ['ddf'], + 'application/vnd.tao.intent-module-archive' => ['tao'], + 'application/vnd.tcpdump.pcap' => ['pcap', 'cap', 'dmp'], + 'application/vnd.tmobile-livetv' => ['tmo'], + 'application/vnd.trid.tpt' => ['tpt'], + 'application/vnd.triscape.mxs' => ['mxs'], + 'application/vnd.trueapp' => ['tra'], + 'application/vnd.truedoc' => ['pfr'], + 'application/vnd.ufdl' => ['ufd', 'ufdl'], + 'application/vnd.uiq.theme' => ['utz'], + 'application/vnd.umajin' => ['umj'], + 'application/vnd.unity' => ['unityweb'], + 'application/vnd.uoml+xml' => ['uoml'], + 'application/vnd.vcx' => ['vcx'], + 'application/vnd.visio' => ['vsd', 'vst', 'vss', 'vsw'], + 'application/vnd.visionary' => ['vis'], + 'application/vnd.vsf' => ['vsf'], + 'application/vnd.wap.wbxml' => ['wbxml'], + 'application/vnd.wap.wmlc' => ['wmlc'], + 'application/vnd.wap.wmlscriptc' => ['wmlsc'], + 'application/vnd.webturbo' => ['wtb'], + 'application/vnd.wolfram.player' => ['nbp'], + 'application/vnd.wordperfect' => ['wpd', 'wp', 'wp4', 'wp5', 'wp6', 'wpp'], + 'application/vnd.wqd' => ['wqd'], + 'application/vnd.wt.stf' => ['stf'], + 'application/vnd.xara' => ['xar'], + 'application/vnd.xdgapp' => ['flatpak', 'xdgapp'], + 'application/vnd.xfdl' => ['xfdl'], + 'application/vnd.yamaha.hv-dic' => ['hvd'], + 'application/vnd.yamaha.hv-script' => ['hvs'], + 'application/vnd.yamaha.hv-voice' => ['hvp'], + 'application/vnd.yamaha.openscoreformat' => ['osf'], + 'application/vnd.yamaha.openscoreformat.osfpvg+xml' => ['osfpvg'], + 'application/vnd.yamaha.smaf-audio' => ['saf'], + 'application/vnd.yamaha.smaf-phrase' => ['spf'], + 'application/vnd.yellowriver-custom-menu' => ['cmp'], + 'application/vnd.youtube.yt' => ['yt'], + 'application/vnd.zul' => ['zir', 'zirz'], + 'application/vnd.zzazz.deck+xml' => ['zaz'], + 'application/voicexml+xml' => ['vxml'], + 'application/wasm' => ['wasm'], + 'application/watcherinfo+xml' => ['wif'], + 'application/widget' => ['wgt'], + 'application/winhlp' => ['hlp'], + 'application/wk1' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'application/wmf' => ['wmf'], + 'application/wordperfect' => ['wp', 'wp4', 'wp5', 'wp6', 'wpd', 'wpp'], + 'application/wsdl+xml' => ['wsdl'], + 'application/wspolicy+xml' => ['wspolicy'], + 'application/wwf' => ['wwf'], + 'application/x-123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'application/x-7z-compressed' => ['7z', '7z.001'], + 'application/x-abiword' => ['abw', 'abw.CRASHED', 'abw.gz', 'zabw'], + 'application/x-ace' => ['ace'], + 'application/x-ace-compressed' => ['ace'], + 'application/x-alz' => ['alz'], + 'application/x-amiga-disk-format' => ['adf'], + 'application/x-amipro' => ['sam'], + 'application/x-annodex' => ['anx'], + 'application/x-aportisdoc' => ['pdb', 'pdc'], + 'application/x-apple-diskimage' => ['dmg'], + 'application/x-apple-systemprofiler+xml' => ['spx'], + 'application/x-appleworks-document' => ['cwk'], + 'application/x-applix-spreadsheet' => ['as'], + 'application/x-applix-word' => ['aw'], + 'application/x-archive' => ['a', 'ar'], + 'application/x-arj' => ['arj'], + 'application/x-asar' => ['asar'], + 'application/x-asp' => ['asp'], + 'application/x-atari-2600-rom' => ['a26'], + 'application/x-atari-7800-rom' => ['a78'], + 'application/x-atari-lynx-rom' => ['lnx'], + 'application/x-authorware-bin' => ['aab', 'x32', 'u32', 'vox'], + 'application/x-authorware-map' => ['aam'], + 'application/x-authorware-seg' => ['aas'], + 'application/x-awk' => ['awk'], + 'application/x-bat' => ['bat'], + 'application/x-bcpio' => ['bcpio'], + 'application/x-bdoc' => ['bdoc'], + 'application/x-bittorrent' => ['torrent'], + 'application/x-blender' => ['blend', 'BLEND', 'blender'], + 'application/x-blorb' => ['blb', 'blorb'], + 'application/x-bps-patch' => ['bps'], + 'application/x-bsdiff' => ['bsdiff'], + 'application/x-bz2' => ['bz2'], + 'application/x-bzdvi' => ['dvi.bz2'], + 'application/x-bzip' => ['bz', 'bz2'], + 'application/x-bzip-compressed-tar' => ['tar.bz2', 'tbz2', 'tb2'], + 'application/x-bzip1' => ['bz'], + 'application/x-bzip1-compressed-tar' => ['tar.bz', 'tbz'], + 'application/x-bzip2' => ['bz2', 'boz'], + 'application/x-bzip2-compressed-tar' => ['tar.bz2', 'tbz2', 'tb2'], + 'application/x-bzip3' => ['bz3'], + 'application/x-bzip3-compressed-tar' => ['tar.bz3', 'tbz3'], + 'application/x-bzpdf' => ['pdf.bz2'], + 'application/x-bzpostscript' => ['ps.bz2'], + 'application/x-cb7' => ['cb7'], + 'application/x-cbr' => ['cbr', 'cba', 'cbt', 'cbz', 'cb7'], + 'application/x-cbt' => ['cbt'], + 'application/x-cbz' => ['cbz'], + 'application/x-ccmx' => ['ccmx'], + 'application/x-cd-image' => ['iso', 'iso9660'], + 'application/x-cdlink' => ['vcd'], + 'application/x-cdr' => ['cdr'], + 'application/x-cdrdao-toc' => ['toc'], + 'application/x-cfs-compressed' => ['cfs'], + 'application/x-chat' => ['chat'], + 'application/x-chess-pgn' => ['pgn'], + 'application/x-chm' => ['chm'], + 'application/x-chrome-extension' => ['crx'], + 'application/x-cisco-vpn-settings' => ['pcf'], + 'application/x-cocoa' => ['cco'], + 'application/x-compress' => ['Z'], + 'application/x-compressed-iso' => ['cso'], + 'application/x-compressed-tar' => ['tar.gz', 'tgz'], + 'application/x-conference' => ['nsc'], + 'application/x-coreldraw' => ['cdr'], + 'application/x-cpio' => ['cpio'], + 'application/x-cpio-compressed' => ['cpio.gz'], + 'application/x-csh' => ['csh'], + 'application/x-cue' => ['cue'], + 'application/x-dar' => ['dar'], + 'application/x-dbase' => ['dbf'], + 'application/x-dbf' => ['dbf'], + 'application/x-dc-rom' => ['dc'], + 'application/x-deb' => ['deb', 'udeb'], + 'application/x-debian-package' => ['deb', 'udeb'], + 'application/x-designer' => ['ui'], + 'application/x-desktop' => ['desktop', 'kdelnk'], + 'application/x-dgc-compressed' => ['dgc'], + 'application/x-dia-diagram' => ['dia'], + 'application/x-dia-shape' => ['shape'], + 'application/x-director' => ['dir', 'dcr', 'dxr', 'cst', 'cct', 'cxt', 'w3d', 'fgd', 'swa'], + 'application/x-discjuggler-cd-image' => ['cdi'], + 'application/x-docbook+xml' => ['dbk', 'docbook'], + 'application/x-doom' => ['wad'], + 'application/x-doom-wad' => ['wad'], + 'application/x-dosexec' => ['exe'], + 'application/x-dreamcast-rom' => ['iso'], + 'application/x-dtbncx+xml' => ['ncx'], + 'application/x-dtbook+xml' => ['dtb'], + 'application/x-dtbresource+xml' => ['res'], + 'application/x-dvi' => ['dvi'], + 'application/x-e-theme' => ['etheme'], + 'application/x-egon' => ['egon'], + 'application/x-emf' => ['emf'], + 'application/x-envoy' => ['evy'], + 'application/x-eris-link+cbor' => ['eris'], + 'application/x-eva' => ['eva'], + 'application/x-excellon' => ['drl'], + 'application/x-fd-file' => ['fd', 'qd'], + 'application/x-fds-disk' => ['fds'], + 'application/x-fictionbook' => ['fb2'], + 'application/x-fictionbook+xml' => ['fb2'], + 'application/x-fishscript' => ['fish'], + 'application/x-flash-video' => ['flv'], + 'application/x-fluid' => ['fl'], + 'application/x-font-afm' => ['afm'], + 'application/x-font-bdf' => ['bdf'], + 'application/x-font-ghostscript' => ['gsf'], + 'application/x-font-linux-psf' => ['psf'], + 'application/x-font-otf' => ['otf'], + 'application/x-font-pcf' => ['pcf', 'pcf.Z', 'pcf.gz'], + 'application/x-font-snf' => ['snf'], + 'application/x-font-speedo' => ['spd'], + 'application/x-font-truetype' => ['ttf'], + 'application/x-font-ttf' => ['ttf'], + 'application/x-font-ttx' => ['ttx'], + 'application/x-font-type1' => ['pfa', 'pfb', 'pfm', 'afm', 'gsf'], + 'application/x-font-woff' => ['woff'], + 'application/x-frame' => ['fm'], + 'application/x-freearc' => ['arc'], + 'application/x-futuresplash' => ['spl'], + 'application/x-gameboy-color-rom' => ['gbc', 'cgb'], + 'application/x-gameboy-rom' => ['gb', 'sgb'], + 'application/x-gamecube-iso-image' => ['iso'], + 'application/x-gamecube-rom' => ['iso'], + 'application/x-gamegear-rom' => ['gg'], + 'application/x-gba-rom' => ['gba', 'agb'], + 'application/x-gca-compressed' => ['gca'], + 'application/x-gd-rom-cue' => ['gdi'], + 'application/x-gdscript' => ['gd'], + 'application/x-gedcom' => ['ged', 'gedcom'], + 'application/x-genesis-32x-rom' => ['32x', 'mdx'], + 'application/x-genesis-rom' => ['gen', 'smd', 'sgd'], + 'application/x-gerber' => ['gbr'], + 'application/x-gerber-job' => ['gbrjob'], + 'application/x-gettext' => ['po'], + 'application/x-gettext-translation' => ['gmo', 'mo'], + 'application/x-glade' => ['glade'], + 'application/x-glulx' => ['ulx'], + 'application/x-gnome-app-info' => ['desktop', 'kdelnk'], + 'application/x-gnucash' => ['gnucash', 'gnc', 'xac'], + 'application/x-gnumeric' => ['gnumeric'], + 'application/x-gnuplot' => ['gp', 'gplt', 'gnuplot'], + 'application/x-go-sgf' => ['sgf'], + 'application/x-godot-resource' => ['res', 'tres'], + 'application/x-godot-scene' => ['scn', 'tscn', 'escn'], + 'application/x-godot-shader' => ['gdshader'], + 'application/x-gpx' => ['gpx'], + 'application/x-gpx+xml' => ['gpx'], + 'application/x-gramps-xml' => ['gramps'], + 'application/x-graphite' => ['gra'], + 'application/x-gtar' => ['gtar', 'tar', 'gem'], + 'application/x-gtk-builder' => ['ui'], + 'application/x-gz-font-linux-psf' => ['psf.gz'], + 'application/x-gzdvi' => ['dvi.gz'], + 'application/x-gzip' => ['gz'], + 'application/x-gzpdf' => ['pdf.gz'], + 'application/x-gzpostscript' => ['ps.gz'], + 'application/x-hdf' => ['hdf', 'hdf4', 'h4', 'hdf5', 'h5'], + 'application/x-hfe-file' => ['hfe'], + 'application/x-hfe-floppy-image' => ['hfe'], + 'application/x-httpd-php' => ['php'], + 'application/x-hwp' => ['hwp'], + 'application/x-hwt' => ['hwt'], + 'application/x-ica' => ['ica'], + 'application/x-install-instructions' => ['install'], + 'application/x-ips-patch' => ['ips'], + 'application/x-ipynb+json' => ['ipynb'], + 'application/x-iso9660-appimage' => ['appimage'], + 'application/x-iso9660-image' => ['iso', 'iso9660'], + 'application/x-it87' => ['it87'], + 'application/x-iwork-keynote-sffkey' => ['key'], + 'application/x-iwork-numbers-sffnumbers' => ['numbers'], + 'application/x-iwork-pages-sffpages' => ['pages'], + 'application/x-jar' => ['jar'], + 'application/x-java' => ['class'], + 'application/x-java-archive' => ['jar'], + 'application/x-java-archive-diff' => ['jardiff'], + 'application/x-java-class' => ['class'], + 'application/x-java-jce-keystore' => ['jceks'], + 'application/x-java-jnlp-file' => ['jnlp'], + 'application/x-java-keystore' => ['jks', 'ks'], + 'application/x-java-pack200' => ['pack'], + 'application/x-java-vm' => ['class'], + 'application/x-javascript' => ['js', 'jsm', 'mjs'], + 'application/x-jbuilder-project' => ['jpr', 'jpx'], + 'application/x-karbon' => ['karbon'], + 'application/x-kchart' => ['chrt'], + 'application/x-keepass2' => ['kdbx'], + 'application/x-kexi-connectiondata' => ['kexic'], + 'application/x-kexiproject-shortcut' => ['kexis'], + 'application/x-kexiproject-sqlite' => ['kexi'], + 'application/x-kexiproject-sqlite2' => ['kexi'], + 'application/x-kexiproject-sqlite3' => ['kexi'], + 'application/x-kformula' => ['kfo'], + 'application/x-killustrator' => ['kil'], + 'application/x-kivio' => ['flw'], + 'application/x-kontour' => ['kon'], + 'application/x-kpovmodeler' => ['kpm'], + 'application/x-kpresenter' => ['kpr', 'kpt'], + 'application/x-krita' => ['kra', 'krz'], + 'application/x-kspread' => ['ksp'], + 'application/x-kugar' => ['kud'], + 'application/x-kword' => ['kwd', 'kwt'], + 'application/x-latex' => ['latex'], + 'application/x-lha' => ['lha', 'lzh'], + 'application/x-lhz' => ['lhz'], + 'application/x-linguist' => ['ts'], + 'application/x-lmdb' => ['mdb', 'lmdb'], + 'application/x-lotus123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'application/x-lrzip' => ['lrz'], + 'application/x-lrzip-compressed-tar' => ['tar.lrz', 'tlrz'], + 'application/x-lua-bytecode' => ['luac'], + 'application/x-lyx' => ['lyx'], + 'application/x-lz4' => ['lz4'], + 'application/x-lz4-compressed-tar' => ['tar.lz4'], + 'application/x-lzh-compressed' => ['lzh', 'lha'], + 'application/x-lzip' => ['lz'], + 'application/x-lzip-compressed-tar' => ['tar.lz'], + 'application/x-lzma' => ['lzma'], + 'application/x-lzma-compressed-tar' => ['tar.lzma', 'tlz'], + 'application/x-lzop' => ['lzo'], + 'application/x-lzpdf' => ['pdf.lz'], + 'application/x-m4' => ['m4'], + 'application/x-magicpoint' => ['mgp'], + 'application/x-makeself' => ['run'], + 'application/x-mame-chd' => ['chd'], + 'application/x-markaby' => ['mab'], + 'application/x-mathematica' => ['nb'], + 'application/x-mdb' => ['mdb'], + 'application/x-mie' => ['mie'], + 'application/x-mif' => ['mif'], + 'application/x-mimearchive' => ['mhtml', 'mht'], + 'application/x-mobi8-ebook' => ['azw3', 'kfx'], + 'application/x-mobipocket-ebook' => ['prc', 'mobi'], + 'application/x-modrinth-modpack+zip' => ['mrpack'], + 'application/x-ms-application' => ['application'], + 'application/x-ms-asx' => ['asx', 'wax', 'wvx', 'wmx'], + 'application/x-ms-dos-executable' => ['exe', 'dll', 'cpl', 'drv', 'scr'], + 'application/x-ms-ne-executable' => ['exe', 'dll', 'cpl', 'drv', 'scr'], + 'application/x-ms-pdb' => ['pdb'], + 'application/x-ms-shortcut' => ['lnk'], + 'application/x-ms-wim' => ['wim', 'swm'], + 'application/x-ms-wmd' => ['wmd'], + 'application/x-ms-wmz' => ['wmz'], + 'application/x-ms-xbap' => ['xbap'], + 'application/x-msaccess' => ['mdb'], + 'application/x-msbinder' => ['obd'], + 'application/x-mscardfile' => ['crd'], + 'application/x-msclip' => ['clp'], + 'application/x-msdos-program' => ['exe'], + 'application/x-msdownload' => ['exe', 'dll', 'com', 'bat', 'msi', 'cpl', 'drv', 'scr'], + 'application/x-msexcel' => ['xls', 'xlc', 'xll', 'xlm', 'xlw', 'xla', 'xlt', 'xld'], + 'application/x-msi' => ['msi'], + 'application/x-msmediaview' => ['mvb', 'm13', 'm14'], + 'application/x-msmetafile' => ['wmf', 'wmz', 'emf', 'emz'], + 'application/x-msmoney' => ['mny'], + 'application/x-mspowerpoint' => ['ppz', 'ppt', 'pps', 'pot'], + 'application/x-mspublisher' => ['pub'], + 'application/x-msschedule' => ['scd'], + 'application/x-msterminal' => ['trm'], + 'application/x-mswinurl' => ['url'], + 'application/x-msword' => ['doc'], + 'application/x-mswrite' => ['wri'], + 'application/x-msx-rom' => ['msx'], + 'application/x-n64-rom' => ['n64', 'z64', 'v64'], + 'application/x-navi-animation' => ['ani'], + 'application/x-neo-geo-pocket-color-rom' => ['ngc'], + 'application/x-neo-geo-pocket-rom' => ['ngp'], + 'application/x-nes-rom' => ['nes', 'nez', 'unf', 'unif'], + 'application/x-netcdf' => ['nc', 'cdf'], + 'application/x-netshow-channel' => ['nsc'], + 'application/x-nintendo-3ds-executable' => ['3dsx'], + 'application/x-nintendo-3ds-rom' => ['3ds', 'cci'], + 'application/x-nintendo-ds-rom' => ['nds'], + 'application/x-ns-proxy-autoconfig' => ['pac'], + 'application/x-nuscript' => ['nu'], + 'application/x-nzb' => ['nzb'], + 'application/x-object' => ['o', 'mod'], + 'application/x-ogg' => ['ogx'], + 'application/x-oleo' => ['oleo'], + 'application/x-openvpn-profile' => ['openvpn', 'ovpn'], + 'application/x-openzim' => ['zim'], + 'application/x-pagemaker' => ['p65', 'pm', 'pm6', 'pmd'], + 'application/x-pak' => ['pak'], + 'application/x-palm-database' => ['prc', 'pdb', 'pqa', 'oprc'], + 'application/x-par2' => ['PAR2', 'par2'], + 'application/x-partial-download' => ['wkdownload', 'crdownload', 'part'], + 'application/x-pc-engine-rom' => ['pce'], + 'application/x-pcap' => ['pcap', 'cap', 'dmp'], + 'application/x-pdf' => ['pdf'], + 'application/x-perl' => ['pl', 'pm', 'PL', 'al', 'perl', 'pod', 't'], + 'application/x-photoshop' => ['psd'], + 'application/x-php' => ['php', 'php3', 'php4', 'php5', 'phps'], + 'application/x-pilot' => ['prc', 'pdb'], + 'application/x-pkcs12' => ['p12', 'pfx'], + 'application/x-pkcs7-certificates' => ['p7b', 'spc'], + 'application/x-pkcs7-certreqresp' => ['p7r'], + 'application/x-planperfect' => ['pln'], + 'application/x-pocket-word' => ['psw'], + 'application/x-powershell' => ['ps1'], + 'application/x-pw' => ['pw'], + 'application/x-pyspread-bz-spreadsheet' => ['pys'], + 'application/x-pyspread-spreadsheet' => ['pysu'], + 'application/x-python-bytecode' => ['pyc', 'pyo'], + 'application/x-qed-disk' => ['qed'], + 'application/x-qemu-disk' => ['qcow2', 'qcow'], + 'application/x-qpress' => ['qp'], + 'application/x-qtiplot' => ['qti', 'qti.gz'], + 'application/x-quattropro' => ['wb1', 'wb2', 'wb3', 'qpw'], + 'application/x-quicktime-media-link' => ['qtl'], + 'application/x-quicktimeplayer' => ['qtl'], + 'application/x-qw' => ['qif'], + 'application/x-rar' => ['rar'], + 'application/x-rar-compressed' => ['rar'], + 'application/x-raw-disk-image' => ['raw-disk-image', 'img'], + 'application/x-raw-disk-image-xz-compressed' => ['raw-disk-image.xz', 'img.xz'], + 'application/x-raw-floppy-disk-image' => ['fd', 'qd'], + 'application/x-redhat-package-manager' => ['rpm'], + 'application/x-reject' => ['rej'], + 'application/x-research-info-systems' => ['ris'], + 'application/x-rnc' => ['rnc'], + 'application/x-rpm' => ['rpm'], + 'application/x-ruby' => ['rb'], + 'application/x-rzip' => ['rz'], + 'application/x-rzip-compressed-tar' => ['tar.rz', 'trz'], + 'application/x-sami' => ['smi', 'sami'], + 'application/x-sap-file' => ['sap'], + 'application/x-saturn-rom' => ['iso'], + 'application/x-sdp' => ['sdp'], + 'application/x-sea' => ['sea'], + 'application/x-sega-cd-rom' => ['iso'], + 'application/x-sega-pico-rom' => ['iso'], + 'application/x-sg1000-rom' => ['sg'], + 'application/x-sh' => ['sh'], + 'application/x-shar' => ['shar'], + 'application/x-shared-library-la' => ['la'], + 'application/x-sharedlib' => ['so'], + 'application/x-shellscript' => ['sh'], + 'application/x-shockwave-flash' => ['swf', 'spl'], + 'application/x-shorten' => ['shn'], + 'application/x-siag' => ['siag'], + 'application/x-silverlight-app' => ['xap'], + 'application/x-sit' => ['sit'], + 'application/x-sitx' => ['sitx'], + 'application/x-smaf' => ['mmf', 'smaf'], + 'application/x-sms-rom' => ['sms'], + 'application/x-snes-rom' => ['sfc', 'smc'], + 'application/x-source-rpm' => ['src.rpm', 'spm'], + 'application/x-spss-por' => ['por'], + 'application/x-spss-sav' => ['sav', 'zsav'], + 'application/x-spss-savefile' => ['sav', 'zsav'], + 'application/x-sql' => ['sql'], + 'application/x-sqlite2' => ['sqlite2'], + 'application/x-sqlite3' => ['sqlite3'], + 'application/x-srt' => ['srt'], + 'application/x-stuffit' => ['sit'], + 'application/x-stuffitx' => ['sitx'], + 'application/x-subrip' => ['srt'], + 'application/x-sv4cpio' => ['sv4cpio'], + 'application/x-sv4crc' => ['sv4crc'], + 'application/x-t3vm-image' => ['t3'], + 'application/x-t602' => ['602'], + 'application/x-tads' => ['gam'], + 'application/x-tar' => ['tar', 'gtar', 'gem'], + 'application/x-targa' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'application/x-tarz' => ['tar.Z', 'taz'], + 'application/x-tcl' => ['tcl', 'tk'], + 'application/x-tex' => ['tex', 'ltx', 'sty', 'cls', 'dtx', 'ins', 'latex'], + 'application/x-tex-gf' => ['gf'], + 'application/x-tex-pk' => ['pk'], + 'application/x-tex-tfm' => ['tfm'], + 'application/x-texinfo' => ['texinfo', 'texi'], + 'application/x-tga' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'application/x-tgif' => ['obj'], + 'application/x-theme' => ['theme'], + 'application/x-thomson-cartridge-memo7' => ['m7'], + 'application/x-thomson-cassette' => ['k7'], + 'application/x-thomson-sap-image' => ['sap'], + 'application/x-tiled-tmx' => ['tmx'], + 'application/x-tiled-tsx' => ['tsx'], + 'application/x-trash' => ['bak', 'old', 'sik'], + 'application/x-trig' => ['trig'], + 'application/x-troff' => ['tr', 'roff', 't'], + 'application/x-troff-man' => ['man'], + 'application/x-tzo' => ['tar.lzo', 'tzo'], + 'application/x-ufraw' => ['ufraw'], + 'application/x-ustar' => ['ustar'], + 'application/x-vdi-disk' => ['vdi'], + 'application/x-vhd-disk' => ['vhd', 'vpc'], + 'application/x-vhdx-disk' => ['vhdx'], + 'application/x-virtual-boy-rom' => ['vb'], + 'application/x-virtualbox-hdd' => ['hdd'], + 'application/x-virtualbox-ova' => ['ova'], + 'application/x-virtualbox-ovf' => ['ovf'], + 'application/x-virtualbox-vbox' => ['vbox'], + 'application/x-virtualbox-vbox-extpack' => ['vbox-extpack'], + 'application/x-virtualbox-vdi' => ['vdi'], + 'application/x-virtualbox-vhd' => ['vhd', 'vpc'], + 'application/x-virtualbox-vhdx' => ['vhdx'], + 'application/x-virtualbox-vmdk' => ['vmdk'], + 'application/x-vmdk-disk' => ['vmdk'], + 'application/x-vnd.kde.kexi' => ['kexi'], + 'application/x-wais-source' => ['src'], + 'application/x-wbfs' => ['iso'], + 'application/x-web-app-manifest+json' => ['webapp'], + 'application/x-wia' => ['iso'], + 'application/x-wii-iso-image' => ['iso'], + 'application/x-wii-rom' => ['iso'], + 'application/x-wii-wad' => ['wad'], + 'application/x-win-lnk' => ['lnk'], + 'application/x-windows-themepack' => ['themepack'], + 'application/x-wmf' => ['wmf'], + 'application/x-wonderswan-color-rom' => ['wsc'], + 'application/x-wonderswan-rom' => ['ws'], + 'application/x-wordperfect' => ['wp', 'wp4', 'wp5', 'wp6', 'wpd', 'wpp'], + 'application/x-wpg' => ['wpg'], + 'application/x-wwf' => ['wwf'], + 'application/x-x509-ca-cert' => ['der', 'crt', 'pem', 'cert'], + 'application/x-xar' => ['xar', 'pkg'], + 'application/x-xbel' => ['xbel'], + 'application/x-xfig' => ['fig'], + 'application/x-xliff' => ['xlf', 'xliff'], + 'application/x-xliff+xml' => ['xlf'], + 'application/x-xpinstall' => ['xpi'], + 'application/x-xspf+xml' => ['xspf'], + 'application/x-xz' => ['xz'], + 'application/x-xz-compressed-tar' => ['tar.xz', 'txz'], + 'application/x-xzpdf' => ['pdf.xz'], + 'application/x-yaml' => ['yaml', 'yml'], + 'application/x-zip' => ['zip', 'zipx'], + 'application/x-zip-compressed' => ['zip', 'zipx'], + 'application/x-zip-compressed-fb2' => ['fb2.zip'], + 'application/x-zmachine' => ['z1', 'z2', 'z3', 'z4', 'z5', 'z6', 'z7', 'z8'], + 'application/x-zoo' => ['zoo'], + 'application/x-zpaq' => ['zpaq'], + 'application/x-zstd-compressed-tar' => ['tar.zst', 'tzst'], + 'application/xaml+xml' => ['xaml'], + 'application/xcap-att+xml' => ['xav'], + 'application/xcap-caps+xml' => ['xca'], + 'application/xcap-diff+xml' => ['xdf'], + 'application/xcap-el+xml' => ['xel'], + 'application/xcap-error+xml' => ['xer'], + 'application/xcap-ns+xml' => ['xns'], + 'application/xenc+xml' => ['xenc'], + 'application/xhtml+xml' => ['xhtml', 'xht', 'html', 'htm'], + 'application/xliff+xml' => ['xlf', 'xliff'], + 'application/xml' => ['xml', 'xsl', 'xsd', 'rng', 'xbl'], + 'application/xml-dtd' => ['dtd'], + 'application/xml-external-parsed-entity' => ['ent'], + 'application/xop+xml' => ['xop'], + 'application/xproc+xml' => ['xpl'], + 'application/xps' => ['xps'], + 'application/xslt+xml' => ['xsl', 'xslt'], + 'application/xspf+xml' => ['xspf'], + 'application/xv+xml' => ['mxml', 'xhvml', 'xvml', 'xvm'], + 'application/yaml' => ['yaml', 'yml'], + 'application/yang' => ['yang'], + 'application/yin+xml' => ['yin'], + 'application/zip' => ['zip', 'zipx'], + 'application/zlib' => ['zz'], + 'application/zstd' => ['zst'], + 'audio/3gpp' => ['3gpp', '3gp', '3ga'], + 'audio/3gpp-encrypted' => ['3gp', '3gpp', '3ga'], + 'audio/3gpp2' => ['3g2', '3gp2', '3gpp2'], + 'audio/aac' => ['aac', 'adts', 'ass'], + 'audio/ac3' => ['ac3'], + 'audio/adpcm' => ['adp'], + 'audio/amr' => ['amr'], + 'audio/amr-encrypted' => ['amr'], + 'audio/amr-wb' => ['awb'], + 'audio/amr-wb-encrypted' => ['awb'], + 'audio/annodex' => ['axa'], + 'audio/basic' => ['au', 'snd'], + 'audio/dff' => ['dff'], + 'audio/dsd' => ['dsf'], + 'audio/dsf' => ['dsf'], + 'audio/flac' => ['flac'], + 'audio/imelody' => ['imy', 'ime'], + 'audio/m3u' => ['m3u', 'm3u8', 'vlc'], + 'audio/m4a' => ['m4a', 'f4a'], + 'audio/midi' => ['mid', 'midi', 'kar', 'rmi'], + 'audio/mobile-xmf' => ['mxmf'], + 'audio/mp2' => ['mp2'], + 'audio/mp3' => ['mp3', 'mpga'], + 'audio/mp4' => ['m4a', 'mp4a', 'f4a'], + 'audio/mpeg' => ['mp3', 'mpga', 'mp2', 'mp2a', 'm2a', 'm3a'], + 'audio/mpegurl' => ['m3u', 'm3u8', 'vlc'], + 'audio/ogg' => ['ogg', 'oga', 'spx', 'opus'], + 'audio/prs.sid' => ['sid', 'psid'], + 'audio/s3m' => ['s3m'], + 'audio/scpls' => ['pls'], + 'audio/silk' => ['sil'], + 'audio/tta' => ['tta'], + 'audio/usac' => ['loas', 'xhe'], + 'audio/vnd.audible' => ['aa', 'aax'], + 'audio/vnd.audible.aax' => ['aax'], + 'audio/vnd.audible.aaxc' => ['aaxc'], + 'audio/vnd.dece.audio' => ['uva', 'uvva'], + 'audio/vnd.digital-winds' => ['eol'], + 'audio/vnd.dra' => ['dra'], + 'audio/vnd.dts' => ['dts'], + 'audio/vnd.dts.hd' => ['dtshd'], + 'audio/vnd.lucent.voice' => ['lvp'], + 'audio/vnd.m-realaudio' => ['ra', 'rax'], + 'audio/vnd.ms-playready.media.pya' => ['pya'], + 'audio/vnd.nokia.mobile-xmf' => ['mxmf'], + 'audio/vnd.nuera.ecelp4800' => ['ecelp4800'], + 'audio/vnd.nuera.ecelp7470' => ['ecelp7470'], + 'audio/vnd.nuera.ecelp9600' => ['ecelp9600'], + 'audio/vnd.rip' => ['rip'], + 'audio/vnd.rn-realaudio' => ['ra', 'rax'], + 'audio/vnd.wave' => ['wav'], + 'audio/vorbis' => ['oga', 'ogg'], + 'audio/wav' => ['wav'], + 'audio/wave' => ['wav'], + 'audio/webm' => ['weba'], + 'audio/wma' => ['wma'], + 'audio/x-aac' => ['aac', 'adts', 'ass'], + 'audio/x-aifc' => ['aifc', 'aiffc'], + 'audio/x-aiff' => ['aif', 'aiff', 'aifc'], + 'audio/x-aiffc' => ['aifc', 'aiffc'], + 'audio/x-amzxml' => ['amz'], + 'audio/x-annodex' => ['axa'], + 'audio/x-ape' => ['ape'], + 'audio/x-caf' => ['caf'], + 'audio/x-dff' => ['dff'], + 'audio/x-dsd' => ['dsf'], + 'audio/x-dsf' => ['dsf'], + 'audio/x-dts' => ['dts'], + 'audio/x-dtshd' => ['dtshd'], + 'audio/x-flac' => ['flac'], + 'audio/x-flac+ogg' => ['oga', 'ogg'], + 'audio/x-gsm' => ['gsm'], + 'audio/x-hx-aac-adts' => ['aac', 'adts', 'ass'], + 'audio/x-imelody' => ['imy', 'ime'], + 'audio/x-iriver-pla' => ['pla'], + 'audio/x-it' => ['it'], + 'audio/x-m3u' => ['m3u', 'm3u8', 'vlc'], + 'audio/x-m4a' => ['m4a', 'f4a'], + 'audio/x-m4b' => ['m4b', 'f4b'], + 'audio/x-m4r' => ['m4r'], + 'audio/x-matroska' => ['mka'], + 'audio/x-midi' => ['mid', 'midi', 'kar'], + 'audio/x-minipsf' => ['minipsf'], + 'audio/x-mo3' => ['mo3'], + 'audio/x-mod' => ['mod', 'ult', 'uni', 'm15', 'mtm', '669', 'med'], + 'audio/x-mp2' => ['mp2'], + 'audio/x-mp3' => ['mp3', 'mpga'], + 'audio/x-mp3-playlist' => ['m3u', 'm3u8', 'vlc'], + 'audio/x-mpeg' => ['mp3', 'mpga'], + 'audio/x-mpegurl' => ['m3u', 'm3u8', 'vlc'], + 'audio/x-mpg' => ['mp3', 'mpga'], + 'audio/x-ms-asx' => ['asx', 'wax', 'wvx', 'wmx'], + 'audio/x-ms-wax' => ['wax'], + 'audio/x-ms-wma' => ['wma'], + 'audio/x-ms-wmv' => ['wmv'], + 'audio/x-musepack' => ['mpc', 'mpp', 'mp+'], + 'audio/x-ogg' => ['oga', 'ogg', 'opus'], + 'audio/x-oggflac' => ['oga', 'ogg'], + 'audio/x-opus+ogg' => ['opus'], + 'audio/x-pn-audibleaudio' => ['aa', 'aax'], + 'audio/x-pn-realaudio' => ['ram', 'ra', 'rax'], + 'audio/x-pn-realaudio-plugin' => ['rmp'], + 'audio/x-psf' => ['psf'], + 'audio/x-psflib' => ['psflib'], + 'audio/x-realaudio' => ['ra'], + 'audio/x-rn-3gpp-amr' => ['3gp', '3gpp', '3ga'], + 'audio/x-rn-3gpp-amr-encrypted' => ['3gp', '3gpp', '3ga'], + 'audio/x-rn-3gpp-amr-wb' => ['3gp', '3gpp', '3ga'], + 'audio/x-rn-3gpp-amr-wb-encrypted' => ['3gp', '3gpp', '3ga'], + 'audio/x-s3m' => ['s3m'], + 'audio/x-scpls' => ['pls'], + 'audio/x-shorten' => ['shn'], + 'audio/x-speex' => ['spx'], + 'audio/x-speex+ogg' => ['oga', 'ogg', 'spx'], + 'audio/x-stm' => ['stm'], + 'audio/x-tak' => ['tak'], + 'audio/x-tta' => ['tta'], + 'audio/x-voc' => ['voc'], + 'audio/x-vorbis' => ['oga', 'ogg'], + 'audio/x-vorbis+ogg' => ['oga', 'ogg'], + 'audio/x-wav' => ['wav'], + 'audio/x-wavpack' => ['wv', 'wvp'], + 'audio/x-wavpack-correction' => ['wvc'], + 'audio/x-xi' => ['xi'], + 'audio/x-xm' => ['xm'], + 'audio/x-xmf' => ['xmf'], + 'audio/xm' => ['xm'], + 'audio/xmf' => ['xmf'], + 'chemical/x-cdx' => ['cdx'], + 'chemical/x-cif' => ['cif'], + 'chemical/x-cmdf' => ['cmdf'], + 'chemical/x-cml' => ['cml'], + 'chemical/x-csml' => ['csml'], + 'chemical/x-pdb' => ['pdb', 'brk'], + 'chemical/x-xyz' => ['xyz'], + 'flv-application/octet-stream' => ['flv'], + 'font/collection' => ['ttc'], + 'font/otf' => ['otf'], + 'font/ttf' => ['ttf'], + 'font/woff' => ['woff'], + 'font/woff2' => ['woff2'], + 'image/aces' => ['exr'], + 'image/apng' => ['apng', 'png'], + 'image/astc' => ['astc'], + 'image/avci' => ['avci'], + 'image/avcs' => ['avcs'], + 'image/avif' => ['avif', 'avifs'], + 'image/avif-sequence' => ['avif', 'avifs'], + 'image/bmp' => ['bmp', 'dib'], + 'image/cdr' => ['cdr'], + 'image/cgm' => ['cgm'], + 'image/dicom-rle' => ['drle'], + 'image/emf' => ['emf'], + 'image/fax-g3' => ['g3'], + 'image/fits' => ['fits', 'fit', 'fts'], + 'image/g3fax' => ['g3'], + 'image/gif' => ['gif'], + 'image/heic' => ['heic', 'heif', 'hif'], + 'image/heic-sequence' => ['heics', 'heic', 'heif', 'hif'], + 'image/heif' => ['heif', 'heic', 'hif'], + 'image/heif-sequence' => ['heifs', 'heic', 'heif', 'hif'], + 'image/hej2k' => ['hej2'], + 'image/hsj2' => ['hsj2'], + 'image/ico' => ['ico'], + 'image/icon' => ['ico'], + 'image/ief' => ['ief'], + 'image/jls' => ['jls'], + 'image/jp2' => ['jp2', 'jpg2'], + 'image/jpeg' => ['jpg', 'jpeg', 'jpe', 'jfif'], + 'image/jpeg2000' => ['jp2', 'jpg2'], + 'image/jpeg2000-image' => ['jp2', 'jpg2'], + 'image/jph' => ['jph'], + 'image/jphc' => ['jhc'], + 'image/jpm' => ['jpm', 'jpgm'], + 'image/jpx' => ['jpx', 'jpf'], + 'image/jxl' => ['jxl'], + 'image/jxr' => ['jxr', 'hdp', 'wdp'], + 'image/jxra' => ['jxra'], + 'image/jxrs' => ['jxrs'], + 'image/jxs' => ['jxs'], + 'image/jxsc' => ['jxsc'], + 'image/jxsi' => ['jxsi'], + 'image/jxss' => ['jxss'], + 'image/ktx' => ['ktx'], + 'image/ktx2' => ['ktx2'], + 'image/openraster' => ['ora'], + 'image/pdf' => ['pdf'], + 'image/photoshop' => ['psd'], + 'image/pjpeg' => ['jpg', 'jpeg', 'jpe', 'jfif'], + 'image/png' => ['png'], + 'image/prs.btif' => ['btif'], + 'image/prs.pti' => ['pti'], + 'image/psd' => ['psd'], + 'image/qoi' => ['qoi'], + 'image/rle' => ['rle'], + 'image/sgi' => ['sgi'], + 'image/svg' => ['svg'], + 'image/svg+xml' => ['svg', 'svgz'], + 'image/svg+xml-compressed' => ['svgz', 'svg.gz'], + 'image/t38' => ['t38'], + 'image/targa' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'image/tga' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'image/tiff' => ['tif', 'tiff'], + 'image/tiff-fx' => ['tfx'], + 'image/vnd.adobe.photoshop' => ['psd'], + 'image/vnd.airzip.accelerator.azv' => ['azv'], + 'image/vnd.dece.graphic' => ['uvi', 'uvvi', 'uvg', 'uvvg'], + 'image/vnd.djvu' => ['djvu', 'djv'], + 'image/vnd.djvu+multipage' => ['djvu', 'djv'], + 'image/vnd.dvb.subtitle' => ['sub'], + 'image/vnd.dwg' => ['dwg'], + 'image/vnd.dxf' => ['dxf'], + 'image/vnd.fastbidsheet' => ['fbs'], + 'image/vnd.fpx' => ['fpx'], + 'image/vnd.fst' => ['fst'], + 'image/vnd.fujixerox.edmics-mmr' => ['mmr'], + 'image/vnd.fujixerox.edmics-rlc' => ['rlc'], + 'image/vnd.microsoft.icon' => ['ico'], + 'image/vnd.mozilla.apng' => ['apng', 'png'], + 'image/vnd.ms-dds' => ['dds'], + 'image/vnd.ms-modi' => ['mdi'], + 'image/vnd.ms-photo' => ['wdp', 'jxr', 'hdp'], + 'image/vnd.net-fpx' => ['npx'], + 'image/vnd.pco.b16' => ['b16'], + 'image/vnd.rn-realpix' => ['rp'], + 'image/vnd.tencent.tap' => ['tap'], + 'image/vnd.valve.source.texture' => ['vtf'], + 'image/vnd.wap.wbmp' => ['wbmp'], + 'image/vnd.xiff' => ['xif'], + 'image/vnd.zbrush.pcx' => ['pcx'], + 'image/webp' => ['webp'], + 'image/wmf' => ['wmf'], + 'image/x-3ds' => ['3ds'], + 'image/x-adobe-dng' => ['dng'], + 'image/x-applix-graphics' => ['ag'], + 'image/x-bmp' => ['bmp', 'dib'], + 'image/x-bzeps' => ['eps.bz2', 'epsi.bz2', 'epsf.bz2'], + 'image/x-canon-cr2' => ['cr2'], + 'image/x-canon-cr3' => ['cr3'], + 'image/x-canon-crw' => ['crw'], + 'image/x-cdr' => ['cdr'], + 'image/x-cmu-raster' => ['ras'], + 'image/x-cmx' => ['cmx'], + 'image/x-compressed-xcf' => ['xcf.gz', 'xcf.bz2'], + 'image/x-dds' => ['dds'], + 'image/x-djvu' => ['djvu', 'djv'], + 'image/x-emf' => ['emf'], + 'image/x-eps' => ['eps', 'epsi', 'epsf'], + 'image/x-exr' => ['exr'], + 'image/x-fits' => ['fits', 'fit', 'fts'], + 'image/x-freehand' => ['fh', 'fhc', 'fh4', 'fh5', 'fh7'], + 'image/x-fuji-raf' => ['raf'], + 'image/x-gimp-gbr' => ['gbr'], + 'image/x-gimp-gih' => ['gih'], + 'image/x-gimp-pat' => ['pat'], + 'image/x-gzeps' => ['eps.gz', 'epsi.gz', 'epsf.gz'], + 'image/x-icb' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'image/x-icns' => ['icns'], + 'image/x-ico' => ['ico'], + 'image/x-icon' => ['ico'], + 'image/x-iff' => ['iff', 'ilbm', 'lbm'], + 'image/x-ilbm' => ['iff', 'ilbm', 'lbm'], + 'image/x-jng' => ['jng'], + 'image/x-jp2-codestream' => ['j2c', 'j2k', 'jpc'], + 'image/x-jpeg2000-image' => ['jp2', 'jpg2'], + 'image/x-kodak-dcr' => ['dcr'], + 'image/x-kodak-k25' => ['k25'], + 'image/x-kodak-kdc' => ['kdc'], + 'image/x-lwo' => ['lwo', 'lwob'], + 'image/x-lws' => ['lws'], + 'image/x-macpaint' => ['pntg'], + 'image/x-minolta-mrw' => ['mrw'], + 'image/x-mrsid-image' => ['sid'], + 'image/x-ms-bmp' => ['bmp', 'dib'], + 'image/x-msod' => ['msod'], + 'image/x-nikon-nef' => ['nef'], + 'image/x-nikon-nrw' => ['nrw'], + 'image/x-olympus-orf' => ['orf'], + 'image/x-panasonic-raw' => ['raw'], + 'image/x-panasonic-raw2' => ['rw2'], + 'image/x-panasonic-rw' => ['raw'], + 'image/x-panasonic-rw2' => ['rw2'], + 'image/x-pcx' => ['pcx'], + 'image/x-pentax-pef' => ['pef'], + 'image/x-photo-cd' => ['pcd'], + 'image/x-photoshop' => ['psd'], + 'image/x-pict' => ['pic', 'pct', 'pict', 'pict1', 'pict2'], + 'image/x-portable-anymap' => ['pnm'], + 'image/x-portable-bitmap' => ['pbm'], + 'image/x-portable-graymap' => ['pgm'], + 'image/x-portable-pixmap' => ['ppm'], + 'image/x-psd' => ['psd'], + 'image/x-quicktime' => ['qtif', 'qif'], + 'image/x-rgb' => ['rgb'], + 'image/x-sgi' => ['sgi'], + 'image/x-sigma-x3f' => ['x3f'], + 'image/x-skencil' => ['sk', 'sk1'], + 'image/x-sony-arw' => ['arw'], + 'image/x-sony-sr2' => ['sr2'], + 'image/x-sony-srf' => ['srf'], + 'image/x-sun-raster' => ['sun'], + 'image/x-targa' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'image/x-tga' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'image/x-win-bitmap' => ['cur'], + 'image/x-win-metafile' => ['wmf'], + 'image/x-wmf' => ['wmf'], + 'image/x-xbitmap' => ['xbm'], + 'image/x-xcf' => ['xcf'], + 'image/x-xfig' => ['fig'], + 'image/x-xpixmap' => ['xpm'], + 'image/x-xpm' => ['xpm'], + 'image/x-xwindowdump' => ['xwd'], + 'image/x.djvu' => ['djvu', 'djv'], + 'message/disposition-notification' => ['disposition-notification'], + 'message/global' => ['u8msg'], + 'message/global-delivery-status' => ['u8dsn'], + 'message/global-disposition-notification' => ['u8mdn'], + 'message/global-headers' => ['u8hdr'], + 'message/rfc822' => ['eml', 'mime'], + 'message/vnd.wfa.wsc' => ['wsc'], + 'model/3mf' => ['3mf'], + 'model/gltf+json' => ['gltf'], + 'model/gltf-binary' => ['glb'], + 'model/iges' => ['igs', 'iges'], + 'model/mesh' => ['msh', 'mesh', 'silo'], + 'model/mtl' => ['mtl'], + 'model/obj' => ['obj'], + 'model/step+xml' => ['stpx'], + 'model/step+zip' => ['stpz'], + 'model/step-xml+zip' => ['stpxz'], + 'model/stl' => ['stl'], + 'model/vnd.collada+xml' => ['dae'], + 'model/vnd.dwf' => ['dwf'], + 'model/vnd.gdl' => ['gdl'], + 'model/vnd.gtw' => ['gtw'], + 'model/vnd.mts' => ['mts'], + 'model/vnd.opengex' => ['ogex'], + 'model/vnd.parasolid.transmit.binary' => ['x_b'], + 'model/vnd.parasolid.transmit.text' => ['x_t'], + 'model/vnd.sap.vds' => ['vds'], + 'model/vnd.usdz+zip' => ['usdz'], + 'model/vnd.valve.source.compiled-map' => ['bsp'], + 'model/vnd.vtu' => ['vtu'], + 'model/vrml' => ['wrl', 'vrml', 'vrm'], + 'model/x.stl-ascii' => ['stl'], + 'model/x.stl-binary' => ['stl'], + 'model/x3d+binary' => ['x3db', 'x3dbz'], + 'model/x3d+fastinfoset' => ['x3db'], + 'model/x3d+vrml' => ['x3dv', 'x3dvz'], + 'model/x3d+xml' => ['x3d', 'x3dz'], + 'model/x3d-vrml' => ['x3dv'], + 'text/cache-manifest' => ['appcache', 'manifest'], + 'text/calendar' => ['ics', 'ifb', 'vcs'], + 'text/coffeescript' => ['coffee', 'litcoffee'], + 'text/crystal' => ['cr'], + 'text/css' => ['css'], + 'text/csv' => ['csv'], + 'text/csv-schema' => ['csvs'], + 'text/directory' => ['vcard', 'vcf', 'vct', 'gcrd'], + 'text/ecmascript' => ['es'], + 'text/gedcom' => ['ged', 'gedcom'], + 'text/google-video-pointer' => ['gvp'], + 'text/html' => ['html', 'htm', 'shtml'], + 'text/ico' => ['ico'], + 'text/jade' => ['jade'], + 'text/javascript' => ['js', 'jsm', 'mjs'], + 'text/jscript' => ['js', 'jsm', 'mjs'], + 'text/jscript.encode' => ['jse'], + 'text/jsx' => ['jsx'], + 'text/julia' => ['jl'], + 'text/less' => ['less'], + 'text/markdown' => ['md', 'markdown', 'mkd'], + 'text/mathml' => ['mml'], + 'text/mdx' => ['mdx'], + 'text/n3' => ['n3'], + 'text/org' => ['org'], + 'text/plain' => ['txt', 'text', 'conf', 'def', 'list', 'log', 'in', 'ini', 'asc'], + 'text/prs.lines.tag' => ['dsc'], + 'text/rdf' => ['rdf', 'rdfs', 'owl'], + 'text/richtext' => ['rtx'], + 'text/rss' => ['rss'], + 'text/rtf' => ['rtf'], + 'text/rust' => ['rs'], + 'text/sgml' => ['sgml', 'sgm'], + 'text/shex' => ['shex'], + 'text/slim' => ['slim', 'slm'], + 'text/spdx' => ['spdx'], + 'text/spreadsheet' => ['sylk', 'slk'], + 'text/stylus' => ['stylus', 'styl'], + 'text/tab-separated-values' => ['tsv'], + 'text/tcl' => ['tcl', 'tk'], + 'text/troff' => ['t', 'tr', 'roff', 'man', 'me', 'ms'], + 'text/turtle' => ['ttl'], + 'text/uri-list' => ['uri', 'uris', 'urls'], + 'text/vbs' => ['vbs'], + 'text/vbscript' => ['vbs'], + 'text/vbscript.encode' => ['vbe'], + 'text/vcard' => ['vcard', 'vcf', 'vct', 'gcrd'], + 'text/vnd.curl' => ['curl'], + 'text/vnd.curl.dcurl' => ['dcurl'], + 'text/vnd.curl.mcurl' => ['mcurl'], + 'text/vnd.curl.scurl' => ['scurl'], + 'text/vnd.dvb.subtitle' => ['sub'], + 'text/vnd.familysearch.gedcom' => ['ged', 'gedcom'], + 'text/vnd.fly' => ['fly'], + 'text/vnd.fmi.flexstor' => ['flx'], + 'text/vnd.graphviz' => ['gv', 'dot'], + 'text/vnd.in3d.3dml' => ['3dml'], + 'text/vnd.in3d.spot' => ['spot'], + 'text/vnd.qt.linguist' => ['ts'], + 'text/vnd.rn-realtext' => ['rt'], + 'text/vnd.senx.warpscript' => ['mc2'], + 'text/vnd.sun.j2me.app-descriptor' => ['jad'], + 'text/vnd.trolltech.linguist' => ['ts'], + 'text/vnd.wap.wml' => ['wml'], + 'text/vnd.wap.wmlscript' => ['wmls'], + 'text/vtt' => ['vtt'], + 'text/x-adasrc' => ['adb', 'ads'], + 'text/x-asm' => ['s', 'asm'], + 'text/x-basic' => ['bas'], + 'text/x-bibtex' => ['bib'], + 'text/x-blueprint' => ['blp'], + 'text/x-c' => ['c', 'cc', 'cxx', 'cpp', 'h', 'hh', 'dic'], + 'text/x-c++hdr' => ['hh', 'hp', 'hpp', 'h++', 'hxx'], + 'text/x-c++src' => ['cpp', 'cxx', 'cc', 'C', 'c++'], + 'text/x-chdr' => ['h'], + 'text/x-cmake' => ['cmake'], + 'text/x-cobol' => ['cbl', 'cob'], + 'text/x-comma-separated-values' => ['csv'], + 'text/x-common-lisp' => ['asd', 'fasl', 'lisp', 'ros'], + 'text/x-component' => ['htc'], + 'text/x-crystal' => ['cr'], + 'text/x-csharp' => ['cs'], + 'text/x-csrc' => ['c'], + 'text/x-csv' => ['csv'], + 'text/x-dart' => ['dart'], + 'text/x-dbus-service' => ['service'], + 'text/x-dcl' => ['dcl'], + 'text/x-devicetree-binary' => ['dtb'], + 'text/x-devicetree-source' => ['dts', 'dtsi'], + 'text/x-diff' => ['diff', 'patch'], + 'text/x-dsl' => ['dsl'], + 'text/x-dsrc' => ['d', 'di'], + 'text/x-dtd' => ['dtd'], + 'text/x-eiffel' => ['e', 'eif'], + 'text/x-elixir' => ['ex', 'exs'], + 'text/x-emacs-lisp' => ['el'], + 'text/x-erlang' => ['erl'], + 'text/x-fish' => ['fish'], + 'text/x-fortran' => ['f', 'for', 'f77', 'f90', 'f95'], + 'text/x-gcode-gx' => ['gx'], + 'text/x-genie' => ['gs'], + 'text/x-gettext-translation' => ['po'], + 'text/x-gettext-translation-template' => ['pot'], + 'text/x-gherkin' => ['feature'], + 'text/x-go' => ['go'], + 'text/x-google-video-pointer' => ['gvp'], + 'text/x-gradle' => ['gradle'], + 'text/x-groovy' => ['groovy', 'gvy', 'gy', 'gsh'], + 'text/x-handlebars-template' => ['hbs'], + 'text/x-haskell' => ['hs'], + 'text/x-idl' => ['idl'], + 'text/x-imelody' => ['imy', 'ime'], + 'text/x-iptables' => ['iptables'], + 'text/x-java' => ['java'], + 'text/x-java-source' => ['java'], + 'text/x-kaitai-struct' => ['ksy'], + 'text/x-kotlin' => ['kt'], + 'text/x-ldif' => ['ldif'], + 'text/x-lilypond' => ['ly'], + 'text/x-literate-haskell' => ['lhs'], + 'text/x-log' => ['log'], + 'text/x-lua' => ['lua'], + 'text/x-lyx' => ['lyx'], + 'text/x-makefile' => ['mk', 'mak'], + 'text/x-markdown' => ['md', 'mkd', 'markdown'], + 'text/x-matlab' => ['m'], + 'text/x-microdvd' => ['sub'], + 'text/x-moc' => ['moc'], + 'text/x-modelica' => ['mo'], + 'text/x-mof' => ['mof'], + 'text/x-mpl2' => ['mpl'], + 'text/x-mpsub' => ['sub'], + 'text/x-mrml' => ['mrml', 'mrl'], + 'text/x-ms-regedit' => ['reg'], + 'text/x-mup' => ['mup', 'not'], + 'text/x-nfo' => ['nfo'], + 'text/x-nim' => ['nim'], + 'text/x-nimscript' => ['nims', 'nimble'], + 'text/x-nu' => ['nu'], + 'text/x-objc++src' => ['mm'], + 'text/x-objcsrc' => ['m'], + 'text/x-ocaml' => ['ml', 'mli'], + 'text/x-ocl' => ['ocl'], + 'text/x-octave' => ['m'], + 'text/x-ooc' => ['ooc'], + 'text/x-opencl-src' => ['cl'], + 'text/x-opml' => ['opml'], + 'text/x-opml+xml' => ['opml'], + 'text/x-org' => ['org'], + 'text/x-pascal' => ['p', 'pas'], + 'text/x-patch' => ['diff', 'patch'], + 'text/x-perl' => ['pl', 'PL', 'pm', 'al', 'perl', 'pod', 't'], + 'text/x-po' => ['po'], + 'text/x-pot' => ['pot'], + 'text/x-processing' => ['pde'], + 'text/x-python' => ['py', 'pyx', 'wsgi'], + 'text/x-python3' => ['py', 'py3', 'py3x', 'pyi'], + 'text/x-qml' => ['qml', 'qmltypes', 'qmlproject'], + 'text/x-reject' => ['rej'], + 'text/x-rpm-spec' => ['spec'], + 'text/x-rst' => ['rst'], + 'text/x-sagemath' => ['sage'], + 'text/x-sass' => ['sass'], + 'text/x-scala' => ['scala', 'sc'], + 'text/x-scheme' => ['scm', 'ss'], + 'text/x-scss' => ['scss'], + 'text/x-setext' => ['etx'], + 'text/x-sfv' => ['sfv'], + 'text/x-sh' => ['sh'], + 'text/x-sql' => ['sql'], + 'text/x-ssa' => ['ssa', 'ass'], + 'text/x-subviewer' => ['sub'], + 'text/x-suse-ymp' => ['ymp'], + 'text/x-svhdr' => ['svh'], + 'text/x-svsrc' => ['sv'], + 'text/x-systemd-unit' => ['automount', 'device', 'mount', 'path', 'scope', 'service', 'slice', 'socket', 'swap', 'target', 'timer'], + 'text/x-tcl' => ['tcl', 'tk'], + 'text/x-tex' => ['tex', 'ltx', 'sty', 'cls', 'dtx', 'ins', 'latex'], + 'text/x-texinfo' => ['texi', 'texinfo'], + 'text/x-troff' => ['tr', 'roff', 't'], + 'text/x-troff-me' => ['me'], + 'text/x-troff-mm' => ['mm'], + 'text/x-troff-ms' => ['ms'], + 'text/x-twig' => ['twig'], + 'text/x-txt2tags' => ['t2t'], + 'text/x-typst' => ['typ'], + 'text/x-uil' => ['uil'], + 'text/x-uuencode' => ['uu', 'uue'], + 'text/x-vala' => ['vala', 'vapi'], + 'text/x-vb' => ['vb'], + 'text/x-vcalendar' => ['vcs', 'ics'], + 'text/x-vcard' => ['vcf', 'vcard', 'vct', 'gcrd'], + 'text/x-verilog' => ['v'], + 'text/x-vhdl' => ['vhd', 'vhdl'], + 'text/x-xmi' => ['xmi'], + 'text/x-xslfo' => ['fo', 'xslfo'], + 'text/x-yaml' => ['yaml', 'yml'], + 'text/x.gcode' => ['gcode'], + 'text/xml' => ['xml', 'xbl', 'xsd', 'rng'], + 'text/xml-external-parsed-entity' => ['ent'], + 'text/yaml' => ['yaml', 'yml'], + 'video/3gp' => ['3gp', '3gpp', '3ga'], + 'video/3gpp' => ['3gp', '3gpp', '3ga'], + 'video/3gpp-encrypted' => ['3gp', '3gpp', '3ga'], + 'video/3gpp2' => ['3g2', '3gp2', '3gpp2'], + 'video/annodex' => ['axv'], + 'video/avi' => ['avi', 'avf', 'divx'], + 'video/divx' => ['avi', 'avf', 'divx'], + 'video/dv' => ['dv'], + 'video/fli' => ['fli', 'flc'], + 'video/flv' => ['flv'], + 'video/h261' => ['h261'], + 'video/h263' => ['h263'], + 'video/h264' => ['h264'], + 'video/iso.segment' => ['m4s'], + 'video/jpeg' => ['jpgv'], + 'video/jpm' => ['jpm', 'jpgm'], + 'video/mj2' => ['mj2', 'mjp2'], + 'video/mp2t' => ['ts', 'm2t', 'm2ts', 'mts', 'cpi', 'clpi', 'mpl', 'mpls', 'bdm', 'bdmv'], + 'video/mp4' => ['mp4', 'mp4v', 'mpg4', 'm4v', 'f4v', 'lrv'], + 'video/mp4v-es' => ['mp4', 'm4v', 'f4v', 'lrv'], + 'video/mpeg' => ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v', 'mp2', 'vob'], + 'video/mpeg-system' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], + 'video/msvideo' => ['avi', 'avf', 'divx'], + 'video/ogg' => ['ogv', 'ogg'], + 'video/quicktime' => ['mov', 'qt', 'moov', 'qtvr'], + 'video/vivo' => ['viv', 'vivo'], + 'video/vnd.avi' => ['avi', 'avf', 'divx'], + 'video/vnd.dece.hd' => ['uvh', 'uvvh'], + 'video/vnd.dece.mobile' => ['uvm', 'uvvm'], + 'video/vnd.dece.pd' => ['uvp', 'uvvp'], + 'video/vnd.dece.sd' => ['uvs', 'uvvs'], + 'video/vnd.dece.video' => ['uvv', 'uvvv'], + 'video/vnd.divx' => ['avi', 'avf', 'divx'], + 'video/vnd.dvb.file' => ['dvb'], + 'video/vnd.fvt' => ['fvt'], + 'video/vnd.mpegurl' => ['mxu', 'm4u', 'm1u'], + 'video/vnd.ms-playready.media.pyv' => ['pyv'], + 'video/vnd.radgamettools.bink' => ['bik', 'bk2'], + 'video/vnd.radgamettools.smacker' => ['smk'], + 'video/vnd.rn-realvideo' => ['rv', 'rvx'], + 'video/vnd.uvvu.mp4' => ['uvu', 'uvvu'], + 'video/vnd.vivo' => ['viv', 'vivo'], + 'video/vnd.youtube.yt' => ['yt'], + 'video/webm' => ['webm'], + 'video/x-anim' => ['anim1', 'anim2', 'anim3', 'anim4', 'anim5', 'anim6', 'anim7', 'anim8', 'anim9', 'animj'], + 'video/x-annodex' => ['axv'], + 'video/x-avi' => ['avi', 'avf', 'divx'], + 'video/x-f4v' => ['f4v'], + 'video/x-fli' => ['fli', 'flc'], + 'video/x-flic' => ['fli', 'flc'], + 'video/x-flv' => ['flv'], + 'video/x-javafx' => ['fxm'], + 'video/x-m4v' => ['m4v', 'mp4', 'f4v', 'lrv'], + 'video/x-matroska' => ['mkv', 'mk3d', 'mks'], + 'video/x-matroska-3d' => ['mk3d'], + 'video/x-mjpeg' => ['mjpeg', 'mjpg'], + 'video/x-mng' => ['mng'], + 'video/x-mpeg' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], + 'video/x-mpeg-system' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], + 'video/x-mpeg2' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], + 'video/x-mpegurl' => ['m1u', 'm4u', 'mxu'], + 'video/x-ms-asf' => ['asf', 'asx'], + 'video/x-ms-asf-plugin' => ['asf'], + 'video/x-ms-vob' => ['vob'], + 'video/x-ms-wax' => ['asx', 'wax', 'wvx', 'wmx'], + 'video/x-ms-wm' => ['wm', 'asf'], + 'video/x-ms-wmv' => ['wmv'], + 'video/x-ms-wmx' => ['wmx', 'asx', 'wax', 'wvx'], + 'video/x-ms-wvx' => ['wvx', 'asx', 'wax', 'wmx'], + 'video/x-msvideo' => ['avi', 'avf', 'divx'], + 'video/x-nsv' => ['nsv'], + 'video/x-ogg' => ['ogv', 'ogg'], + 'video/x-ogm' => ['ogm'], + 'video/x-ogm+ogg' => ['ogm'], + 'video/x-real-video' => ['rv', 'rvx'], + 'video/x-sgi-movie' => ['movie'], + 'video/x-smv' => ['smv'], + 'video/x-theora' => ['ogg'], + 'video/x-theora+ogg' => ['ogg'], + 'x-conference/x-cooltalk' => ['ice'], + 'x-epoc/x-sisx-app' => ['sisx'], + 'zz-application/zz-winassoc-123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'zz-application/zz-winassoc-cab' => ['cab'], + 'zz-application/zz-winassoc-cdr' => ['cdr'], + 'zz-application/zz-winassoc-doc' => ['doc'], + 'zz-application/zz-winassoc-hlp' => ['hlp'], + 'zz-application/zz-winassoc-mdb' => ['mdb'], + 'zz-application/zz-winassoc-uu' => ['uue'], + 'zz-application/zz-winassoc-xls' => ['xls', 'xlc', 'xll', 'xlm', 'xlw', 'xla', 'xlt', 'xld'], + ]; + + private const REVERSE_MAP = [ + '123' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + '1km' => ['application/vnd.1000minds.decision-model+xml'], + '32x' => ['application/x-genesis-32x-rom'], + '3dml' => ['text/vnd.in3d.3dml'], + '3ds' => ['application/x-nintendo-3ds-rom', 'image/x-3ds'], + '3dsx' => ['application/x-nintendo-3ds-executable'], + '3g2' => ['audio/3gpp2', 'video/3gpp2'], + '3ga' => ['audio/3gpp', 'audio/3gpp-encrypted', 'audio/x-rn-3gpp-amr', 'audio/x-rn-3gpp-amr-encrypted', 'audio/x-rn-3gpp-amr-wb', 'audio/x-rn-3gpp-amr-wb-encrypted', 'video/3gp', 'video/3gpp', 'video/3gpp-encrypted'], + '3gp' => ['audio/3gpp', 'audio/3gpp-encrypted', 'audio/x-rn-3gpp-amr', 'audio/x-rn-3gpp-amr-encrypted', 'audio/x-rn-3gpp-amr-wb', 'audio/x-rn-3gpp-amr-wb-encrypted', 'video/3gp', 'video/3gpp', 'video/3gpp-encrypted'], + '3gp2' => ['audio/3gpp2', 'video/3gpp2'], + '3gpp' => ['audio/3gpp', 'audio/3gpp-encrypted', 'audio/x-rn-3gpp-amr', 'audio/x-rn-3gpp-amr-encrypted', 'audio/x-rn-3gpp-amr-wb', 'audio/x-rn-3gpp-amr-wb-encrypted', 'video/3gp', 'video/3gpp', 'video/3gpp-encrypted'], + '3gpp2' => ['audio/3gpp2', 'video/3gpp2'], + '3mf' => ['application/vnd.ms-3mfdocument', 'model/3mf'], + '602' => ['application/x-t602'], + '669' => ['audio/x-mod'], + '7z' => ['application/x-7z-compressed'], + '7z.001' => ['application/x-7z-compressed'], + 'BLEND' => ['application/x-blender'], + 'C' => ['text/x-c++src'], + 'PAR2' => ['application/x-par2'], + 'PL' => ['application/x-perl', 'text/x-perl'], + 'Z' => ['application/x-compress'], + 'a' => ['application/x-archive'], + 'a26' => ['application/x-atari-2600-rom'], + 'a78' => ['application/x-atari-7800-rom'], + 'aa' => ['audio/vnd.audible', 'audio/x-pn-audibleaudio'], + 'aab' => ['application/x-authorware-bin'], + 'aac' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts'], + 'aam' => ['application/x-authorware-map'], + 'aas' => ['application/x-authorware-seg'], + 'aax' => ['audio/vnd.audible', 'audio/vnd.audible.aax', 'audio/x-pn-audibleaudio'], + 'aaxc' => ['audio/vnd.audible.aaxc'], + 'abw' => ['application/x-abiword'], + 'abw.CRASHED' => ['application/x-abiword'], + 'abw.gz' => ['application/x-abiword'], + 'ac' => ['application/pkix-attr-cert', 'application/vnd.nokia.n-gage.ac+xml'], + 'ac3' => ['audio/ac3'], + 'acc' => ['application/vnd.americandynamics.acc'], + 'ace' => ['application/x-ace', 'application/x-ace-compressed'], + 'acu' => ['application/vnd.acucobol'], + 'acutc' => ['application/vnd.acucorp'], + 'adb' => ['text/x-adasrc'], + 'adf' => ['application/x-amiga-disk-format'], + 'adp' => ['audio/adpcm'], + 'ads' => ['text/x-adasrc'], + 'adts' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts'], + 'aep' => ['application/vnd.audiograph'], + 'afm' => ['application/x-font-afm', 'application/x-font-type1'], + 'afp' => ['application/vnd.ibm.modcap'], + 'ag' => ['image/x-applix-graphics'], + 'agb' => ['application/x-gba-rom'], + 'age' => ['application/vnd.age'], + 'ahead' => ['application/vnd.ahead.space'], + 'ai' => ['application/illustrator', 'application/postscript', 'application/vnd.adobe.illustrator'], + 'aif' => ['audio/x-aiff'], + 'aifc' => ['audio/x-aifc', 'audio/x-aiff', 'audio/x-aiffc'], + 'aiff' => ['audio/x-aiff'], + 'aiffc' => ['audio/x-aifc', 'audio/x-aiffc'], + 'air' => ['application/vnd.adobe.air-application-installer-package+zip'], + 'ait' => ['application/vnd.dvb.ait'], + 'al' => ['application/x-perl', 'text/x-perl'], + 'alz' => ['application/x-alz'], + 'ami' => ['application/vnd.amiga.ami'], + 'amr' => ['audio/amr', 'audio/amr-encrypted'], + 'amz' => ['audio/x-amzxml'], + 'ani' => ['application/x-navi-animation'], + 'anim1' => ['video/x-anim'], + 'anim2' => ['video/x-anim'], + 'anim3' => ['video/x-anim'], + 'anim4' => ['video/x-anim'], + 'anim5' => ['video/x-anim'], + 'anim6' => ['video/x-anim'], + 'anim7' => ['video/x-anim'], + 'anim8' => ['video/x-anim'], + 'anim9' => ['video/x-anim'], + 'animj' => ['video/x-anim'], + 'anx' => ['application/annodex', 'application/x-annodex'], + 'ape' => ['audio/x-ape'], + 'apk' => ['application/vnd.android.package-archive'], + 'apng' => ['image/apng', 'image/vnd.mozilla.apng'], + 'appcache' => ['text/cache-manifest'], + 'appimage' => ['application/vnd.appimage', 'application/x-iso9660-appimage'], + 'appinstaller' => ['application/appinstaller'], + 'application' => ['application/x-ms-application'], + 'appx' => ['application/appx'], + 'appxbundle' => ['application/appxbundle'], + 'apr' => ['application/vnd.lotus-approach'], + 'ar' => ['application/x-archive'], + 'arc' => ['application/x-freearc'], + 'arj' => ['application/x-arj'], + 'arw' => ['image/x-sony-arw'], + 'as' => ['application/x-applix-spreadsheet'], + 'asar' => ['application/x-asar'], + 'asc' => ['application/pgp', 'application/pgp-encrypted', 'application/pgp-keys', 'application/pgp-signature', 'text/plain'], + 'asd' => ['text/x-common-lisp'], + 'asf' => ['application/vnd.ms-asf', 'video/x-ms-asf', 'video/x-ms-asf-plugin', 'video/x-ms-wm'], + 'asice' => ['application/vnd.etsi.asic-e+zip'], + 'asm' => ['text/x-asm'], + 'aso' => ['application/vnd.accpac.simply.aso'], + 'asp' => ['application/x-asp'], + 'ass' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts', 'text/x-ssa'], + 'astc' => ['image/astc'], + 'asx' => ['application/x-ms-asx', 'audio/x-ms-asx', 'video/x-ms-asf', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], + 'atc' => ['application/vnd.acucorp'], + 'atom' => ['application/atom+xml'], + 'atomcat' => ['application/atomcat+xml'], + 'atomdeleted' => ['application/atomdeleted+xml'], + 'atomsvc' => ['application/atomsvc+xml'], + 'atx' => ['application/vnd.antix.game-component'], + 'au' => ['audio/basic'], + 'automount' => ['text/x-systemd-unit'], + 'avci' => ['image/avci'], + 'avcs' => ['image/avcs'], + 'avf' => ['video/avi', 'video/divx', 'video/msvideo', 'video/vnd.avi', 'video/vnd.divx', 'video/x-avi', 'video/x-msvideo'], + 'avi' => ['video/avi', 'video/divx', 'video/msvideo', 'video/vnd.avi', 'video/vnd.divx', 'video/x-avi', 'video/x-msvideo'], + 'avif' => ['image/avif', 'image/avif-sequence'], + 'avifs' => ['image/avif', 'image/avif-sequence'], + 'aw' => ['application/applixware', 'application/x-applix-word'], + 'awb' => ['audio/amr-wb', 'audio/amr-wb-encrypted'], + 'awk' => ['application/x-awk'], + 'axa' => ['audio/annodex', 'audio/x-annodex'], + 'axv' => ['video/annodex', 'video/x-annodex'], + 'azf' => ['application/vnd.airzip.filesecure.azf'], + 'azs' => ['application/vnd.airzip.filesecure.azs'], + 'azv' => ['image/vnd.airzip.accelerator.azv'], + 'azw' => ['application/vnd.amazon.ebook'], + 'azw3' => ['application/vnd.amazon.mobi8-ebook', 'application/x-mobi8-ebook'], + 'b16' => ['image/vnd.pco.b16'], + 'bak' => ['application/x-trash'], + 'bas' => ['text/x-basic'], + 'bat' => ['application/bat', 'application/x-bat', 'application/x-msdownload'], + 'bcpio' => ['application/x-bcpio'], + 'bdf' => ['application/x-font-bdf'], + 'bdm' => ['application/vnd.syncml.dm+wbxml', 'video/mp2t'], + 'bdmv' => ['video/mp2t'], + 'bdoc' => ['application/bdoc', 'application/x-bdoc'], + 'bed' => ['application/vnd.realvnc.bed'], + 'bh2' => ['application/vnd.fujitsu.oasysprs'], + 'bib' => ['text/x-bibtex'], + 'bik' => ['video/vnd.radgamettools.bink'], + 'bin' => ['application/octet-stream'], + 'bk2' => ['video/vnd.radgamettools.bink'], + 'blb' => ['application/x-blorb'], + 'blend' => ['application/x-blender'], + 'blender' => ['application/x-blender'], + 'blorb' => ['application/x-blorb'], + 'blp' => ['text/x-blueprint'], + 'bmi' => ['application/vnd.bmi'], + 'bmml' => ['application/vnd.balsamiq.bmml+xml'], + 'bmp' => ['image/bmp', 'image/x-bmp', 'image/x-ms-bmp'], + 'book' => ['application/vnd.framemaker'], + 'box' => ['application/vnd.previewsystems.box'], + 'boz' => ['application/x-bzip2'], + 'bps' => ['application/x-bps-patch'], + 'brk' => ['chemical/x-pdb'], + 'bsdiff' => ['application/x-bsdiff'], + 'bsp' => ['model/vnd.valve.source.compiled-map'], + 'btif' => ['image/prs.btif'], + 'bz' => ['application/bzip2', 'application/x-bzip', 'application/x-bzip1'], + 'bz2' => ['application/x-bz2', 'application/bzip2', 'application/x-bzip', 'application/x-bzip2'], + 'bz3' => ['application/x-bzip3'], + 'c' => ['text/x-c', 'text/x-csrc'], + 'c++' => ['text/x-c++src'], + 'c11amc' => ['application/vnd.cluetrust.cartomobile-config'], + 'c11amz' => ['application/vnd.cluetrust.cartomobile-config-pkg'], + 'c4d' => ['application/vnd.clonk.c4group'], + 'c4f' => ['application/vnd.clonk.c4group'], + 'c4g' => ['application/vnd.clonk.c4group'], + 'c4p' => ['application/vnd.clonk.c4group'], + 'c4u' => ['application/vnd.clonk.c4group'], + 'cab' => ['application/vnd.ms-cab-compressed', 'zz-application/zz-winassoc-cab'], + 'caf' => ['audio/x-caf'], + 'cap' => ['application/pcap', 'application/vnd.tcpdump.pcap', 'application/x-pcap'], + 'car' => ['application/vnd.curl.car'], + 'cat' => ['application/vnd.ms-pki.seccat'], + 'cb7' => ['application/x-cb7', 'application/x-cbr'], + 'cba' => ['application/x-cbr'], + 'cbl' => ['text/x-cobol'], + 'cbor' => ['application/cbor'], + 'cbr' => ['application/vnd.comicbook-rar', 'application/x-cbr'], + 'cbt' => ['application/x-cbr', 'application/x-cbt'], + 'cbz' => ['application/vnd.comicbook+zip', 'application/x-cbr', 'application/x-cbz'], + 'cc' => ['text/x-c', 'text/x-c++src'], + 'cci' => ['application/x-nintendo-3ds-rom'], + 'ccmx' => ['application/x-ccmx'], + 'cco' => ['application/x-cocoa'], + 'cct' => ['application/x-director'], + 'ccxml' => ['application/ccxml+xml'], + 'cdbcmsg' => ['application/vnd.contact.cmsg'], + 'cdf' => ['application/x-netcdf'], + 'cdfx' => ['application/cdfx+xml'], + 'cdi' => ['application/x-discjuggler-cd-image'], + 'cdkey' => ['application/vnd.mediastation.cdkey'], + 'cdmia' => ['application/cdmi-capability'], + 'cdmic' => ['application/cdmi-container'], + 'cdmid' => ['application/cdmi-domain'], + 'cdmio' => ['application/cdmi-object'], + 'cdmiq' => ['application/cdmi-queue'], + 'cdr' => ['application/cdr', 'application/coreldraw', 'application/vnd.corel-draw', 'application/x-cdr', 'application/x-coreldraw', 'image/cdr', 'image/x-cdr', 'zz-application/zz-winassoc-cdr'], + 'cdx' => ['chemical/x-cdx'], + 'cdxml' => ['application/vnd.chemdraw+xml'], + 'cdy' => ['application/vnd.cinderella'], + 'cer' => ['application/pkix-cert'], + 'cert' => ['application/x-x509-ca-cert'], + 'cfs' => ['application/x-cfs-compressed'], + 'cgb' => ['application/x-gameboy-color-rom'], + 'cgm' => ['image/cgm'], + 'chat' => ['application/x-chat'], + 'chd' => ['application/x-mame-chd'], + 'chm' => ['application/vnd.ms-htmlhelp', 'application/x-chm'], + 'chrt' => ['application/vnd.kde.kchart', 'application/x-kchart'], + 'cif' => ['chemical/x-cif'], + 'cii' => ['application/vnd.anser-web-certificate-issue-initiation'], + 'cil' => ['application/vnd.ms-artgalry'], + 'cjs' => ['application/node'], + 'cl' => ['text/x-opencl-src'], + 'cla' => ['application/vnd.claymore'], + 'class' => ['application/java', 'application/java-byte-code', 'application/java-vm', 'application/x-java', 'application/x-java-class', 'application/x-java-vm'], + 'clkk' => ['application/vnd.crick.clicker.keyboard'], + 'clkp' => ['application/vnd.crick.clicker.palette'], + 'clkt' => ['application/vnd.crick.clicker.template'], + 'clkw' => ['application/vnd.crick.clicker.wordbank'], + 'clkx' => ['application/vnd.crick.clicker'], + 'clp' => ['application/x-msclip'], + 'clpi' => ['video/mp2t'], + 'cls' => ['application/x-tex', 'text/x-tex'], + 'cmake' => ['text/x-cmake'], + 'cmc' => ['application/vnd.cosmocaller'], + 'cmdf' => ['chemical/x-cmdf'], + 'cml' => ['chemical/x-cml'], + 'cmp' => ['application/vnd.yellowriver-custom-menu'], + 'cmx' => ['image/x-cmx'], + 'cob' => ['text/x-cobol'], + 'cod' => ['application/vnd.rim.cod'], + 'coffee' => ['application/vnd.coffeescript', 'text/coffeescript'], + 'com' => ['application/x-msdownload'], + 'conf' => ['text/plain'], + 'cpi' => ['video/mp2t'], + 'cpio' => ['application/x-cpio'], + 'cpio.gz' => ['application/x-cpio-compressed'], + 'cpl' => ['application/cpl+xml', 'application/vnd.microsoft.portable-executable', 'application/x-ms-dos-executable', 'application/x-ms-ne-executable', 'application/x-msdownload'], + 'cpp' => ['text/x-c', 'text/x-c++src'], + 'cpt' => ['application/mac-compactpro'], + 'cr' => ['text/crystal', 'text/x-crystal'], + 'cr2' => ['image/x-canon-cr2'], + 'cr3' => ['image/x-canon-cr3'], + 'crd' => ['application/x-mscardfile'], + 'crdownload' => ['application/x-partial-download'], + 'crl' => ['application/pkix-crl'], + 'crt' => ['application/x-x509-ca-cert'], + 'crw' => ['image/x-canon-crw'], + 'crx' => ['application/x-chrome-extension'], + 'cryptonote' => ['application/vnd.rig.cryptonote'], + 'cs' => ['text/x-csharp'], + 'csh' => ['application/x-csh'], + 'csl' => ['application/vnd.citationstyles.style+xml'], + 'csml' => ['chemical/x-csml'], + 'cso' => ['application/x-compressed-iso'], + 'csp' => ['application/vnd.commonspace'], + 'css' => ['text/css'], + 'cst' => ['application/x-director'], + 'csv' => ['text/csv', 'application/csv', 'text/x-comma-separated-values', 'text/x-csv'], + 'csvs' => ['text/csv-schema'], + 'cu' => ['application/cu-seeme'], + 'cue' => ['application/x-cue'], + 'cur' => ['image/x-win-bitmap'], + 'curl' => ['text/vnd.curl'], + 'cwk' => ['application/x-appleworks-document'], + 'cww' => ['application/prs.cww'], + 'cxt' => ['application/x-director'], + 'cxx' => ['text/x-c', 'text/x-c++src'], + 'd' => ['text/x-dsrc'], + 'dae' => ['model/vnd.collada+xml'], + 'daf' => ['application/vnd.mobius.daf'], + 'dar' => ['application/x-dar'], + 'dart' => ['application/vnd.dart', 'text/x-dart'], + 'dataless' => ['application/vnd.fdsn.seed'], + 'davmount' => ['application/davmount+xml'], + 'dbf' => ['application/dbase', 'application/dbf', 'application/vnd.dbf', 'application/x-dbase', 'application/x-dbf'], + 'dbk' => ['application/docbook+xml', 'application/vnd.oasis.docbook+xml', 'application/x-docbook+xml'], + 'dc' => ['application/x-dc-rom'], + 'dcl' => ['text/x-dcl'], + 'dcm' => ['application/dicom'], + 'dcr' => ['application/x-director', 'image/x-kodak-dcr'], + 'dcurl' => ['text/vnd.curl.dcurl'], + 'dd2' => ['application/vnd.oma.dd2+xml'], + 'ddd' => ['application/vnd.fujixerox.ddd'], + 'ddf' => ['application/vnd.syncml.dmddf+xml'], + 'dds' => ['image/vnd.ms-dds', 'image/x-dds'], + 'deb' => ['application/vnd.debian.binary-package', 'application/x-deb', 'application/x-debian-package'], + 'def' => ['text/plain'], + 'der' => ['application/x-x509-ca-cert'], + 'desktop' => ['application/x-desktop', 'application/x-gnome-app-info'], + 'device' => ['text/x-systemd-unit'], + 'dfac' => ['application/vnd.dreamfactory'], + 'dff' => ['audio/dff', 'audio/x-dff'], + 'dgc' => ['application/x-dgc-compressed'], + 'di' => ['text/x-dsrc'], + 'dia' => ['application/x-dia-diagram'], + 'dib' => ['image/bmp', 'image/x-bmp', 'image/x-ms-bmp'], + 'dic' => ['text/x-c'], + 'diff' => ['text/x-diff', 'text/x-patch'], + 'dir' => ['application/x-director'], + 'dis' => ['application/vnd.mobius.dis'], + 'disposition-notification' => ['message/disposition-notification'], + 'divx' => ['video/avi', 'video/divx', 'video/msvideo', 'video/vnd.avi', 'video/vnd.divx', 'video/x-avi', 'video/x-msvideo'], + 'djv' => ['image/vnd.djvu', 'image/vnd.djvu+multipage', 'image/x-djvu', 'image/x.djvu'], + 'djvu' => ['image/vnd.djvu', 'image/vnd.djvu+multipage', 'image/x-djvu', 'image/x.djvu'], + 'dll' => ['application/vnd.microsoft.portable-executable', 'application/x-ms-dos-executable', 'application/x-ms-ne-executable', 'application/x-msdownload'], + 'dmg' => ['application/x-apple-diskimage'], + 'dmp' => ['application/pcap', 'application/vnd.tcpdump.pcap', 'application/x-pcap'], + 'dna' => ['application/vnd.dna'], + 'dng' => ['image/x-adobe-dng'], + 'doc' => ['application/msword', 'application/vnd.ms-word', 'application/x-msword', 'zz-application/zz-winassoc-doc'], + 'docbook' => ['application/docbook+xml', 'application/vnd.oasis.docbook+xml', 'application/x-docbook+xml'], + 'docm' => ['application/vnd.ms-word.document.macroenabled.12'], + 'docx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'], + 'dot' => ['application/msword', 'application/msword-template', 'text/vnd.graphviz'], + 'dotm' => ['application/vnd.ms-word.template.macroenabled.12'], + 'dotx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.template'], + 'dp' => ['application/vnd.osgi.dp'], + 'dpg' => ['application/vnd.dpgraph'], + 'dra' => ['audio/vnd.dra'], + 'drl' => ['application/x-excellon'], + 'drle' => ['image/dicom-rle'], + 'drv' => ['application/vnd.microsoft.portable-executable', 'application/x-ms-dos-executable', 'application/x-ms-ne-executable', 'application/x-msdownload'], + 'dsc' => ['text/prs.lines.tag'], + 'dsf' => ['audio/dsd', 'audio/dsf', 'audio/x-dsd', 'audio/x-dsf'], + 'dsl' => ['text/x-dsl'], + 'dssc' => ['application/dssc+der'], + 'dtb' => ['application/x-dtbook+xml', 'text/x-devicetree-binary'], + 'dtd' => ['application/xml-dtd', 'text/x-dtd'], + 'dts' => ['audio/vnd.dts', 'audio/x-dts', 'text/x-devicetree-source'], + 'dtshd' => ['audio/vnd.dts.hd', 'audio/x-dtshd'], + 'dtsi' => ['text/x-devicetree-source'], + 'dtx' => ['application/x-tex', 'text/x-tex'], + 'dv' => ['video/dv'], + 'dvb' => ['video/vnd.dvb.file'], + 'dvi' => ['application/x-dvi'], + 'dvi.bz2' => ['application/x-bzdvi'], + 'dvi.gz' => ['application/x-gzdvi'], + 'dwd' => ['application/atsc-dwd+xml'], + 'dwf' => ['model/vnd.dwf'], + 'dwg' => ['image/vnd.dwg'], + 'dxf' => ['image/vnd.dxf'], + 'dxp' => ['application/vnd.spotfire.dxp'], + 'dxr' => ['application/x-director'], + 'e' => ['text/x-eiffel'], + 'ear' => ['application/java-archive'], + 'ecelp4800' => ['audio/vnd.nuera.ecelp4800'], + 'ecelp7470' => ['audio/vnd.nuera.ecelp7470'], + 'ecelp9600' => ['audio/vnd.nuera.ecelp9600'], + 'ecma' => ['application/ecmascript'], + 'edm' => ['application/vnd.novadigm.edm'], + 'edx' => ['application/vnd.novadigm.edx'], + 'efi' => ['application/vnd.microsoft.portable-executable'], + 'efif' => ['application/vnd.picsel'], + 'egon' => ['application/x-egon'], + 'ei6' => ['application/vnd.pg.osasli'], + 'eif' => ['text/x-eiffel'], + 'el' => ['text/x-emacs-lisp'], + 'emf' => ['application/emf', 'application/x-emf', 'application/x-msmetafile', 'image/emf', 'image/x-emf'], + 'eml' => ['message/rfc822'], + 'emma' => ['application/emma+xml'], + 'emotionml' => ['application/emotionml+xml'], + 'emp' => ['application/vnd.emusic-emusic_package'], + 'emz' => ['application/x-msmetafile'], + 'ent' => ['application/xml-external-parsed-entity', 'text/xml-external-parsed-entity'], + 'eol' => ['audio/vnd.digital-winds'], + 'eot' => ['application/vnd.ms-fontobject'], + 'eps' => ['application/postscript', 'image/x-eps'], + 'eps.bz2' => ['image/x-bzeps'], + 'eps.gz' => ['image/x-gzeps'], + 'epsf' => ['image/x-eps'], + 'epsf.bz2' => ['image/x-bzeps'], + 'epsf.gz' => ['image/x-gzeps'], + 'epsi' => ['image/x-eps'], + 'epsi.bz2' => ['image/x-bzeps'], + 'epsi.gz' => ['image/x-gzeps'], + 'epub' => ['application/epub+zip'], + 'eris' => ['application/x-eris-link+cbor'], + 'erl' => ['text/x-erlang'], + 'es' => ['application/ecmascript', 'text/ecmascript'], + 'es3' => ['application/vnd.eszigno3+xml'], + 'esa' => ['application/vnd.osgi.subsystem'], + 'escn' => ['application/x-godot-scene'], + 'esf' => ['application/vnd.epson.esf'], + 'et3' => ['application/vnd.eszigno3+xml'], + 'etheme' => ['application/x-e-theme'], + 'etx' => ['text/x-setext'], + 'eva' => ['application/x-eva'], + 'evy' => ['application/x-envoy'], + 'ex' => ['text/x-elixir'], + 'exe' => ['application/vnd.microsoft.portable-executable', 'application/x-dosexec', 'application/x-ms-dos-executable', 'application/x-ms-ne-executable', 'application/x-msdos-program', 'application/x-msdownload'], + 'exi' => ['application/exi'], + 'exp' => ['application/express'], + 'exr' => ['image/aces', 'image/x-exr'], + 'exs' => ['text/x-elixir'], + 'ext' => ['application/vnd.novadigm.ext'], + 'ez' => ['application/andrew-inset'], + 'ez2' => ['application/vnd.ezpix-album'], + 'ez3' => ['application/vnd.ezpix-package'], + 'f' => ['text/x-fortran'], + 'f4a' => ['audio/m4a', 'audio/mp4', 'audio/x-m4a'], + 'f4b' => ['audio/x-m4b'], + 'f4v' => ['video/mp4', 'video/mp4v-es', 'video/x-f4v', 'video/x-m4v'], + 'f77' => ['text/x-fortran'], + 'f90' => ['text/x-fortran'], + 'f95' => ['text/x-fortran'], + 'fasl' => ['text/x-common-lisp'], + 'fb2' => ['application/x-fictionbook', 'application/x-fictionbook+xml'], + 'fb2.zip' => ['application/x-zip-compressed-fb2'], + 'fbs' => ['image/vnd.fastbidsheet'], + 'fcdt' => ['application/vnd.adobe.formscentral.fcdt'], + 'fcs' => ['application/vnd.isac.fcs'], + 'fd' => ['application/x-fd-file', 'application/x-raw-floppy-disk-image'], + 'fdf' => ['application/vnd.fdf'], + 'fds' => ['application/x-fds-disk'], + 'fdt' => ['application/fdt+xml'], + 'fe_launch' => ['application/vnd.denovo.fcselayout-link'], + 'feature' => ['text/x-gherkin'], + 'fg5' => ['application/vnd.fujitsu.oasysgp'], + 'fgd' => ['application/x-director'], + 'fh' => ['image/x-freehand'], + 'fh4' => ['image/x-freehand'], + 'fh5' => ['image/x-freehand'], + 'fh7' => ['image/x-freehand'], + 'fhc' => ['image/x-freehand'], + 'fig' => ['application/x-xfig', 'image/x-xfig'], + 'fish' => ['application/x-fishscript', 'text/x-fish'], + 'fit' => ['application/fits', 'image/fits', 'image/x-fits'], + 'fits' => ['application/fits', 'image/fits', 'image/x-fits'], + 'fl' => ['application/x-fluid'], + 'flac' => ['audio/flac', 'audio/x-flac'], + 'flatpak' => ['application/vnd.flatpak', 'application/vnd.xdgapp'], + 'flatpakref' => ['application/vnd.flatpak.ref'], + 'flatpakrepo' => ['application/vnd.flatpak.repo'], + 'flc' => ['video/fli', 'video/x-fli', 'video/x-flic'], + 'fli' => ['video/fli', 'video/x-fli', 'video/x-flic'], + 'flo' => ['application/vnd.micrografx.flo'], + 'flv' => ['video/x-flv', 'application/x-flash-video', 'flv-application/octet-stream', 'video/flv'], + 'flw' => ['application/vnd.kde.kivio', 'application/x-kivio'], + 'flx' => ['text/vnd.fmi.flexstor'], + 'fly' => ['text/vnd.fly'], + 'fm' => ['application/vnd.framemaker', 'application/x-frame'], + 'fnc' => ['application/vnd.frogans.fnc'], + 'fo' => ['application/vnd.software602.filler.form+xml', 'text/x-xslfo'], + 'fodg' => ['application/vnd.oasis.opendocument.graphics-flat-xml'], + 'fodp' => ['application/vnd.oasis.opendocument.presentation-flat-xml'], + 'fods' => ['application/vnd.oasis.opendocument.spreadsheet-flat-xml'], + 'fodt' => ['application/vnd.oasis.opendocument.text-flat-xml'], + 'for' => ['text/x-fortran'], + 'fpx' => ['image/vnd.fpx'], + 'frame' => ['application/vnd.framemaker'], + 'fsc' => ['application/vnd.fsc.weblaunch'], + 'fst' => ['image/vnd.fst'], + 'ftc' => ['application/vnd.fluxtime.clip'], + 'fti' => ['application/vnd.anser-web-funds-transfer-initiation'], + 'fts' => ['application/fits', 'image/fits', 'image/x-fits'], + 'fvt' => ['video/vnd.fvt'], + 'fxm' => ['video/x-javafx'], + 'fxp' => ['application/vnd.adobe.fxp'], + 'fxpl' => ['application/vnd.adobe.fxp'], + 'fzs' => ['application/vnd.fuzzysheet'], + 'g2w' => ['application/vnd.geoplan'], + 'g3' => ['image/fax-g3', 'image/g3fax'], + 'g3w' => ['application/vnd.geospace'], + 'gac' => ['application/vnd.groove-account'], + 'gam' => ['application/x-tads'], + 'gb' => ['application/x-gameboy-rom'], + 'gba' => ['application/x-gba-rom'], + 'gbc' => ['application/x-gameboy-color-rom'], + 'gbr' => ['application/rpki-ghostbusters', 'application/vnd.gerber', 'application/x-gerber', 'image/x-gimp-gbr'], + 'gbrjob' => ['application/x-gerber-job'], + 'gca' => ['application/x-gca-compressed'], + 'gcode' => ['text/x.gcode'], + 'gcrd' => ['text/directory', 'text/vcard', 'text/x-vcard'], + 'gd' => ['application/x-gdscript'], + 'gdi' => ['application/x-gd-rom-cue'], + 'gdl' => ['model/vnd.gdl'], + 'gdoc' => ['application/vnd.google-apps.document'], + 'gdshader' => ['application/x-godot-shader'], + 'ged' => ['application/x-gedcom', 'text/gedcom', 'text/vnd.familysearch.gedcom'], + 'gedcom' => ['application/x-gedcom', 'text/gedcom', 'text/vnd.familysearch.gedcom'], + 'gem' => ['application/x-gtar', 'application/x-tar'], + 'gen' => ['application/x-genesis-rom'], + 'geo' => ['application/vnd.dynageo'], + 'geo.json' => ['application/geo+json', 'application/vnd.geo+json'], + 'geojson' => ['application/geo+json', 'application/vnd.geo+json'], + 'gex' => ['application/vnd.geometry-explorer'], + 'gf' => ['application/x-tex-gf'], + 'gg' => ['application/x-gamegear-rom'], + 'ggb' => ['application/vnd.geogebra.file'], + 'ggt' => ['application/vnd.geogebra.tool'], + 'ghf' => ['application/vnd.groove-help'], + 'gif' => ['image/gif'], + 'gih' => ['image/x-gimp-gih'], + 'gim' => ['application/vnd.groove-identity-message'], + 'glade' => ['application/x-glade'], + 'glb' => ['model/gltf-binary'], + 'gltf' => ['model/gltf+json'], + 'gml' => ['application/gml+xml'], + 'gmo' => ['application/x-gettext-translation'], + 'gmx' => ['application/vnd.gmx'], + 'gnc' => ['application/x-gnucash'], + 'gnd' => ['application/gnunet-directory'], + 'gnucash' => ['application/x-gnucash'], + 'gnumeric' => ['application/x-gnumeric'], + 'gnuplot' => ['application/x-gnuplot'], + 'go' => ['text/x-go'], + 'gp' => ['application/x-gnuplot'], + 'gpg' => ['application/pgp', 'application/pgp-encrypted', 'application/pgp-keys', 'application/pgp-signature'], + 'gph' => ['application/vnd.flographit'], + 'gplt' => ['application/x-gnuplot'], + 'gpx' => ['application/gpx', 'application/gpx+xml', 'application/x-gpx', 'application/x-gpx+xml'], + 'gqf' => ['application/vnd.grafeq'], + 'gqs' => ['application/vnd.grafeq'], + 'gra' => ['application/x-graphite'], + 'gradle' => ['text/x-gradle'], + 'gram' => ['application/srgs'], + 'gramps' => ['application/x-gramps-xml'], + 'gre' => ['application/vnd.geometry-explorer'], + 'groovy' => ['text/x-groovy'], + 'grv' => ['application/vnd.groove-injector'], + 'grxml' => ['application/srgs+xml'], + 'gs' => ['text/x-genie'], + 'gsf' => ['application/x-font-ghostscript', 'application/x-font-type1'], + 'gsh' => ['text/x-groovy'], + 'gsheet' => ['application/vnd.google-apps.spreadsheet'], + 'gslides' => ['application/vnd.google-apps.presentation'], + 'gsm' => ['audio/x-gsm'], + 'gtar' => ['application/x-gtar', 'application/x-tar'], + 'gtm' => ['application/vnd.groove-tool-message'], + 'gtw' => ['model/vnd.gtw'], + 'gv' => ['text/vnd.graphviz'], + 'gvp' => ['text/google-video-pointer', 'text/x-google-video-pointer'], + 'gvy' => ['text/x-groovy'], + 'gx' => ['text/x-gcode-gx'], + 'gxf' => ['application/gxf'], + 'gxt' => ['application/vnd.geonext'], + 'gy' => ['text/x-groovy'], + 'gz' => ['application/x-gzip', 'application/gzip'], + 'h' => ['text/x-c', 'text/x-chdr'], + 'h++' => ['text/x-c++hdr'], + 'h261' => ['video/h261'], + 'h263' => ['video/h263'], + 'h264' => ['video/h264'], + 'h4' => ['application/x-hdf'], + 'h5' => ['application/x-hdf'], + 'hal' => ['application/vnd.hal+xml'], + 'hbci' => ['application/vnd.hbci'], + 'hbs' => ['text/x-handlebars-template'], + 'hdd' => ['application/x-virtualbox-hdd'], + 'hdf' => ['application/x-hdf'], + 'hdf4' => ['application/x-hdf'], + 'hdf5' => ['application/x-hdf'], + 'hdp' => ['image/jxr', 'image/vnd.ms-photo'], + 'heic' => ['image/heic', 'image/heic-sequence', 'image/heif', 'image/heif-sequence'], + 'heics' => ['image/heic-sequence'], + 'heif' => ['image/heic', 'image/heic-sequence', 'image/heif', 'image/heif-sequence'], + 'heifs' => ['image/heif-sequence'], + 'hej2' => ['image/hej2k'], + 'held' => ['application/atsc-held+xml'], + 'hfe' => ['application/x-hfe-file', 'application/x-hfe-floppy-image'], + 'hh' => ['text/x-c', 'text/x-c++hdr'], + 'hif' => ['image/heic', 'image/heic-sequence', 'image/heif', 'image/heif-sequence'], + 'hjson' => ['application/hjson'], + 'hlp' => ['application/winhlp', 'zz-application/zz-winassoc-hlp'], + 'hp' => ['text/x-c++hdr'], + 'hpgl' => ['application/vnd.hp-hpgl'], + 'hpid' => ['application/vnd.hp-hpid'], + 'hpp' => ['text/x-c++hdr'], + 'hps' => ['application/vnd.hp-hps'], + 'hqx' => ['application/stuffit', 'application/mac-binhex40'], + 'hs' => ['text/x-haskell'], + 'hsj2' => ['image/hsj2'], + 'hta' => ['application/hta'], + 'htc' => ['text/x-component'], + 'htke' => ['application/vnd.kenameaapp'], + 'htm' => ['text/html', 'application/xhtml+xml'], + 'html' => ['text/html', 'application/xhtml+xml'], + 'hvd' => ['application/vnd.yamaha.hv-dic'], + 'hvp' => ['application/vnd.yamaha.hv-voice'], + 'hvs' => ['application/vnd.yamaha.hv-script'], + 'hwp' => ['application/vnd.haansoft-hwp', 'application/x-hwp'], + 'hwt' => ['application/vnd.haansoft-hwt', 'application/x-hwt'], + 'hxx' => ['text/x-c++hdr'], + 'i2g' => ['application/vnd.intergeo'], + 'ica' => ['application/x-ica'], + 'icb' => ['application/tga', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], + 'icc' => ['application/vnd.iccprofile'], + 'ice' => ['x-conference/x-cooltalk'], + 'icm' => ['application/vnd.iccprofile'], + 'icns' => ['image/x-icns'], + 'ico' => ['application/ico', 'image/ico', 'image/icon', 'image/vnd.microsoft.icon', 'image/x-ico', 'image/x-icon', 'text/ico'], + 'ics' => ['application/ics', 'text/calendar', 'text/x-vcalendar'], + 'idl' => ['text/x-idl'], + 'ief' => ['image/ief'], + 'ifb' => ['text/calendar'], + 'iff' => ['image/x-iff', 'image/x-ilbm'], + 'ifm' => ['application/vnd.shana.informed.formdata'], + 'iges' => ['model/iges'], + 'igl' => ['application/vnd.igloader'], + 'igm' => ['application/vnd.insors.igm'], + 'igs' => ['model/iges'], + 'igx' => ['application/vnd.micrografx.igx'], + 'iif' => ['application/vnd.shana.informed.interchange'], + 'ilbm' => ['image/x-iff', 'image/x-ilbm'], + 'ime' => ['audio/imelody', 'audio/x-imelody', 'text/x-imelody'], + 'img' => ['application/vnd.efi.img', 'application/x-raw-disk-image'], + 'img.xz' => ['application/x-raw-disk-image-xz-compressed'], + 'imp' => ['application/vnd.accpac.simply.imp'], + 'ims' => ['application/vnd.ms-ims'], + 'imy' => ['audio/imelody', 'audio/x-imelody', 'text/x-imelody'], + 'in' => ['text/plain'], + 'ini' => ['text/plain'], + 'ink' => ['application/inkml+xml'], + 'inkml' => ['application/inkml+xml'], + 'ins' => ['application/x-tex', 'text/x-tex'], + 'install' => ['application/x-install-instructions'], + 'iota' => ['application/vnd.astraea-software.iota'], + 'ipfix' => ['application/ipfix'], + 'ipk' => ['application/vnd.shana.informed.package'], + 'ips' => ['application/x-ips-patch'], + 'iptables' => ['text/x-iptables'], + 'ipynb' => ['application/x-ipynb+json'], + 'irm' => ['application/vnd.ibm.rights-management'], + 'irp' => ['application/vnd.irepository.package+xml'], + 'iso' => ['application/vnd.efi.iso', 'application/x-cd-image', 'application/x-dreamcast-rom', 'application/x-gamecube-iso-image', 'application/x-gamecube-rom', 'application/x-iso9660-image', 'application/x-saturn-rom', 'application/x-sega-cd-rom', 'application/x-sega-pico-rom', 'application/x-wbfs', 'application/x-wia', 'application/x-wii-iso-image', 'application/x-wii-rom'], + 'iso9660' => ['application/vnd.efi.iso', 'application/x-cd-image', 'application/x-iso9660-image'], + 'it' => ['audio/x-it'], + 'it87' => ['application/x-it87'], + 'itp' => ['application/vnd.shana.informed.formtemplate'], + 'its' => ['application/its+xml'], + 'ivp' => ['application/vnd.immervision-ivp'], + 'ivu' => ['application/vnd.immervision-ivu'], + 'j2c' => ['image/x-jp2-codestream'], + 'j2k' => ['image/x-jp2-codestream'], + 'jad' => ['text/vnd.sun.j2me.app-descriptor'], + 'jade' => ['text/jade'], + 'jam' => ['application/vnd.jam'], + 'jar' => ['application/x-java-archive', 'application/java-archive', 'application/x-jar'], + 'jardiff' => ['application/x-java-archive-diff'], + 'java' => ['text/x-java', 'text/x-java-source'], + 'jceks' => ['application/x-java-jce-keystore'], + 'jfif' => ['image/jpeg', 'image/pjpeg'], + 'jhc' => ['image/jphc'], + 'jisp' => ['application/vnd.jisp'], + 'jks' => ['application/x-java-keystore'], + 'jl' => ['text/julia'], + 'jls' => ['image/jls'], + 'jlt' => ['application/vnd.hp-jlyt'], + 'jng' => ['image/x-jng'], + 'jnlp' => ['application/x-java-jnlp-file'], + 'joda' => ['application/vnd.joost.joda-archive'], + 'jp2' => ['image/jp2', 'image/jpeg2000', 'image/jpeg2000-image', 'image/x-jpeg2000-image'], + 'jpc' => ['image/x-jp2-codestream'], + 'jpe' => ['image/jpeg', 'image/pjpeg'], + 'jpeg' => ['image/jpeg', 'image/pjpeg'], + 'jpf' => ['image/jpx'], + 'jpg' => ['image/jpeg', 'image/pjpeg'], + 'jpg2' => ['image/jp2', 'image/jpeg2000', 'image/jpeg2000-image', 'image/x-jpeg2000-image'], + 'jpgm' => ['image/jpm', 'video/jpm'], + 'jpgv' => ['video/jpeg'], + 'jph' => ['image/jph'], + 'jpm' => ['image/jpm', 'video/jpm'], + 'jpr' => ['application/x-jbuilder-project'], + 'jpx' => ['application/x-jbuilder-project', 'image/jpx'], + 'jrd' => ['application/jrd+json'], + 'js' => ['text/javascript', 'application/javascript', 'application/x-javascript', 'text/jscript'], + 'jse' => ['text/jscript.encode'], + 'jsm' => ['application/javascript', 'application/x-javascript', 'text/javascript', 'text/jscript'], + 'json' => ['application/json', 'application/schema+json'], + 'json-patch' => ['application/json-patch+json'], + 'json5' => ['application/json5'], + 'jsonld' => ['application/ld+json'], + 'jsonml' => ['application/jsonml+json'], + 'jsx' => ['text/jsx'], + 'jxl' => ['image/jxl'], + 'jxr' => ['image/jxr', 'image/vnd.ms-photo'], + 'jxra' => ['image/jxra'], + 'jxrs' => ['image/jxrs'], + 'jxs' => ['image/jxs'], + 'jxsc' => ['image/jxsc'], + 'jxsi' => ['image/jxsi'], + 'jxss' => ['image/jxss'], + 'k25' => ['image/x-kodak-k25'], + 'k7' => ['application/x-thomson-cassette'], + 'kar' => ['audio/midi', 'audio/x-midi'], + 'karbon' => ['application/vnd.kde.karbon', 'application/x-karbon'], + 'kdbx' => ['application/x-keepass2'], + 'kdc' => ['image/x-kodak-kdc'], + 'kdelnk' => ['application/x-desktop', 'application/x-gnome-app-info'], + 'kexi' => ['application/x-kexiproject-sqlite', 'application/x-kexiproject-sqlite2', 'application/x-kexiproject-sqlite3', 'application/x-vnd.kde.kexi'], + 'kexic' => ['application/x-kexi-connectiondata'], + 'kexis' => ['application/x-kexiproject-shortcut'], + 'key' => ['application/vnd.apple.keynote', 'application/pgp-keys', 'application/x-iwork-keynote-sffkey'], + 'keynote' => ['application/vnd.apple.keynote'], + 'kfo' => ['application/vnd.kde.kformula', 'application/x-kformula'], + 'kfx' => ['application/vnd.amazon.mobi8-ebook', 'application/x-mobi8-ebook'], + 'kia' => ['application/vnd.kidspiration'], + 'kil' => ['application/x-killustrator'], + 'kino' => ['application/smil', 'application/smil+xml'], + 'kml' => ['application/vnd.google-earth.kml+xml'], + 'kmz' => ['application/vnd.google-earth.kmz'], + 'kne' => ['application/vnd.kinar'], + 'knp' => ['application/vnd.kinar'], + 'kon' => ['application/vnd.kde.kontour', 'application/x-kontour'], + 'kpm' => ['application/x-kpovmodeler'], + 'kpr' => ['application/vnd.kde.kpresenter', 'application/x-kpresenter'], + 'kpt' => ['application/vnd.kde.kpresenter', 'application/x-kpresenter'], + 'kpxx' => ['application/vnd.ds-keypoint'], + 'kra' => ['application/x-krita'], + 'krz' => ['application/x-krita'], + 'ks' => ['application/x-java-keystore'], + 'ksp' => ['application/vnd.kde.kspread', 'application/x-kspread'], + 'ksy' => ['text/x-kaitai-struct'], + 'kt' => ['text/x-kotlin'], + 'ktr' => ['application/vnd.kahootz'], + 'ktx' => ['image/ktx'], + 'ktx2' => ['image/ktx2'], + 'ktz' => ['application/vnd.kahootz'], + 'kud' => ['application/x-kugar'], + 'kwd' => ['application/vnd.kde.kword', 'application/x-kword'], + 'kwt' => ['application/vnd.kde.kword', 'application/x-kword'], + 'la' => ['application/x-shared-library-la'], + 'lasxml' => ['application/vnd.las.las+xml'], + 'latex' => ['application/x-latex', 'application/x-tex', 'text/x-tex'], + 'lbd' => ['application/vnd.llamagraphics.life-balance.desktop'], + 'lbe' => ['application/vnd.llamagraphics.life-balance.exchange+xml'], + 'lbm' => ['image/x-iff', 'image/x-ilbm'], + 'ldif' => ['text/x-ldif'], + 'les' => ['application/vnd.hhe.lesson-player'], + 'less' => ['text/less'], + 'lgr' => ['application/lgr+xml'], + 'lha' => ['application/x-lha', 'application/x-lzh-compressed'], + 'lhs' => ['text/x-literate-haskell'], + 'lhz' => ['application/x-lhz'], + 'lib' => ['application/vnd.microsoft.portable-executable'], + 'link66' => ['application/vnd.route66.link66+xml'], + 'lisp' => ['text/x-common-lisp'], + 'list' => ['text/plain'], + 'list3820' => ['application/vnd.ibm.modcap'], + 'listafp' => ['application/vnd.ibm.modcap'], + 'litcoffee' => ['text/coffeescript'], + 'lmdb' => ['application/x-lmdb'], + 'lnk' => ['application/x-ms-shortcut', 'application/x-win-lnk'], + 'lnx' => ['application/x-atari-lynx-rom'], + 'loas' => ['audio/usac'], + 'log' => ['text/plain', 'text/x-log'], + 'lostxml' => ['application/lost+xml'], + 'lrm' => ['application/vnd.ms-lrm'], + 'lrv' => ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], + 'lrz' => ['application/x-lrzip'], + 'ltf' => ['application/vnd.frogans.ltf'], + 'ltx' => ['application/x-tex', 'text/x-tex'], + 'lua' => ['text/x-lua'], + 'luac' => ['application/x-lua-bytecode'], + 'lvp' => ['audio/vnd.lucent.voice'], + 'lwo' => ['image/x-lwo'], + 'lwob' => ['image/x-lwo'], + 'lwp' => ['application/vnd.lotus-wordpro'], + 'lws' => ['image/x-lws'], + 'ly' => ['text/x-lilypond'], + 'lyx' => ['application/x-lyx', 'text/x-lyx'], + 'lz' => ['application/x-lzip'], + 'lz4' => ['application/x-lz4'], + 'lzh' => ['application/x-lha', 'application/x-lzh-compressed'], + 'lzma' => ['application/x-lzma'], + 'lzo' => ['application/x-lzop'], + 'm' => ['text/x-matlab', 'text/x-objcsrc', 'text/x-octave'], + 'm13' => ['application/x-msmediaview'], + 'm14' => ['application/x-msmediaview'], + 'm15' => ['audio/x-mod'], + 'm1u' => ['video/vnd.mpegurl', 'video/x-mpegurl'], + 'm1v' => ['video/mpeg'], + 'm21' => ['application/mp21'], + 'm2a' => ['audio/mpeg'], + 'm2t' => ['video/mp2t'], + 'm2ts' => ['video/mp2t'], + 'm2v' => ['video/mpeg'], + 'm3a' => ['audio/mpeg'], + 'm3u' => ['audio/x-mpegurl', 'application/m3u', 'application/vnd.apple.mpegurl', 'audio/m3u', 'audio/mpegurl', 'audio/x-m3u', 'audio/x-mp3-playlist'], + 'm3u8' => ['application/m3u', 'application/vnd.apple.mpegurl', 'audio/m3u', 'audio/mpegurl', 'audio/x-m3u', 'audio/x-mp3-playlist', 'audio/x-mpegurl'], + 'm4' => ['application/x-m4'], + 'm4a' => ['audio/mp4', 'audio/m4a', 'audio/x-m4a'], + 'm4b' => ['audio/x-m4b'], + 'm4p' => ['application/mp4'], + 'm4r' => ['audio/x-m4r'], + 'm4s' => ['video/iso.segment'], + 'm4u' => ['video/vnd.mpegurl', 'video/x-mpegurl'], + 'm4v' => ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], + 'm7' => ['application/x-thomson-cartridge-memo7'], + 'ma' => ['application/mathematica'], + 'mab' => ['application/x-markaby'], + 'mads' => ['application/mads+xml'], + 'maei' => ['application/mmt-aei+xml'], + 'mag' => ['application/vnd.ecowin.chart'], + 'mak' => ['text/x-makefile'], + 'maker' => ['application/vnd.framemaker'], + 'man' => ['application/x-troff-man', 'text/troff'], + 'manifest' => ['text/cache-manifest'], + 'map' => ['application/json'], + 'markdown' => ['text/markdown', 'text/x-markdown'], + 'mathml' => ['application/mathml+xml'], + 'mb' => ['application/mathematica'], + 'mbk' => ['application/vnd.mobius.mbk'], + 'mbox' => ['application/mbox'], + 'mc1' => ['application/vnd.medcalcdata'], + 'mc2' => ['text/vnd.senx.warpscript'], + 'mcd' => ['application/vnd.mcd'], + 'mcurl' => ['text/vnd.curl.mcurl'], + 'md' => ['text/markdown', 'text/x-markdown'], + 'mdb' => ['application/x-msaccess', 'application/mdb', 'application/msaccess', 'application/vnd.ms-access', 'application/vnd.msaccess', 'application/x-lmdb', 'application/x-mdb', 'zz-application/zz-winassoc-mdb'], + 'mdi' => ['image/vnd.ms-modi'], + 'mdx' => ['application/x-genesis-32x-rom', 'text/mdx'], + 'me' => ['text/troff', 'text/x-troff-me'], + 'med' => ['audio/x-mod'], + 'mesh' => ['model/mesh'], + 'meta4' => ['application/metalink4+xml'], + 'metalink' => ['application/metalink+xml'], + 'mets' => ['application/mets+xml'], + 'mfm' => ['application/vnd.mfmp'], + 'mft' => ['application/rpki-manifest'], + 'mgp' => ['application/vnd.osgeo.mapguide.package', 'application/x-magicpoint'], + 'mgz' => ['application/vnd.proteus.magazine'], + 'mht' => ['application/x-mimearchive'], + 'mhtml' => ['application/x-mimearchive'], + 'mid' => ['audio/midi', 'audio/x-midi'], + 'midi' => ['audio/midi', 'audio/x-midi'], + 'mie' => ['application/x-mie'], + 'mif' => ['application/vnd.mif', 'application/x-mif'], + 'mime' => ['message/rfc822'], + 'minipsf' => ['audio/x-minipsf'], + 'mj2' => ['video/mj2'], + 'mjp2' => ['video/mj2'], + 'mjpeg' => ['video/x-mjpeg'], + 'mjpg' => ['video/x-mjpeg'], + 'mjs' => ['application/javascript', 'application/x-javascript', 'text/javascript', 'text/jscript'], + 'mk' => ['text/x-makefile'], + 'mk3d' => ['video/x-matroska', 'video/x-matroska-3d'], + 'mka' => ['audio/x-matroska'], + 'mkd' => ['text/markdown', 'text/x-markdown'], + 'mks' => ['video/x-matroska'], + 'mkv' => ['video/x-matroska'], + 'ml' => ['text/x-ocaml'], + 'mli' => ['text/x-ocaml'], + 'mlp' => ['application/vnd.dolby.mlp'], + 'mm' => ['text/x-objc++src', 'text/x-troff-mm'], + 'mmd' => ['application/vnd.chipnuts.karaoke-mmd'], + 'mmf' => ['application/vnd.smaf', 'application/x-smaf'], + 'mml' => ['application/mathml+xml', 'text/mathml'], + 'mmr' => ['image/vnd.fujixerox.edmics-mmr'], + 'mng' => ['video/x-mng'], + 'mny' => ['application/x-msmoney'], + 'mo' => ['application/x-gettext-translation', 'text/x-modelica'], + 'mo3' => ['audio/x-mo3'], + 'mobi' => ['application/x-mobipocket-ebook'], + 'moc' => ['text/x-moc'], + 'mod' => ['application/x-object', 'audio/x-mod'], + 'mods' => ['application/mods+xml'], + 'mof' => ['text/x-mof'], + 'moov' => ['video/quicktime'], + 'mount' => ['text/x-systemd-unit'], + 'mov' => ['video/quicktime'], + 'movie' => ['video/x-sgi-movie'], + 'mp+' => ['audio/x-musepack'], + 'mp2' => ['audio/mp2', 'audio/mpeg', 'audio/x-mp2', 'video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], + 'mp21' => ['application/mp21'], + 'mp2a' => ['audio/mpeg'], + 'mp3' => ['audio/mpeg', 'audio/mp3', 'audio/x-mp3', 'audio/x-mpeg', 'audio/x-mpg'], + 'mp4' => ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], + 'mp4a' => ['audio/mp4'], + 'mp4s' => ['application/mp4'], + 'mp4v' => ['video/mp4'], + 'mpc' => ['application/vnd.mophun.certificate', 'audio/x-musepack'], + 'mpd' => ['application/dash+xml'], + 'mpe' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], + 'mpeg' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], + 'mpf' => ['application/media-policy-dataset+xml'], + 'mpg' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], + 'mpg4' => ['video/mp4'], + 'mpga' => ['audio/mp3', 'audio/mpeg', 'audio/x-mp3', 'audio/x-mpeg', 'audio/x-mpg'], + 'mpkg' => ['application/vnd.apple.installer+xml'], + 'mpl' => ['text/x-mpl2', 'video/mp2t'], + 'mpls' => ['video/mp2t'], + 'mpm' => ['application/vnd.blueice.multipass'], + 'mpn' => ['application/vnd.mophun.application'], + 'mpp' => ['application/dash-patch+xml', 'application/vnd.ms-project', 'audio/x-musepack'], + 'mpt' => ['application/vnd.ms-project'], + 'mpy' => ['application/vnd.ibm.minipay'], + 'mqy' => ['application/vnd.mobius.mqy'], + 'mrc' => ['application/marc'], + 'mrcx' => ['application/marcxml+xml'], + 'mrl' => ['text/x-mrml'], + 'mrml' => ['text/x-mrml'], + 'mrpack' => ['application/x-modrinth-modpack+zip'], + 'mrw' => ['image/x-minolta-mrw'], + 'ms' => ['text/troff', 'text/x-troff-ms'], + 'mscml' => ['application/mediaservercontrol+xml'], + 'mseed' => ['application/vnd.fdsn.mseed'], + 'mseq' => ['application/vnd.mseq'], + 'msf' => ['application/vnd.epson.msf'], + 'msg' => ['application/vnd.ms-outlook'], + 'msh' => ['model/mesh'], + 'msi' => ['application/x-msdownload', 'application/x-msi'], + 'msix' => ['application/msix'], + 'msixbundle' => ['application/msixbundle'], + 'msl' => ['application/vnd.mobius.msl'], + 'msod' => ['image/x-msod'], + 'msp' => ['application/microsoftpatch'], + 'msty' => ['application/vnd.muvee.style'], + 'msu' => ['application/microsoftupdate'], + 'msx' => ['application/x-msx-rom'], + 'mtl' => ['model/mtl'], + 'mtm' => ['audio/x-mod'], + 'mts' => ['model/vnd.mts', 'video/mp2t'], + 'mup' => ['text/x-mup'], + 'mus' => ['application/vnd.musician'], + 'musd' => ['application/mmt-usd+xml'], + 'musicxml' => ['application/vnd.recordare.musicxml+xml'], + 'mvb' => ['application/x-msmediaview'], + 'mvt' => ['application/vnd.mapbox-vector-tile'], + 'mwf' => ['application/vnd.mfer'], + 'mxf' => ['application/mxf'], + 'mxl' => ['application/vnd.recordare.musicxml'], + 'mxmf' => ['audio/mobile-xmf', 'audio/vnd.nokia.mobile-xmf'], + 'mxml' => ['application/xv+xml'], + 'mxs' => ['application/vnd.triscape.mxs'], + 'mxu' => ['video/vnd.mpegurl', 'video/x-mpegurl'], + 'n-gage' => ['application/vnd.nokia.n-gage.symbian.install'], + 'n3' => ['text/n3'], + 'n64' => ['application/x-n64-rom'], + 'nb' => ['application/mathematica', 'application/x-mathematica'], + 'nbp' => ['application/vnd.wolfram.player'], + 'nc' => ['application/x-netcdf'], + 'ncx' => ['application/x-dtbncx+xml'], + 'nds' => ['application/x-nintendo-ds-rom'], + 'nef' => ['image/x-nikon-nef'], + 'nes' => ['application/x-nes-rom'], + 'nez' => ['application/x-nes-rom'], + 'nfo' => ['text/x-nfo'], + 'ngc' => ['application/x-neo-geo-pocket-color-rom'], + 'ngdat' => ['application/vnd.nokia.n-gage.data'], + 'ngp' => ['application/x-neo-geo-pocket-rom'], + 'nim' => ['text/x-nim'], + 'nimble' => ['text/x-nimscript'], + 'nims' => ['text/x-nimscript'], + 'nitf' => ['application/vnd.nitf'], + 'nlu' => ['application/vnd.neurolanguage.nlu'], + 'nml' => ['application/vnd.enliven'], + 'nnd' => ['application/vnd.noblenet-directory'], + 'nns' => ['application/vnd.noblenet-sealer'], + 'nnw' => ['application/vnd.noblenet-web'], + 'not' => ['text/x-mup'], + 'npx' => ['image/vnd.net-fpx'], + 'nq' => ['application/n-quads'], + 'nrw' => ['image/x-nikon-nrw'], + 'nsc' => ['application/x-conference', 'application/x-netshow-channel'], + 'nsf' => ['application/vnd.lotus-notes'], + 'nsv' => ['video/x-nsv'], + 'nt' => ['application/n-triples'], + 'ntf' => ['application/vnd.nitf'], + 'nu' => ['application/x-nuscript', 'text/x-nu'], + 'numbers' => ['application/vnd.apple.numbers', 'application/x-iwork-numbers-sffnumbers'], + 'nzb' => ['application/x-nzb'], + 'o' => ['application/x-object'], + 'oa2' => ['application/vnd.fujitsu.oasys2'], + 'oa3' => ['application/vnd.fujitsu.oasys3'], + 'oas' => ['application/vnd.fujitsu.oasys'], + 'obd' => ['application/x-msbinder'], + 'obgx' => ['application/vnd.openblox.game+xml'], + 'obj' => ['application/prs.wavefront-obj', 'application/x-tgif', 'model/obj'], + 'ocl' => ['text/x-ocl'], + 'ocx' => ['application/vnd.microsoft.portable-executable'], + 'oda' => ['application/oda'], + 'odb' => ['application/vnd.oasis.opendocument.database', 'application/vnd.sun.xml.base'], + 'odc' => ['application/vnd.oasis.opendocument.chart'], + 'odf' => ['application/vnd.oasis.opendocument.formula'], + 'odft' => ['application/vnd.oasis.opendocument.formula-template'], + 'odg' => ['application/vnd.oasis.opendocument.graphics'], + 'odi' => ['application/vnd.oasis.opendocument.image'], + 'odm' => ['application/vnd.oasis.opendocument.text-master'], + 'odp' => ['application/vnd.oasis.opendocument.presentation'], + 'ods' => ['application/vnd.oasis.opendocument.spreadsheet'], + 'odt' => ['application/vnd.oasis.opendocument.text'], + 'oga' => ['audio/ogg', 'audio/vorbis', 'audio/x-flac+ogg', 'audio/x-ogg', 'audio/x-oggflac', 'audio/x-speex+ogg', 'audio/x-vorbis', 'audio/x-vorbis+ogg'], + 'ogex' => ['model/vnd.opengex'], + 'ogg' => ['audio/ogg', 'audio/vorbis', 'audio/x-flac+ogg', 'audio/x-ogg', 'audio/x-oggflac', 'audio/x-speex+ogg', 'audio/x-vorbis', 'audio/x-vorbis+ogg', 'video/ogg', 'video/x-ogg', 'video/x-theora', 'video/x-theora+ogg'], + 'ogm' => ['video/x-ogm', 'video/x-ogm+ogg'], + 'ogv' => ['video/ogg', 'video/x-ogg'], + 'ogx' => ['application/ogg', 'application/x-ogg'], + 'old' => ['application/x-trash'], + 'oleo' => ['application/x-oleo'], + 'omdoc' => ['application/omdoc+xml'], + 'onepkg' => ['application/onenote'], + 'onetmp' => ['application/onenote'], + 'onetoc' => ['application/onenote'], + 'onetoc2' => ['application/onenote'], + 'ooc' => ['text/x-ooc'], + 'openvpn' => ['application/x-openvpn-profile'], + 'opf' => ['application/oebps-package+xml'], + 'opml' => ['text/x-opml', 'text/x-opml+xml'], + 'oprc' => ['application/vnd.palm', 'application/x-palm-database'], + 'opus' => ['audio/ogg', 'audio/x-ogg', 'audio/x-opus+ogg'], + 'ora' => ['image/openraster'], + 'orf' => ['image/x-olympus-orf'], + 'org' => ['application/vnd.lotus-organizer', 'text/org', 'text/x-org'], + 'osf' => ['application/vnd.yamaha.openscoreformat'], + 'osfpvg' => ['application/vnd.yamaha.openscoreformat.osfpvg+xml'], + 'osm' => ['application/vnd.openstreetmap.data+xml'], + 'otc' => ['application/vnd.oasis.opendocument.chart-template'], + 'otf' => ['application/vnd.oasis.opendocument.formula-template', 'application/x-font-otf', 'font/otf'], + 'otg' => ['application/vnd.oasis.opendocument.graphics-template'], + 'oth' => ['application/vnd.oasis.opendocument.text-web'], + 'oti' => ['application/vnd.oasis.opendocument.image-template'], + 'otp' => ['application/vnd.oasis.opendocument.presentation-template'], + 'ots' => ['application/vnd.oasis.opendocument.spreadsheet-template'], + 'ott' => ['application/vnd.oasis.opendocument.text-template'], + 'ova' => ['application/ovf', 'application/x-virtualbox-ova'], + 'ovf' => ['application/x-virtualbox-ovf'], + 'ovpn' => ['application/x-openvpn-profile'], + 'owl' => ['application/rdf+xml', 'text/rdf'], + 'owx' => ['application/owl+xml'], + 'oxps' => ['application/oxps'], + 'oxt' => ['application/vnd.openofficeorg.extension'], + 'p' => ['text/x-pascal'], + 'p10' => ['application/pkcs10'], + 'p12' => ['application/pkcs12', 'application/x-pkcs12'], + 'p65' => ['application/x-pagemaker'], + 'p7b' => ['application/x-pkcs7-certificates'], + 'p7c' => ['application/pkcs7-mime'], + 'p7m' => ['application/pkcs7-mime'], + 'p7r' => ['application/x-pkcs7-certreqresp'], + 'p7s' => ['application/pkcs7-signature'], + 'p8' => ['application/pkcs8'], + 'p8e' => ['application/pkcs8-encrypted'], + 'pac' => ['application/x-ns-proxy-autoconfig'], + 'pack' => ['application/x-java-pack200'], + 'pages' => ['application/vnd.apple.pages', 'application/x-iwork-pages-sffpages'], + 'pak' => ['application/x-pak'], + 'par2' => ['application/x-par2'], + 'part' => ['application/x-partial-download'], + 'pas' => ['text/x-pascal'], + 'pat' => ['image/x-gimp-pat'], + 'patch' => ['text/x-diff', 'text/x-patch'], + 'path' => ['text/x-systemd-unit'], + 'paw' => ['application/vnd.pawaafile'], + 'pbd' => ['application/vnd.powerbuilder6'], + 'pbm' => ['image/x-portable-bitmap'], + 'pcap' => ['application/pcap', 'application/vnd.tcpdump.pcap', 'application/x-pcap'], + 'pcd' => ['image/x-photo-cd'], + 'pce' => ['application/x-pc-engine-rom'], + 'pcf' => ['application/x-cisco-vpn-settings', 'application/x-font-pcf'], + 'pcf.Z' => ['application/x-font-pcf'], + 'pcf.gz' => ['application/x-font-pcf'], + 'pcl' => ['application/vnd.hp-pcl'], + 'pclxl' => ['application/vnd.hp-pclxl'], + 'pct' => ['image/x-pict'], + 'pcurl' => ['application/vnd.curl.pcurl'], + 'pcx' => ['image/vnd.zbrush.pcx', 'image/x-pcx'], + 'pdb' => ['application/vnd.palm', 'application/x-aportisdoc', 'application/x-ms-pdb', 'application/x-palm-database', 'application/x-pilot', 'chemical/x-pdb'], + 'pdc' => ['application/x-aportisdoc'], + 'pde' => ['text/x-processing'], + 'pdf' => ['application/pdf', 'application/acrobat', 'application/nappdf', 'application/x-pdf', 'image/pdf'], + 'pdf.bz2' => ['application/x-bzpdf'], + 'pdf.gz' => ['application/x-gzpdf'], + 'pdf.lz' => ['application/x-lzpdf'], + 'pdf.xz' => ['application/x-xzpdf'], + 'pef' => ['image/x-pentax-pef'], + 'pem' => ['application/x-x509-ca-cert'], + 'perl' => ['application/x-perl', 'text/x-perl'], + 'pfa' => ['application/x-font-type1'], + 'pfb' => ['application/x-font-type1'], + 'pfm' => ['application/x-font-type1'], + 'pfr' => ['application/font-tdpfr', 'application/vnd.truedoc'], + 'pfx' => ['application/pkcs12', 'application/x-pkcs12'], + 'pgm' => ['image/x-portable-graymap'], + 'pgn' => ['application/vnd.chess-pgn', 'application/x-chess-pgn'], + 'pgp' => ['application/pgp', 'application/pgp-encrypted', 'application/pgp-keys', 'application/pgp-signature'], + 'php' => ['application/x-php', 'application/x-httpd-php'], + 'php3' => ['application/x-php'], + 'php4' => ['application/x-php'], + 'php5' => ['application/x-php'], + 'phps' => ['application/x-php'], + 'pic' => ['image/x-pict'], + 'pict' => ['image/x-pict'], + 'pict1' => ['image/x-pict'], + 'pict2' => ['image/x-pict'], + 'pk' => ['application/x-tex-pk'], + 'pkg' => ['application/x-xar'], + 'pki' => ['application/pkixcmp'], + 'pkipath' => ['application/pkix-pkipath'], + 'pkpass' => ['application/vnd.apple.pkpass'], + 'pkr' => ['application/pgp-keys'], + 'pl' => ['application/x-perl', 'text/x-perl'], + 'pla' => ['audio/x-iriver-pla'], + 'plb' => ['application/vnd.3gpp.pic-bw-large'], + 'plc' => ['application/vnd.mobius.plc'], + 'plf' => ['application/vnd.pocketlearn'], + 'pln' => ['application/x-planperfect'], + 'pls' => ['application/pls', 'application/pls+xml', 'audio/scpls', 'audio/x-scpls'], + 'pm' => ['application/x-pagemaker', 'application/x-perl', 'text/x-perl'], + 'pm6' => ['application/x-pagemaker'], + 'pmd' => ['application/x-pagemaker'], + 'pml' => ['application/vnd.ctc-posml'], + 'png' => ['image/png', 'image/apng', 'image/vnd.mozilla.apng'], + 'pnm' => ['image/x-portable-anymap'], + 'pntg' => ['image/x-macpaint'], + 'po' => ['application/x-gettext', 'text/x-gettext-translation', 'text/x-po'], + 'pod' => ['application/x-perl', 'text/x-perl'], + 'por' => ['application/x-spss-por'], + 'portpkg' => ['application/vnd.macports.portpkg'], + 'pot' => ['application/mspowerpoint', 'application/powerpoint', 'application/vnd.ms-powerpoint', 'application/x-mspowerpoint', 'text/x-gettext-translation-template', 'text/x-pot'], + 'potm' => ['application/vnd.ms-powerpoint.template.macroenabled.12'], + 'potx' => ['application/vnd.openxmlformats-officedocument.presentationml.template'], + 'ppam' => ['application/vnd.ms-powerpoint.addin.macroenabled.12'], + 'ppd' => ['application/vnd.cups-ppd'], + 'ppm' => ['image/x-portable-pixmap'], + 'pps' => ['application/mspowerpoint', 'application/powerpoint', 'application/vnd.ms-powerpoint', 'application/x-mspowerpoint'], + 'ppsm' => ['application/vnd.ms-powerpoint.slideshow.macroenabled.12'], + 'ppsx' => ['application/vnd.openxmlformats-officedocument.presentationml.slideshow'], + 'ppt' => ['application/vnd.ms-powerpoint', 'application/mspowerpoint', 'application/powerpoint', 'application/x-mspowerpoint'], + 'pptm' => ['application/vnd.ms-powerpoint.presentation.macroenabled.12'], + 'pptx' => ['application/vnd.openxmlformats-officedocument.presentationml.presentation'], + 'ppz' => ['application/mspowerpoint', 'application/powerpoint', 'application/vnd.ms-powerpoint', 'application/x-mspowerpoint'], + 'pqa' => ['application/vnd.palm', 'application/x-palm-database'], + 'prc' => ['application/vnd.palm', 'application/x-mobipocket-ebook', 'application/x-palm-database', 'application/x-pilot'], + 'pre' => ['application/vnd.lotus-freelance'], + 'prf' => ['application/pics-rules'], + 'provx' => ['application/provenance+xml'], + 'ps' => ['application/postscript'], + 'ps.bz2' => ['application/x-bzpostscript'], + 'ps.gz' => ['application/x-gzpostscript'], + 'ps1' => ['application/x-powershell'], + 'psb' => ['application/vnd.3gpp.pic-bw-small'], + 'psd' => ['application/photoshop', 'application/x-photoshop', 'image/photoshop', 'image/psd', 'image/vnd.adobe.photoshop', 'image/x-photoshop', 'image/x-psd'], + 'psf' => ['application/x-font-linux-psf', 'audio/x-psf'], + 'psf.gz' => ['application/x-gz-font-linux-psf'], + 'psflib' => ['audio/x-psflib'], + 'psid' => ['audio/prs.sid'], + 'pskcxml' => ['application/pskc+xml'], + 'psw' => ['application/x-pocket-word'], + 'pti' => ['image/prs.pti'], + 'ptid' => ['application/vnd.pvi.ptid1'], + 'pub' => ['application/vnd.ms-publisher', 'application/x-mspublisher'], + 'pvb' => ['application/vnd.3gpp.pic-bw-var'], + 'pw' => ['application/x-pw'], + 'pwn' => ['application/vnd.3m.post-it-notes'], + 'py' => ['text/x-python', 'text/x-python3'], + 'py3' => ['text/x-python3'], + 'py3x' => ['text/x-python3'], + 'pya' => ['audio/vnd.ms-playready.media.pya'], + 'pyc' => ['application/x-python-bytecode'], + 'pyi' => ['text/x-python3'], + 'pyo' => ['application/x-python-bytecode'], + 'pys' => ['application/x-pyspread-bz-spreadsheet'], + 'pysu' => ['application/x-pyspread-spreadsheet'], + 'pyv' => ['video/vnd.ms-playready.media.pyv'], + 'pyx' => ['text/x-python'], + 'qam' => ['application/vnd.epson.quickanime'], + 'qbo' => ['application/vnd.intu.qbo'], + 'qcow' => ['application/x-qemu-disk'], + 'qcow2' => ['application/x-qemu-disk'], + 'qd' => ['application/x-fd-file', 'application/x-raw-floppy-disk-image'], + 'qed' => ['application/x-qed-disk'], + 'qfx' => ['application/vnd.intu.qfx'], + 'qif' => ['application/x-qw', 'image/x-quicktime'], + 'qml' => ['text/x-qml'], + 'qmlproject' => ['text/x-qml'], + 'qmltypes' => ['text/x-qml'], + 'qoi' => ['image/qoi'], + 'qp' => ['application/x-qpress'], + 'qps' => ['application/vnd.publishare-delta-tree'], + 'qpw' => ['application/x-quattropro'], + 'qs' => ['application/sparql-query'], + 'qt' => ['video/quicktime'], + 'qti' => ['application/x-qtiplot'], + 'qti.gz' => ['application/x-qtiplot'], + 'qtif' => ['image/x-quicktime'], + 'qtl' => ['application/x-quicktime-media-link', 'application/x-quicktimeplayer'], + 'qtvr' => ['video/quicktime'], + 'qwd' => ['application/vnd.quark.quarkxpress'], + 'qwt' => ['application/vnd.quark.quarkxpress'], + 'qxb' => ['application/vnd.quark.quarkxpress'], + 'qxd' => ['application/vnd.quark.quarkxpress'], + 'qxl' => ['application/vnd.quark.quarkxpress'], + 'qxt' => ['application/vnd.quark.quarkxpress'], + 'ra' => ['audio/vnd.m-realaudio', 'audio/vnd.rn-realaudio', 'audio/x-pn-realaudio', 'audio/x-realaudio'], + 'raf' => ['image/x-fuji-raf'], + 'ram' => ['application/ram', 'audio/x-pn-realaudio'], + 'raml' => ['application/raml+yaml'], + 'rapd' => ['application/route-apd+xml'], + 'rar' => ['application/x-rar-compressed', 'application/vnd.rar', 'application/x-rar'], + 'ras' => ['image/x-cmu-raster'], + 'raw' => ['image/x-panasonic-raw', 'image/x-panasonic-rw'], + 'raw-disk-image' => ['application/vnd.efi.img', 'application/x-raw-disk-image'], + 'raw-disk-image.xz' => ['application/x-raw-disk-image-xz-compressed'], + 'rax' => ['audio/vnd.m-realaudio', 'audio/vnd.rn-realaudio', 'audio/x-pn-realaudio'], + 'rb' => ['application/x-ruby'], + 'rcprofile' => ['application/vnd.ipunplugged.rcprofile'], + 'rdf' => ['application/rdf+xml', 'text/rdf'], + 'rdfs' => ['application/rdf+xml', 'text/rdf'], + 'rdz' => ['application/vnd.data-vision.rdz'], + 'reg' => ['text/x-ms-regedit'], + 'rej' => ['application/x-reject', 'text/x-reject'], + 'relo' => ['application/p2p-overlay+xml'], + 'rep' => ['application/vnd.businessobjects'], + 'res' => ['application/x-dtbresource+xml', 'application/x-godot-resource'], + 'rgb' => ['image/x-rgb'], + 'rif' => ['application/reginfo+xml'], + 'rip' => ['audio/vnd.rip'], + 'ris' => ['application/x-research-info-systems'], + 'rl' => ['application/resource-lists+xml'], + 'rlc' => ['image/vnd.fujixerox.edmics-rlc'], + 'rld' => ['application/resource-lists-diff+xml'], + 'rle' => ['image/rle'], + 'rm' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmi' => ['audio/midi'], + 'rmj' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmm' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmp' => ['audio/x-pn-realaudio-plugin'], + 'rms' => ['application/vnd.jcp.javame.midlet-rms', 'application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmvb' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmx' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rnc' => ['application/relax-ng-compact-syntax', 'application/x-rnc'], + 'rng' => ['application/xml', 'text/xml'], + 'roa' => ['application/rpki-roa'], + 'roff' => ['application/x-troff', 'text/troff', 'text/x-troff'], + 'ros' => ['text/x-common-lisp'], + 'rp' => ['image/vnd.rn-realpix'], + 'rp9' => ['application/vnd.cloanto.rp9'], + 'rpm' => ['application/x-redhat-package-manager', 'application/x-rpm'], + 'rpss' => ['application/vnd.nokia.radio-presets'], + 'rpst' => ['application/vnd.nokia.radio-preset'], + 'rq' => ['application/sparql-query'], + 'rs' => ['application/rls-services+xml', 'text/rust'], + 'rsat' => ['application/atsc-rsat+xml'], + 'rsd' => ['application/rsd+xml'], + 'rsheet' => ['application/urc-ressheet+xml'], + 'rss' => ['application/rss+xml', 'text/rss'], + 'rst' => ['text/x-rst'], + 'rt' => ['text/vnd.rn-realtext'], + 'rtf' => ['application/rtf', 'text/rtf'], + 'rtx' => ['text/richtext'], + 'run' => ['application/x-makeself'], + 'rusd' => ['application/route-usd+xml'], + 'rv' => ['video/vnd.rn-realvideo', 'video/x-real-video'], + 'rvx' => ['video/vnd.rn-realvideo', 'video/x-real-video'], + 'rw2' => ['image/x-panasonic-raw2', 'image/x-panasonic-rw2'], + 'rz' => ['application/x-rzip'], + 's' => ['text/x-asm'], + 's3m' => ['audio/s3m', 'audio/x-s3m'], + 'saf' => ['application/vnd.yamaha.smaf-audio'], + 'sage' => ['text/x-sagemath'], + 'sam' => ['application/x-amipro'], + 'sami' => ['application/x-sami'], + 'sap' => ['application/x-sap-file', 'application/x-thomson-sap-image'], + 'sass' => ['text/x-sass'], + 'sav' => ['application/x-spss-sav', 'application/x-spss-savefile'], + 'sbml' => ['application/sbml+xml'], + 'sc' => ['application/vnd.ibm.secure-container', 'text/x-scala'], + 'scala' => ['text/x-scala'], + 'scd' => ['application/x-msschedule'], + 'scm' => ['application/vnd.lotus-screencam', 'text/x-scheme'], + 'scn' => ['application/x-godot-scene'], + 'scope' => ['text/x-systemd-unit'], + 'scq' => ['application/scvp-cv-request'], + 'scr' => ['application/vnd.microsoft.portable-executable', 'application/x-ms-dos-executable', 'application/x-ms-ne-executable', 'application/x-msdownload'], + 'scs' => ['application/scvp-cv-response'], + 'scss' => ['text/x-scss'], + 'scurl' => ['text/vnd.curl.scurl'], + 'sda' => ['application/vnd.stardivision.draw'], + 'sdc' => ['application/vnd.stardivision.calc'], + 'sdd' => ['application/vnd.stardivision.impress'], + 'sdkd' => ['application/vnd.solent.sdkm+xml'], + 'sdkm' => ['application/vnd.solent.sdkm+xml'], + 'sdp' => ['application/sdp', 'application/vnd.sdp', 'application/vnd.stardivision.impress', 'application/x-sdp'], + 'sds' => ['application/vnd.stardivision.chart'], + 'sdw' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], + 'sea' => ['application/x-sea'], + 'see' => ['application/vnd.seemail'], + 'seed' => ['application/vnd.fdsn.seed'], + 'sema' => ['application/vnd.sema'], + 'semd' => ['application/vnd.semd'], + 'semf' => ['application/vnd.semf'], + 'senmlx' => ['application/senml+xml'], + 'sensmlx' => ['application/sensml+xml'], + 'ser' => ['application/java-serialized-object'], + 'service' => ['text/x-dbus-service', 'text/x-systemd-unit'], + 'setpay' => ['application/set-payment-initiation'], + 'setreg' => ['application/set-registration-initiation'], + 'sfc' => ['application/vnd.nintendo.snes.rom', 'application/x-snes-rom'], + 'sfd-hdstx' => ['application/vnd.hydrostatix.sof-data'], + 'sfs' => ['application/vnd.spotfire.sfs'], + 'sfv' => ['text/x-sfv'], + 'sg' => ['application/x-sg1000-rom'], + 'sgb' => ['application/x-gameboy-rom'], + 'sgd' => ['application/x-genesis-rom'], + 'sgf' => ['application/x-go-sgf'], + 'sgi' => ['image/sgi', 'image/x-sgi'], + 'sgl' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], + 'sgm' => ['text/sgml'], + 'sgml' => ['text/sgml'], + 'sh' => ['application/x-sh', 'application/x-shellscript', 'text/x-sh'], + 'shape' => ['application/x-dia-shape'], + 'shar' => ['application/x-shar'], + 'shex' => ['text/shex'], + 'shf' => ['application/shf+xml'], + 'shn' => ['application/x-shorten', 'audio/x-shorten'], + 'shtml' => ['text/html'], + 'siag' => ['application/x-siag'], + 'sid' => ['audio/prs.sid', 'image/x-mrsid-image'], + 'sieve' => ['application/sieve'], + 'sig' => ['application/pgp-signature'], + 'sik' => ['application/x-trash'], + 'sil' => ['audio/silk'], + 'silo' => ['model/mesh'], + 'sis' => ['application/vnd.symbian.install'], + 'sisx' => ['application/vnd.symbian.install', 'x-epoc/x-sisx-app'], + 'sit' => ['application/x-stuffit', 'application/stuffit', 'application/x-sit'], + 'sitx' => ['application/x-sitx', 'application/x-stuffitx'], + 'siv' => ['application/sieve'], + 'sk' => ['image/x-skencil'], + 'sk1' => ['image/x-skencil'], + 'skd' => ['application/vnd.koan'], + 'skm' => ['application/vnd.koan'], + 'skp' => ['application/vnd.koan'], + 'skr' => ['application/pgp-keys'], + 'skt' => ['application/vnd.koan'], + 'sldm' => ['application/vnd.ms-powerpoint.slide.macroenabled.12'], + 'sldx' => ['application/vnd.openxmlformats-officedocument.presentationml.slide'], + 'slice' => ['text/x-systemd-unit'], + 'slim' => ['text/slim'], + 'slk' => ['text/spreadsheet'], + 'slm' => ['text/slim'], + 'sls' => ['application/route-s-tsid+xml'], + 'slt' => ['application/vnd.epson.salt'], + 'sm' => ['application/vnd.stepmania.stepchart'], + 'smaf' => ['application/vnd.smaf', 'application/x-smaf'], + 'smc' => ['application/vnd.nintendo.snes.rom', 'application/x-snes-rom'], + 'smd' => ['application/vnd.stardivision.mail', 'application/x-genesis-rom'], + 'smf' => ['application/vnd.stardivision.math'], + 'smi' => ['application/smil', 'application/smil+xml', 'application/x-sami'], + 'smil' => ['application/smil', 'application/smil+xml'], + 'smk' => ['video/vnd.radgamettools.smacker'], + 'sml' => ['application/smil', 'application/smil+xml'], + 'sms' => ['application/x-sms-rom'], + 'smv' => ['video/x-smv'], + 'smzip' => ['application/vnd.stepmania.package'], + 'snap' => ['application/vnd.snap'], + 'snd' => ['audio/basic'], + 'snf' => ['application/x-font-snf'], + 'so' => ['application/x-sharedlib'], + 'socket' => ['text/x-systemd-unit'], + 'spc' => ['application/x-pkcs7-certificates'], + 'spd' => ['application/x-font-speedo'], + 'spdx' => ['text/spdx'], + 'spec' => ['text/x-rpm-spec'], + 'spf' => ['application/vnd.yamaha.smaf-phrase'], + 'spl' => ['application/futuresplash', 'application/vnd.adobe.flash.movie', 'application/x-futuresplash', 'application/x-shockwave-flash'], + 'spm' => ['application/x-source-rpm'], + 'spot' => ['text/vnd.in3d.spot'], + 'spp' => ['application/scvp-vp-response'], + 'spq' => ['application/scvp-vp-request'], + 'spx' => ['application/x-apple-systemprofiler+xml', 'audio/ogg', 'audio/x-speex', 'audio/x-speex+ogg'], + 'sql' => ['application/sql', 'application/x-sql', 'text/x-sql'], + 'sqlite2' => ['application/x-sqlite2'], + 'sqlite3' => ['application/vnd.sqlite3', 'application/x-sqlite3'], + 'sqsh' => ['application/vnd.squashfs'], + 'sr2' => ['image/x-sony-sr2'], + 'src' => ['application/x-wais-source'], + 'src.rpm' => ['application/x-source-rpm'], + 'srf' => ['image/x-sony-srf'], + 'srt' => ['application/x-srt', 'application/x-subrip'], + 'sru' => ['application/sru+xml'], + 'srx' => ['application/sparql-results+xml'], + 'ss' => ['text/x-scheme'], + 'ssa' => ['text/x-ssa'], + 'ssdl' => ['application/ssdl+xml'], + 'sse' => ['application/vnd.kodak-descriptor'], + 'ssf' => ['application/vnd.epson.ssf'], + 'ssml' => ['application/ssml+xml'], + 'st' => ['application/vnd.sailingtracker.track'], + 'stc' => ['application/vnd.sun.xml.calc.template'], + 'std' => ['application/vnd.sun.xml.draw.template'], + 'stf' => ['application/vnd.wt.stf'], + 'sti' => ['application/vnd.sun.xml.impress.template'], + 'stk' => ['application/hyperstudio'], + 'stl' => ['application/vnd.ms-pki.stl', 'model/stl', 'model/x.stl-ascii', 'model/x.stl-binary'], + 'stm' => ['audio/x-stm'], + 'stpx' => ['model/step+xml'], + 'stpxz' => ['model/step-xml+zip'], + 'stpz' => ['model/step+zip'], + 'str' => ['application/vnd.pg.format'], + 'stw' => ['application/vnd.sun.xml.writer.template'], + 'sty' => ['application/x-tex', 'text/x-tex'], + 'styl' => ['text/stylus'], + 'stylus' => ['text/stylus'], + 'sub' => ['image/vnd.dvb.subtitle', 'text/vnd.dvb.subtitle', 'text/x-microdvd', 'text/x-mpsub', 'text/x-subviewer'], + 'sun' => ['image/x-sun-raster'], + 'sus' => ['application/vnd.sus-calendar'], + 'susp' => ['application/vnd.sus-calendar'], + 'sv' => ['text/x-svsrc'], + 'sv4cpio' => ['application/x-sv4cpio'], + 'sv4crc' => ['application/x-sv4crc'], + 'svc' => ['application/vnd.dvb.service'], + 'svd' => ['application/vnd.svd'], + 'svg' => ['image/svg+xml', 'image/svg'], + 'svg.gz' => ['image/svg+xml-compressed'], + 'svgz' => ['image/svg+xml', 'image/svg+xml-compressed'], + 'svh' => ['text/x-svhdr'], + 'swa' => ['application/x-director'], + 'swap' => ['text/x-systemd-unit'], + 'swf' => ['application/futuresplash', 'application/vnd.adobe.flash.movie', 'application/x-shockwave-flash'], + 'swi' => ['application/vnd.aristanetworks.swi'], + 'swidtag' => ['application/swid+xml'], + 'swm' => ['application/x-ms-wim'], + 'sxc' => ['application/vnd.sun.xml.calc'], + 'sxd' => ['application/vnd.sun.xml.draw'], + 'sxg' => ['application/vnd.sun.xml.writer.global'], + 'sxi' => ['application/vnd.sun.xml.impress'], + 'sxm' => ['application/vnd.sun.xml.math'], + 'sxw' => ['application/vnd.sun.xml.writer'], + 'sylk' => ['text/spreadsheet'], + 'sys' => ['application/vnd.microsoft.portable-executable'], + 't' => ['application/x-perl', 'application/x-troff', 'text/troff', 'text/x-perl', 'text/x-troff'], + 't2t' => ['text/x-txt2tags'], + 't3' => ['application/x-t3vm-image'], + 't38' => ['image/t38'], + 'taglet' => ['application/vnd.mynfc'], + 'tak' => ['audio/x-tak'], + 'tao' => ['application/vnd.tao.intent-module-archive'], + 'tap' => ['image/vnd.tencent.tap'], + 'tar' => ['application/x-tar', 'application/x-gtar'], + 'tar.Z' => ['application/x-tarz'], + 'tar.bz' => ['application/x-bzip1-compressed-tar'], + 'tar.bz2' => ['application/x-bzip-compressed-tar', 'application/x-bzip2-compressed-tar'], + 'tar.bz3' => ['application/x-bzip3-compressed-tar'], + 'tar.gz' => ['application/x-compressed-tar'], + 'tar.lrz' => ['application/x-lrzip-compressed-tar'], + 'tar.lz' => ['application/x-lzip-compressed-tar'], + 'tar.lz4' => ['application/x-lz4-compressed-tar'], + 'tar.lzma' => ['application/x-lzma-compressed-tar'], + 'tar.lzo' => ['application/x-tzo'], + 'tar.rz' => ['application/x-rzip-compressed-tar'], + 'tar.xz' => ['application/x-xz-compressed-tar'], + 'tar.zst' => ['application/x-zstd-compressed-tar'], + 'target' => ['text/x-systemd-unit'], + 'taz' => ['application/x-tarz'], + 'tb2' => ['application/x-bzip-compressed-tar', 'application/x-bzip2-compressed-tar'], + 'tbz' => ['application/x-bzip1-compressed-tar'], + 'tbz2' => ['application/x-bzip-compressed-tar', 'application/x-bzip2-compressed-tar'], + 'tbz3' => ['application/x-bzip3-compressed-tar'], + 'tcap' => ['application/vnd.3gpp2.tcap'], + 'tcl' => ['application/x-tcl', 'text/tcl', 'text/x-tcl'], + 'td' => ['application/urc-targetdesc+xml'], + 'teacher' => ['application/vnd.smart.teacher'], + 'tei' => ['application/tei+xml'], + 'teicorpus' => ['application/tei+xml'], + 'tex' => ['application/x-tex', 'text/x-tex'], + 'texi' => ['application/x-texinfo', 'text/x-texinfo'], + 'texinfo' => ['application/x-texinfo', 'text/x-texinfo'], + 'text' => ['text/plain'], + 'tfi' => ['application/thraud+xml'], + 'tfm' => ['application/x-tex-tfm'], + 'tfx' => ['image/tiff-fx'], + 'tga' => ['application/tga', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], + 'tgz' => ['application/x-compressed-tar'], + 'theme' => ['application/x-theme'], + 'themepack' => ['application/x-windows-themepack'], + 'thmx' => ['application/vnd.ms-officetheme'], + 'tif' => ['image/tiff'], + 'tiff' => ['image/tiff'], + 'timer' => ['text/x-systemd-unit'], + 'tk' => ['application/x-tcl', 'text/tcl', 'text/x-tcl'], + 'tlrz' => ['application/x-lrzip-compressed-tar'], + 'tlz' => ['application/x-lzma-compressed-tar'], + 'tmo' => ['application/vnd.tmobile-livetv'], + 'tmx' => ['application/x-tiled-tmx'], + 'tnef' => ['application/ms-tnef', 'application/vnd.ms-tnef'], + 'tnf' => ['application/ms-tnef', 'application/vnd.ms-tnef'], + 'toc' => ['application/x-cdrdao-toc'], + 'toml' => ['application/toml'], + 'torrent' => ['application/x-bittorrent'], + 'tpic' => ['application/tga', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], + 'tpl' => ['application/vnd.groove-tool-template'], + 'tpt' => ['application/vnd.trid.tpt'], + 'tr' => ['application/x-troff', 'text/troff', 'text/x-troff'], + 'tra' => ['application/vnd.trueapp'], + 'tres' => ['application/x-godot-resource'], + 'trig' => ['application/trig', 'application/x-trig'], + 'trm' => ['application/x-msterminal'], + 'trz' => ['application/x-rzip-compressed-tar'], + 'ts' => ['application/x-linguist', 'text/vnd.qt.linguist', 'text/vnd.trolltech.linguist', 'video/mp2t'], + 'tscn' => ['application/x-godot-scene'], + 'tsd' => ['application/timestamped-data'], + 'tsv' => ['text/tab-separated-values'], + 'tsx' => ['application/x-tiled-tsx'], + 'tta' => ['audio/tta', 'audio/x-tta'], + 'ttc' => ['font/collection'], + 'ttf' => ['application/x-font-truetype', 'application/x-font-ttf', 'font/ttf'], + 'ttl' => ['text/turtle'], + 'ttml' => ['application/ttml+xml'], + 'ttx' => ['application/x-font-ttx'], + 'twd' => ['application/vnd.simtech-mindmapper'], + 'twds' => ['application/vnd.simtech-mindmapper'], + 'twig' => ['text/x-twig'], + 'txd' => ['application/vnd.genomatix.tuxedo'], + 'txf' => ['application/vnd.mobius.txf'], + 'txt' => ['text/plain'], + 'txz' => ['application/x-xz-compressed-tar'], + 'typ' => ['text/x-typst'], + 'tzo' => ['application/x-tzo'], + 'tzst' => ['application/x-zstd-compressed-tar'], + 'u32' => ['application/x-authorware-bin'], + 'u8dsn' => ['message/global-delivery-status'], + 'u8hdr' => ['message/global-headers'], + 'u8mdn' => ['message/global-disposition-notification'], + 'u8msg' => ['message/global'], + 'ubj' => ['application/ubjson'], + 'udeb' => ['application/vnd.debian.binary-package', 'application/x-deb', 'application/x-debian-package'], + 'ufd' => ['application/vnd.ufdl'], + 'ufdl' => ['application/vnd.ufdl'], + 'ufraw' => ['application/x-ufraw'], + 'ui' => ['application/x-designer', 'application/x-gtk-builder'], + 'uil' => ['text/x-uil'], + 'ult' => ['audio/x-mod'], + 'ulx' => ['application/x-glulx'], + 'umj' => ['application/vnd.umajin'], + 'unf' => ['application/x-nes-rom'], + 'uni' => ['audio/x-mod'], + 'unif' => ['application/x-nes-rom'], + 'unityweb' => ['application/vnd.unity'], + 'uoml' => ['application/vnd.uoml+xml'], + 'uri' => ['text/uri-list'], + 'uris' => ['text/uri-list'], + 'url' => ['application/x-mswinurl'], + 'urls' => ['text/uri-list'], + 'usdz' => ['model/vnd.usdz+zip'], + 'ustar' => ['application/x-ustar'], + 'utz' => ['application/vnd.uiq.theme'], + 'uu' => ['text/x-uuencode'], + 'uue' => ['text/x-uuencode', 'zz-application/zz-winassoc-uu'], + 'uva' => ['audio/vnd.dece.audio'], + 'uvd' => ['application/vnd.dece.data'], + 'uvf' => ['application/vnd.dece.data'], + 'uvg' => ['image/vnd.dece.graphic'], + 'uvh' => ['video/vnd.dece.hd'], + 'uvi' => ['image/vnd.dece.graphic'], + 'uvm' => ['video/vnd.dece.mobile'], + 'uvp' => ['video/vnd.dece.pd'], + 'uvs' => ['video/vnd.dece.sd'], + 'uvt' => ['application/vnd.dece.ttml+xml'], + 'uvu' => ['video/vnd.uvvu.mp4'], + 'uvv' => ['video/vnd.dece.video'], + 'uvva' => ['audio/vnd.dece.audio'], + 'uvvd' => ['application/vnd.dece.data'], + 'uvvf' => ['application/vnd.dece.data'], + 'uvvg' => ['image/vnd.dece.graphic'], + 'uvvh' => ['video/vnd.dece.hd'], + 'uvvi' => ['image/vnd.dece.graphic'], + 'uvvm' => ['video/vnd.dece.mobile'], + 'uvvp' => ['video/vnd.dece.pd'], + 'uvvs' => ['video/vnd.dece.sd'], + 'uvvt' => ['application/vnd.dece.ttml+xml'], + 'uvvu' => ['video/vnd.uvvu.mp4'], + 'uvvv' => ['video/vnd.dece.video'], + 'uvvx' => ['application/vnd.dece.unspecified'], + 'uvvz' => ['application/vnd.dece.zip'], + 'uvx' => ['application/vnd.dece.unspecified'], + 'uvz' => ['application/vnd.dece.zip'], + 'v' => ['text/x-verilog'], + 'v64' => ['application/x-n64-rom'], + 'vala' => ['text/x-vala'], + 'vapi' => ['text/x-vala'], + 'vb' => ['application/x-virtual-boy-rom', 'text/x-vb'], + 'vbe' => ['text/vbscript.encode'], + 'vbox' => ['application/x-virtualbox-vbox'], + 'vbox-extpack' => ['application/x-virtualbox-vbox-extpack'], + 'vbs' => ['text/vbs', 'text/vbscript'], + 'vcard' => ['text/directory', 'text/vcard', 'text/x-vcard'], + 'vcd' => ['application/x-cdlink'], + 'vcf' => ['text/x-vcard', 'text/directory', 'text/vcard'], + 'vcg' => ['application/vnd.groove-vcard'], + 'vcs' => ['application/ics', 'text/calendar', 'text/x-vcalendar'], + 'vct' => ['text/directory', 'text/vcard', 'text/x-vcard'], + 'vcx' => ['application/vnd.vcx'], + 'vda' => ['application/tga', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], + 'vdi' => ['application/x-vdi-disk', 'application/x-virtualbox-vdi'], + 'vds' => ['model/vnd.sap.vds'], + 'vhd' => ['application/x-vhd-disk', 'application/x-virtualbox-vhd', 'text/x-vhdl'], + 'vhdl' => ['text/x-vhdl'], + 'vhdx' => ['application/x-vhdx-disk', 'application/x-virtualbox-vhdx'], + 'vis' => ['application/vnd.visionary'], + 'viv' => ['video/vivo', 'video/vnd.vivo'], + 'vivo' => ['video/vivo', 'video/vnd.vivo'], + 'vlc' => ['application/m3u', 'audio/m3u', 'audio/mpegurl', 'audio/x-m3u', 'audio/x-mp3-playlist', 'audio/x-mpegurl'], + 'vmdk' => ['application/x-virtualbox-vmdk', 'application/x-vmdk-disk'], + 'vob' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2', 'video/x-ms-vob'], + 'voc' => ['audio/x-voc'], + 'vor' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], + 'vox' => ['application/x-authorware-bin'], + 'vpc' => ['application/x-vhd-disk', 'application/x-virtualbox-vhd'], + 'vrm' => ['model/vrml'], + 'vrml' => ['model/vrml'], + 'vsd' => ['application/vnd.visio'], + 'vsdm' => ['application/vnd.ms-visio.drawing.macroenabled.main+xml'], + 'vsdx' => ['application/vnd.ms-visio.drawing.main+xml'], + 'vsf' => ['application/vnd.vsf'], + 'vss' => ['application/vnd.visio'], + 'vssm' => ['application/vnd.ms-visio.stencil.macroenabled.main+xml'], + 'vssx' => ['application/vnd.ms-visio.stencil.main+xml'], + 'vst' => ['application/tga', 'application/vnd.visio', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], + 'vstm' => ['application/vnd.ms-visio.template.macroenabled.main+xml'], + 'vstx' => ['application/vnd.ms-visio.template.main+xml'], + 'vsw' => ['application/vnd.visio'], + 'vtf' => ['image/vnd.valve.source.texture'], + 'vtt' => ['text/vtt'], + 'vtu' => ['model/vnd.vtu'], + 'vxml' => ['application/voicexml+xml'], + 'w3d' => ['application/x-director'], + 'wad' => ['application/x-doom', 'application/x-doom-wad', 'application/x-wii-wad'], + 'wadl' => ['application/vnd.sun.wadl+xml'], + 'war' => ['application/java-archive'], + 'wasm' => ['application/wasm'], + 'wav' => ['audio/wav', 'audio/vnd.wave', 'audio/wave', 'audio/x-wav'], + 'wax' => ['application/x-ms-asx', 'audio/x-ms-asx', 'audio/x-ms-wax', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], + 'wb1' => ['application/x-quattropro'], + 'wb2' => ['application/x-quattropro'], + 'wb3' => ['application/x-quattropro'], + 'wbmp' => ['image/vnd.wap.wbmp'], + 'wbs' => ['application/vnd.criticaltools.wbs+xml'], + 'wbxml' => ['application/vnd.wap.wbxml'], + 'wcm' => ['application/vnd.ms-works'], + 'wdb' => ['application/vnd.ms-works'], + 'wdp' => ['image/jxr', 'image/vnd.ms-photo'], + 'weba' => ['audio/webm'], + 'webapp' => ['application/x-web-app-manifest+json'], + 'webm' => ['video/webm'], + 'webmanifest' => ['application/manifest+json'], + 'webp' => ['image/webp'], + 'wg' => ['application/vnd.pmi.widget'], + 'wgt' => ['application/widget'], + 'wif' => ['application/watcherinfo+xml'], + 'wim' => ['application/x-ms-wim'], + 'wk1' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + 'wk3' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + 'wk4' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + 'wkdownload' => ['application/x-partial-download'], + 'wks' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/vnd.ms-works', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + 'wm' => ['video/x-ms-wm'], + 'wma' => ['audio/x-ms-wma', 'audio/wma'], + 'wmd' => ['application/x-ms-wmd'], + 'wmf' => ['application/wmf', 'application/x-msmetafile', 'application/x-wmf', 'image/wmf', 'image/x-win-metafile', 'image/x-wmf'], + 'wml' => ['text/vnd.wap.wml'], + 'wmlc' => ['application/vnd.wap.wmlc'], + 'wmls' => ['text/vnd.wap.wmlscript'], + 'wmlsc' => ['application/vnd.wap.wmlscriptc'], + 'wmv' => ['audio/x-ms-wmv', 'video/x-ms-wmv'], + 'wmx' => ['application/x-ms-asx', 'audio/x-ms-asx', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], + 'wmz' => ['application/x-ms-wmz', 'application/x-msmetafile'], + 'woff' => ['application/font-woff', 'application/x-font-woff', 'font/woff'], + 'woff2' => ['font/woff2'], + 'wp' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wp4' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wp5' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wp6' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wpd' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wpg' => ['application/x-wpg'], + 'wpl' => ['application/vnd.ms-wpl'], + 'wpp' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wps' => ['application/vnd.ms-works'], + 'wqd' => ['application/vnd.wqd'], + 'wri' => ['application/x-mswrite'], + 'wrl' => ['model/vrml'], + 'ws' => ['application/x-wonderswan-rom'], + 'wsc' => ['application/x-wonderswan-color-rom', 'message/vnd.wfa.wsc'], + 'wsdl' => ['application/wsdl+xml'], + 'wsgi' => ['text/x-python'], + 'wspolicy' => ['application/wspolicy+xml'], + 'wtb' => ['application/vnd.webturbo'], + 'wv' => ['audio/x-wavpack'], + 'wvc' => ['audio/x-wavpack-correction'], + 'wvp' => ['audio/x-wavpack'], + 'wvx' => ['application/x-ms-asx', 'audio/x-ms-asx', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], + 'wwf' => ['application/wwf', 'application/x-wwf'], + 'x32' => ['application/x-authorware-bin'], + 'x3d' => ['model/x3d+xml'], + 'x3db' => ['model/x3d+binary', 'model/x3d+fastinfoset'], + 'x3dbz' => ['model/x3d+binary'], + 'x3dv' => ['model/x3d+vrml', 'model/x3d-vrml'], + 'x3dvz' => ['model/x3d+vrml'], + 'x3dz' => ['model/x3d+xml'], + 'x3f' => ['image/x-sigma-x3f'], + 'x_b' => ['model/vnd.parasolid.transmit.binary'], + 'x_t' => ['model/vnd.parasolid.transmit.text'], + 'xac' => ['application/x-gnucash'], + 'xaml' => ['application/xaml+xml'], + 'xap' => ['application/x-silverlight-app'], + 'xar' => ['application/vnd.xara', 'application/x-xar'], + 'xav' => ['application/xcap-att+xml'], + 'xbap' => ['application/x-ms-xbap'], + 'xbd' => ['application/vnd.fujixerox.docuworks.binder'], + 'xbel' => ['application/x-xbel'], + 'xbl' => ['application/xml', 'text/xml'], + 'xbm' => ['image/x-xbitmap'], + 'xca' => ['application/xcap-caps+xml'], + 'xcf' => ['image/x-xcf'], + 'xcf.bz2' => ['image/x-compressed-xcf'], + 'xcf.gz' => ['image/x-compressed-xcf'], + 'xcs' => ['application/calendar+xml'], + 'xdf' => ['application/mrb-consumer+xml', 'application/mrb-publish+xml', 'application/xcap-diff+xml'], + 'xdgapp' => ['application/vnd.flatpak', 'application/vnd.xdgapp'], + 'xdm' => ['application/vnd.syncml.dm+xml'], + 'xdp' => ['application/vnd.adobe.xdp+xml'], + 'xdssc' => ['application/dssc+xml'], + 'xdw' => ['application/vnd.fujixerox.docuworks'], + 'xel' => ['application/xcap-el+xml'], + 'xenc' => ['application/xenc+xml'], + 'xer' => ['application/patch-ops-error+xml', 'application/xcap-error+xml'], + 'xfdf' => ['application/vnd.adobe.xfdf'], + 'xfdl' => ['application/vnd.xfdl'], + 'xhe' => ['audio/usac'], + 'xht' => ['application/xhtml+xml'], + 'xhtml' => ['application/xhtml+xml'], + 'xhvml' => ['application/xv+xml'], + 'xi' => ['audio/x-xi'], + 'xif' => ['image/vnd.xiff'], + 'xla' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlam' => ['application/vnd.ms-excel.addin.macroenabled.12'], + 'xlc' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xld' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlf' => ['application/x-xliff', 'application/x-xliff+xml', 'application/xliff+xml'], + 'xliff' => ['application/x-xliff', 'application/xliff+xml'], + 'xll' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlm' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlr' => ['application/vnd.ms-works'], + 'xls' => ['application/vnd.ms-excel', 'application/msexcel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlsb' => ['application/vnd.ms-excel.sheet.binary.macroenabled.12'], + 'xlsm' => ['application/vnd.ms-excel.sheet.macroenabled.12'], + 'xlsx' => ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'], + 'xlt' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xltm' => ['application/vnd.ms-excel.template.macroenabled.12'], + 'xltx' => ['application/vnd.openxmlformats-officedocument.spreadsheetml.template'], + 'xlw' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xm' => ['audio/x-xm', 'audio/xm'], + 'xmf' => ['audio/x-xmf', 'audio/xmf'], + 'xmi' => ['text/x-xmi'], + 'xml' => ['application/xml', 'text/xml'], + 'xns' => ['application/xcap-ns+xml'], + 'xo' => ['application/vnd.olpc-sugar'], + 'xop' => ['application/xop+xml'], + 'xpi' => ['application/x-xpinstall'], + 'xpl' => ['application/xproc+xml'], + 'xpm' => ['image/x-xpixmap', 'image/x-xpm'], + 'xpr' => ['application/vnd.is-xpr'], + 'xps' => ['application/vnd.ms-xpsdocument', 'application/xps'], + 'xpw' => ['application/vnd.intercon.formnet'], + 'xpx' => ['application/vnd.intercon.formnet'], + 'xsd' => ['application/xml', 'text/xml'], + 'xsl' => ['application/xml', 'application/xslt+xml'], + 'xslfo' => ['text/x-xslfo'], + 'xslt' => ['application/xslt+xml'], + 'xsm' => ['application/vnd.syncml+xml'], + 'xspf' => ['application/x-xspf+xml', 'application/xspf+xml'], + 'xul' => ['application/vnd.mozilla.xul+xml'], + 'xvm' => ['application/xv+xml'], + 'xvml' => ['application/xv+xml'], + 'xwd' => ['image/x-xwindowdump'], + 'xyz' => ['chemical/x-xyz'], + 'xz' => ['application/x-xz'], + 'yaml' => ['application/yaml', 'application/x-yaml', 'text/x-yaml', 'text/yaml'], + 'yang' => ['application/yang'], + 'yin' => ['application/yin+xml'], + 'yml' => ['application/yaml', 'application/x-yaml', 'text/x-yaml', 'text/yaml'], + 'ymp' => ['text/x-suse-ymp'], + 'yt' => ['application/vnd.youtube.yt', 'video/vnd.youtube.yt'], + 'z1' => ['application/x-zmachine'], + 'z2' => ['application/x-zmachine'], + 'z3' => ['application/x-zmachine'], + 'z4' => ['application/x-zmachine'], + 'z5' => ['application/x-zmachine'], + 'z6' => ['application/x-zmachine'], + 'z64' => ['application/x-n64-rom'], + 'z7' => ['application/x-zmachine'], + 'z8' => ['application/x-zmachine'], + 'zabw' => ['application/x-abiword'], + 'zaz' => ['application/vnd.zzazz.deck+xml'], + 'zim' => ['application/x-openzim'], + 'zip' => ['application/zip', 'application/x-zip', 'application/x-zip-compressed'], + 'zipx' => ['application/x-zip', 'application/x-zip-compressed', 'application/zip'], + 'zir' => ['application/vnd.zul'], + 'zirz' => ['application/vnd.zul'], + 'zmm' => ['application/vnd.handheld-entertainment+xml'], + 'zoo' => ['application/x-zoo'], + 'zpaq' => ['application/x-zpaq'], + 'zsav' => ['application/x-spss-sav', 'application/x-spss-savefile'], + 'zst' => ['application/zstd'], + 'zz' => ['application/zlib'], + ]; +} diff --git a/tools/mailer/symfony/mime/MimeTypesInterface.php b/tools/mailer/symfony/mime/MimeTypesInterface.php new file mode 100644 index 000000000..17d45ad21 --- /dev/null +++ b/tools/mailer/symfony/mime/MimeTypesInterface.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * @author Fabien Potencier + */ +interface MimeTypesInterface extends MimeTypeGuesserInterface +{ + /** + * Gets the extensions for the given MIME type in decreasing order of preference. + * + * @return string[] + */ + public function getExtensions(string $mimeType): array; + + /** + * Gets the MIME types for the given extension in decreasing order of preference. + * + * @return string[] + */ + public function getMimeTypes(string $ext): array; +} diff --git a/tools/mailer/symfony/mime/Part/AbstractMultipartPart.php b/tools/mailer/symfony/mime/Part/AbstractMultipartPart.php new file mode 100644 index 000000000..1da0ddf33 --- /dev/null +++ b/tools/mailer/symfony/mime/Part/AbstractMultipartPart.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Header\Headers; + +/** + * @author Fabien Potencier + */ +abstract class AbstractMultipartPart extends AbstractPart +{ + private ?string $boundary = null; + private array $parts = []; + + public function __construct(AbstractPart ...$parts) + { + parent::__construct(); + + foreach ($parts as $part) { + $this->parts[] = $part; + } + } + + /** + * @return AbstractPart[] + */ + public function getParts(): array + { + return $this->parts; + } + + public function getMediaType(): string + { + return 'multipart'; + } + + public function getPreparedHeaders(): Headers + { + $headers = parent::getPreparedHeaders(); + $headers->setHeaderParameter('Content-Type', 'boundary', $this->getBoundary()); + + return $headers; + } + + public function bodyToString(): string + { + $parts = $this->getParts(); + $string = ''; + foreach ($parts as $part) { + $string .= '--'.$this->getBoundary()."\r\n".$part->toString()."\r\n"; + } + $string .= '--'.$this->getBoundary()."--\r\n"; + + return $string; + } + + public function bodyToIterable(): iterable + { + $parts = $this->getParts(); + foreach ($parts as $part) { + yield '--'.$this->getBoundary()."\r\n"; + yield from $part->toIterable(); + yield "\r\n"; + } + yield '--'.$this->getBoundary()."--\r\n"; + } + + public function asDebugString(): string + { + $str = parent::asDebugString(); + foreach ($this->getParts() as $part) { + $lines = explode("\n", $part->asDebugString()); + $str .= "\n └ ".array_shift($lines); + foreach ($lines as $line) { + $str .= "\n |".$line; + } + } + + return $str; + } + + private function getBoundary(): string + { + return $this->boundary ??= strtr(base64_encode(random_bytes(6)), '+/', '-_'); + } +} diff --git a/tools/mailer/symfony/mime/Part/AbstractPart.php b/tools/mailer/symfony/mime/Part/AbstractPart.php new file mode 100644 index 000000000..130106d68 --- /dev/null +++ b/tools/mailer/symfony/mime/Part/AbstractPart.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Header\Headers; + +/** + * @author Fabien Potencier + */ +abstract class AbstractPart +{ + private Headers $headers; + + public function __construct() + { + $this->headers = new Headers(); + } + + public function getHeaders(): Headers + { + return $this->headers; + } + + public function getPreparedHeaders(): Headers + { + $headers = clone $this->headers; + $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype()); + + return $headers; + } + + public function toString(): string + { + return $this->getPreparedHeaders()->toString()."\r\n".$this->bodyToString(); + } + + public function toIterable(): iterable + { + yield $this->getPreparedHeaders()->toString(); + yield "\r\n"; + yield from $this->bodyToIterable(); + } + + public function asDebugString(): string + { + return $this->getMediaType().'/'.$this->getMediaSubtype(); + } + + abstract public function bodyToString(): string; + + abstract public function bodyToIterable(): iterable; + + abstract public function getMediaType(): string; + + abstract public function getMediaSubtype(): string; +} diff --git a/tools/mailer/symfony/mime/Part/DataPart.php b/tools/mailer/symfony/mime/Part/DataPart.php new file mode 100644 index 000000000..b1c581e6f --- /dev/null +++ b/tools/mailer/symfony/mime/Part/DataPart.php @@ -0,0 +1,165 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Header\Headers; + +/** + * @author Fabien Potencier + */ +class DataPart extends TextPart +{ + /** @internal */ + protected array $_parent; + + private ?string $filename = null; + private string $mediaType; + private ?string $cid = null; + + /** + * @param resource|string|File $body Use a File instance to defer loading the file until rendering + */ + public function __construct($body, ?string $filename = null, ?string $contentType = null, ?string $encoding = null) + { + if ($body instanceof File && !$filename) { + $filename = $body->getFilename(); + } + + $contentType ??= $body instanceof File ? $body->getContentType() : 'application/octet-stream'; + [$this->mediaType, $subtype] = explode('/', $contentType); + + parent::__construct($body, null, $subtype, $encoding); + + if (null !== $filename) { + $this->filename = $filename; + $this->setName($filename); + } + $this->setDisposition('attachment'); + } + + public static function fromPath(string $path, ?string $name = null, ?string $contentType = null): self + { + return new self(new File($path), $name, $contentType); + } + + /** + * @return $this + */ + public function asInline(): static + { + return $this->setDisposition('inline'); + } + + /** + * @return $this + */ + public function setContentId(string $cid): static + { + if (!str_contains($cid, '@')) { + throw new InvalidArgumentException(sprintf('Invalid cid "%s".', $cid)); + } + + $this->cid = $cid; + + return $this; + } + + public function getContentId(): string + { + return $this->cid ?: $this->cid = $this->generateContentId(); + } + + public function hasContentId(): bool + { + return null !== $this->cid; + } + + public function getMediaType(): string + { + return $this->mediaType; + } + + public function getPreparedHeaders(): Headers + { + $headers = parent::getPreparedHeaders(); + + if (null !== $this->cid) { + $headers->setHeaderBody('Id', 'Content-ID', $this->cid); + } + + if (null !== $this->filename) { + $headers->setHeaderParameter('Content-Disposition', 'filename', $this->filename); + } + + return $headers; + } + + public function asDebugString(): string + { + $str = parent::asDebugString(); + if (null !== $this->filename) { + $str .= ' filename: '.$this->filename; + } + + return $str; + } + + public function getFilename(): ?string + { + return $this->filename; + } + + public function getContentType(): string + { + return implode('/', [$this->getMediaType(), $this->getMediaSubtype()]); + } + + private function generateContentId(): string + { + return bin2hex(random_bytes(16)).'@symfony'; + } + + public function __sleep(): array + { + // converts the body to a string + parent::__sleep(); + + $this->_parent = []; + foreach (['body', 'charset', 'subtype', 'disposition', 'name', 'encoding'] as $name) { + $r = new \ReflectionProperty(TextPart::class, $name); + $this->_parent[$name] = $r->getValue($this); + } + $this->_headers = $this->getHeaders(); + + return ['_headers', '_parent', 'filename', 'mediaType']; + } + + public function __wakeup(): void + { + $r = new \ReflectionProperty(AbstractPart::class, 'headers'); + $r->setValue($this, $this->_headers); + unset($this->_headers); + + if (!\is_array($this->_parent)) { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + foreach (['body', 'charset', 'subtype', 'disposition', 'name', 'encoding'] as $name) { + if (null !== $this->_parent[$name] && !\is_string($this->_parent[$name]) && !$this->_parent[$name] instanceof File) { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + $r = new \ReflectionProperty(TextPart::class, $name); + $r->setValue($this, $this->_parent[$name]); + } + unset($this->_parent); + } +} diff --git a/tools/mailer/symfony/mime/Part/File.php b/tools/mailer/symfony/mime/Part/File.php new file mode 100644 index 000000000..cd05a3dee --- /dev/null +++ b/tools/mailer/symfony/mime/Part/File.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\MimeTypes; + +/** + * @author Fabien Potencier + */ +class File +{ + private static MimeTypes $mimeTypes; + + public function __construct( + private string $path, + private ?string $filename = null, + ) { + } + + public function getPath(): string + { + return $this->path; + } + + public function getContentType(): string + { + $ext = strtolower(pathinfo($this->path, \PATHINFO_EXTENSION)); + self::$mimeTypes ??= new MimeTypes(); + + return self::$mimeTypes->getMimeTypes($ext)[0] ?? 'application/octet-stream'; + } + + public function getSize(): int + { + return filesize($this->path); + } + + public function getFilename(): string + { + return $this->filename ??= basename($this->getPath()); + } +} diff --git a/tools/mailer/symfony/mime/Part/MessagePart.php b/tools/mailer/symfony/mime/Part/MessagePart.php new file mode 100644 index 000000000..6a4c49453 --- /dev/null +++ b/tools/mailer/symfony/mime/Part/MessagePart.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +/** + * @final + * + * @author Fabien Potencier + */ +class MessagePart extends DataPart +{ + public function __construct( + private RawMessage $message, + ) { + if ($message instanceof Message) { + $name = $message->getHeaders()->getHeaderBody('Subject').'.eml'; + } else { + $name = 'email.eml'; + } + parent::__construct('', $name); + } + + public function getMediaType(): string + { + return 'message'; + } + + public function getMediaSubtype(): string + { + return 'rfc822'; + } + + public function getBody(): string + { + return $this->message->toString(); + } + + public function bodyToString(): string + { + return $this->getBody(); + } + + public function bodyToIterable(): iterable + { + return $this->message->toIterable(); + } + + public function __sleep(): array + { + return ['message']; + } + + public function __wakeup(): void + { + $this->__construct($this->message); + } +} diff --git a/tools/mailer/symfony/mime/Part/Multipart/AlternativePart.php b/tools/mailer/symfony/mime/Part/Multipart/AlternativePart.php new file mode 100644 index 000000000..fd7542347 --- /dev/null +++ b/tools/mailer/symfony/mime/Part/Multipart/AlternativePart.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; + +/** + * @author Fabien Potencier + */ +final class AlternativePart extends AbstractMultipartPart +{ + public function getMediaSubtype(): string + { + return 'alternative'; + } +} diff --git a/tools/mailer/symfony/mime/Part/Multipart/DigestPart.php b/tools/mailer/symfony/mime/Part/Multipart/DigestPart.php new file mode 100644 index 000000000..27537f15b --- /dev/null +++ b/tools/mailer/symfony/mime/Part/Multipart/DigestPart.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; +use Symfony\Component\Mime\Part\MessagePart; + +/** + * @author Fabien Potencier + */ +final class DigestPart extends AbstractMultipartPart +{ + public function __construct(MessagePart ...$parts) + { + parent::__construct(...$parts); + } + + public function getMediaSubtype(): string + { + return 'digest'; + } +} diff --git a/tools/mailer/symfony/mime/Part/Multipart/FormDataPart.php b/tools/mailer/symfony/mime/Part/Multipart/FormDataPart.php new file mode 100644 index 000000000..ed9c6e165 --- /dev/null +++ b/tools/mailer/symfony/mime/Part/Multipart/FormDataPart.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Part\AbstractMultipartPart; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * Implements RFC 7578. + * + * @author Fabien Potencier + */ +final class FormDataPart extends AbstractMultipartPart +{ + /** + * @param array $fields + */ + public function __construct( + private array $fields = [], + ) { + parent::__construct(); + + // HTTP does not support \r\n in header values + $this->getHeaders()->setMaxLineLength(\PHP_INT_MAX); + } + + public function getMediaSubtype(): string + { + return 'form-data'; + } + + public function getParts(): array + { + return $this->prepareFields($this->fields); + } + + private function prepareFields(array $fields): array + { + $values = []; + + $prepare = function ($item, $key, $root = null) use (&$values, &$prepare) { + if (null === $root && \is_int($key) && \is_array($item)) { + if (1 !== \count($item)) { + throw new InvalidArgumentException(sprintf('Form field values with integer keys can only have one array element, the key being the field name and the value being the field value, %d provided.', \count($item))); + } + + $key = key($item); + $item = $item[$key]; + } + + $fieldName = null !== $root ? sprintf('%s[%s]', $root, $key) : $key; + + if (\is_array($item)) { + array_walk($item, $prepare, $fieldName); + + return; + } + + if (!\is_string($item) && !$item instanceof TextPart) { + throw new InvalidArgumentException(sprintf('The value of the form field "%s" can only be a string, an array, or an instance of TextPart, "%s" given.', $fieldName, get_debug_type($item))); + } + + $values[] = $this->preparePart($fieldName, $item); + }; + + array_walk($fields, $prepare); + + return $values; + } + + private function preparePart(string $name, string|TextPart $value): TextPart + { + if (\is_string($value)) { + return $this->configurePart($name, new TextPart($value, 'utf-8', 'plain', '8bit')); + } + + return $this->configurePart($name, $value); + } + + private function configurePart(string $name, TextPart $part): TextPart + { + static $r; + + $r ??= new \ReflectionProperty(TextPart::class, 'encoding'); + + $part->setDisposition('form-data'); + $part->setName($name); + // HTTP does not support \r\n in header values + $part->getHeaders()->setMaxLineLength(\PHP_INT_MAX); + $r->setValue($part, '8bit'); + + return $part; + } +} diff --git a/tools/mailer/symfony/mime/Part/Multipart/MixedPart.php b/tools/mailer/symfony/mime/Part/Multipart/MixedPart.php new file mode 100644 index 000000000..c8d7028cd --- /dev/null +++ b/tools/mailer/symfony/mime/Part/Multipart/MixedPart.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; + +/** + * @author Fabien Potencier + */ +final class MixedPart extends AbstractMultipartPart +{ + public function getMediaSubtype(): string + { + return 'mixed'; + } +} diff --git a/tools/mailer/symfony/mime/Part/Multipart/RelatedPart.php b/tools/mailer/symfony/mime/Part/Multipart/RelatedPart.php new file mode 100644 index 000000000..18ca9f17a --- /dev/null +++ b/tools/mailer/symfony/mime/Part/Multipart/RelatedPart.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; +use Symfony\Component\Mime\Part\AbstractPart; + +/** + * @author Fabien Potencier + */ +final class RelatedPart extends AbstractMultipartPart +{ + public function __construct( + private AbstractPart $mainPart, + AbstractPart $part, + AbstractPart ...$parts, + ) { + $this->prepareParts($part, ...$parts); + + parent::__construct($part, ...$parts); + } + + public function getParts(): array + { + return array_merge([$this->mainPart], parent::getParts()); + } + + public function getMediaSubtype(): string + { + return 'related'; + } + + private function generateContentId(): string + { + return bin2hex(random_bytes(16)).'@symfony'; + } + + private function prepareParts(AbstractPart ...$parts): void + { + foreach ($parts as $part) { + if (!$part->getHeaders()->has('Content-ID')) { + $part->getHeaders()->setHeaderBody('Id', 'Content-ID', $this->generateContentId()); + } + } + } +} diff --git a/tools/mailer/symfony/mime/Part/SMimePart.php b/tools/mailer/symfony/mime/Part/SMimePart.php new file mode 100644 index 000000000..6444d312a --- /dev/null +++ b/tools/mailer/symfony/mime/Part/SMimePart.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Header\Headers; + +/** + * @author Sebastiaan Stok + */ +class SMimePart extends AbstractPart +{ + /** @internal */ + protected Headers $_headers; + + public function __construct( + private iterable|string $body, + private string $type, + private string $subtype, + private array $parameters, + ) { + parent::__construct(); + } + + public function getMediaType(): string + { + return $this->type; + } + + public function getMediaSubtype(): string + { + return $this->subtype; + } + + public function bodyToString(): string + { + if (\is_string($this->body)) { + return $this->body; + } + + $body = ''; + foreach ($this->body as $chunk) { + $body .= $chunk; + } + $this->body = $body; + + return $body; + } + + public function bodyToIterable(): iterable + { + if (\is_string($this->body)) { + yield $this->body; + + return; + } + + $body = ''; + foreach ($this->body as $chunk) { + $body .= $chunk; + yield $chunk; + } + $this->body = $body; + } + + public function getPreparedHeaders(): Headers + { + $headers = clone parent::getHeaders(); + + $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype()); + + foreach ($this->parameters as $name => $value) { + $headers->setHeaderParameter('Content-Type', $name, $value); + } + + return $headers; + } + + public function __sleep(): array + { + // convert iterables to strings for serialization + if (is_iterable($this->body)) { + $this->body = $this->bodyToString(); + } + + $this->_headers = $this->getHeaders(); + + return ['_headers', 'body', 'type', 'subtype', 'parameters']; + } + + public function __wakeup(): void + { + $r = new \ReflectionProperty(AbstractPart::class, 'headers'); + $r->setValue($this, $this->_headers); + unset($this->_headers); + } +} diff --git a/tools/mailer/symfony/mime/Part/TextPart.php b/tools/mailer/symfony/mime/Part/TextPart.php new file mode 100644 index 000000000..1054c25e4 --- /dev/null +++ b/tools/mailer/symfony/mime/Part/TextPart.php @@ -0,0 +1,245 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Encoder\Base64ContentEncoder; +use Symfony\Component\Mime\Encoder\ContentEncoderInterface; +use Symfony\Component\Mime\Encoder\EightBitContentEncoder; +use Symfony\Component\Mime\Encoder\QpContentEncoder; +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Header\Headers; + +/** + * @author Fabien Potencier + */ +class TextPart extends AbstractPart +{ + /** @internal */ + protected Headers $_headers; + + private static array $encoders = []; + + /** @var resource|string|File */ + private $body; + private ?string $charset; + private string $subtype; + private ?string $disposition = null; + private ?string $name = null; + private string $encoding; + private ?bool $seekable = null; + + /** + * @param resource|string|File $body Use a File instance to defer loading the file until rendering + */ + public function __construct($body, ?string $charset = 'utf-8', string $subtype = 'plain', ?string $encoding = null) + { + parent::__construct(); + + if (!\is_string($body) && !\is_resource($body) && !$body instanceof File) { + throw new \TypeError(sprintf('The body of "%s" must be a string, a resource, or an instance of "%s" (got "%s").', self::class, File::class, get_debug_type($body))); + } + + if ($body instanceof File) { + $path = $body->getPath(); + if ((is_file($path) && !is_readable($path)) || is_dir($path)) { + throw new InvalidArgumentException(sprintf('Path "%s" is not readable.', $path)); + } + } + + $this->body = $body; + $this->charset = $charset; + $this->subtype = $subtype; + $this->seekable = \is_resource($body) ? stream_get_meta_data($body)['seekable'] && 0 === fseek($body, 0, \SEEK_CUR) : null; + + if (null === $encoding) { + $this->encoding = $this->chooseEncoding(); + } else { + if ('quoted-printable' !== $encoding && 'base64' !== $encoding && '8bit' !== $encoding) { + throw new InvalidArgumentException(sprintf('The encoding must be one of "quoted-printable", "base64", or "8bit" ("%s" given).', $encoding)); + } + $this->encoding = $encoding; + } + } + + public function getMediaType(): string + { + return 'text'; + } + + public function getMediaSubtype(): string + { + return $this->subtype; + } + + /** + * @param string $disposition one of attachment, inline, or form-data + * + * @return $this + */ + public function setDisposition(string $disposition): static + { + $this->disposition = $disposition; + + return $this; + } + + /** + * @return ?string null or one of attachment, inline, or form-data + */ + public function getDisposition(): ?string + { + return $this->disposition; + } + + /** + * Sets the name of the file (used by FormDataPart). + * + * @return $this + */ + public function setName(string $name): static + { + $this->name = $name; + + return $this; + } + + /** + * Gets the name of the file. + */ + public function getName(): ?string + { + return $this->name; + } + + public function getBody(): string + { + if ($this->body instanceof File) { + if (false === $ret = @file_get_contents($this->body->getPath())) { + throw new InvalidArgumentException(error_get_last()['message']); + } + + return $ret; + } + + if (null === $this->seekable) { + return $this->body; + } + + if ($this->seekable) { + rewind($this->body); + } + + return stream_get_contents($this->body) ?: ''; + } + + public function bodyToString(): string + { + return $this->getEncoder()->encodeString($this->getBody(), $this->charset); + } + + public function bodyToIterable(): iterable + { + if ($this->body instanceof File) { + $path = $this->body->getPath(); + if (false === $handle = @fopen($path, 'r', false)) { + throw new InvalidArgumentException(sprintf('Unable to open path "%s".', $path)); + } + + yield from $this->getEncoder()->encodeByteStream($handle); + } elseif (null !== $this->seekable) { + if ($this->seekable) { + rewind($this->body); + } + yield from $this->getEncoder()->encodeByteStream($this->body); + } else { + yield $this->getEncoder()->encodeString($this->body); + } + } + + public function getPreparedHeaders(): Headers + { + $headers = parent::getPreparedHeaders(); + + $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype()); + if ($this->charset) { + $headers->setHeaderParameter('Content-Type', 'charset', $this->charset); + } + if ($this->name && 'form-data' !== $this->disposition) { + $headers->setHeaderParameter('Content-Type', 'name', $this->name); + } + $headers->setHeaderBody('Text', 'Content-Transfer-Encoding', $this->encoding); + + if (!$headers->has('Content-Disposition') && null !== $this->disposition) { + $headers->setHeaderBody('Parameterized', 'Content-Disposition', $this->disposition); + if ($this->name) { + $headers->setHeaderParameter('Content-Disposition', 'name', $this->name); + } + } + + return $headers; + } + + public function asDebugString(): string + { + $str = parent::asDebugString(); + if (null !== $this->charset) { + $str .= ' charset: '.$this->charset; + } + if (null !== $this->disposition) { + $str .= ' disposition: '.$this->disposition; + } + + return $str; + } + + private function getEncoder(): ContentEncoderInterface + { + if ('8bit' === $this->encoding) { + return self::$encoders[$this->encoding] ??= new EightBitContentEncoder(); + } + + if ('quoted-printable' === $this->encoding) { + return self::$encoders[$this->encoding] ??= new QpContentEncoder(); + } + + return self::$encoders[$this->encoding] ??= new Base64ContentEncoder(); + } + + private function chooseEncoding(): string + { + if (null === $this->charset) { + return 'base64'; + } + + return 'quoted-printable'; + } + + public function __sleep(): array + { + // convert resources to strings for serialization + if (null !== $this->seekable) { + $this->body = $this->getBody(); + $this->seekable = null; + } + + $this->_headers = $this->getHeaders(); + + return ['_headers', 'body', 'charset', 'subtype', 'disposition', 'name', 'encoding']; + } + + public function __wakeup(): void + { + $r = new \ReflectionProperty(AbstractPart::class, 'headers'); + $r->setValue($this, $this->_headers); + unset($this->_headers); + } +} diff --git a/tools/mailer/symfony/mime/README.md b/tools/mailer/symfony/mime/README.md new file mode 100644 index 000000000..8e4d5c77f --- /dev/null +++ b/tools/mailer/symfony/mime/README.md @@ -0,0 +1,13 @@ +MIME Component +============== + +The MIME component allows manipulating MIME messages. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/mime.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/tools/mailer/symfony/mime/RawMessage.php b/tools/mailer/symfony/mime/RawMessage.php new file mode 100644 index 000000000..f791211e1 --- /dev/null +++ b/tools/mailer/symfony/mime/RawMessage.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\LogicException; + +/** + * @author Fabien Potencier + */ +class RawMessage +{ + private bool $isGeneratorClosed; + + /** + * @param iterable|string|resource $message + */ + public function __construct( + private $message, + ) { + } + + public function __destruct() + { + if (\is_resource($this->message)) { + fclose($this->message); + } + } + + public function toString(): string + { + if (\is_string($this->message)) { + return $this->message; + } + + if (\is_resource($this->message)) { + return stream_get_contents($this->message, -1, 0); + } + + $message = ''; + foreach ($this->message as $chunk) { + $message .= $chunk; + } + + return $this->message = $message; + } + + public function toIterable(): iterable + { + if ($this->isGeneratorClosed ?? false) { + throw new LogicException('Unable to send the email as its generator is already closed.'); + } + + if (\is_string($this->message)) { + yield $this->message; + + return; + } + + if (\is_resource($this->message)) { + rewind($this->message); + while ($line = fgets($this->message)) { + yield $line; + } + + return; + } + + if ($this->message instanceof \Generator) { + $message = fopen('php://temp', 'w+'); + foreach ($this->message as $chunk) { + fwrite($message, $chunk); + yield $chunk; + } + $this->isGeneratorClosed = !$this->message->valid(); + $this->message = $message; + + return; + } + + foreach ($this->message as $chunk) { + yield $chunk; + } + } + + /** + * @throws LogicException if the message is not valid + */ + public function ensureValidity(): void + { + } + + public function __serialize(): array + { + return [$this->toString()]; + } + + public function __unserialize(array $data): void + { + [$this->message] = $data; + } +} diff --git a/tools/mailer/symfony/mime/Test/Constraint/EmailAddressContains.php b/tools/mailer/symfony/mime/Test/Constraint/EmailAddressContains.php new file mode 100644 index 000000000..6e1e25021 --- /dev/null +++ b/tools/mailer/symfony/mime/Test/Constraint/EmailAddressContains.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mime\Header\MailboxHeader; +use Symfony\Component\Mime\Header\MailboxListHeader; +use Symfony\Component\Mime\RawMessage; + +final class EmailAddressContains extends Constraint +{ + public function __construct( + private string $headerName, + private string $expectedValue, + ) { + } + + public function toString(): string + { + return sprintf('contains address "%s" with value "%s"', $this->headerName, $this->expectedValue); + } + + /** + * @param RawMessage $message + */ + protected function matches($message): bool + { + if (RawMessage::class === $message::class) { + throw new \LogicException('Unable to test a message address on a RawMessage instance.'); + } + + $header = $message->getHeaders()->get($this->headerName); + if ($header instanceof MailboxHeader) { + return $this->expectedValue === $header->getAddress()->getAddress(); + } elseif ($header instanceof MailboxListHeader) { + foreach ($header->getAddresses() as $address) { + if ($this->expectedValue === $address->getAddress()) { + return true; + } + } + + return false; + } + + throw new \LogicException('Unable to test a message address on a non-address header.'); + } + + /** + * @param RawMessage $message + */ + protected function failureDescription($message): string + { + return sprintf('the Email %s (value is %s)', $this->toString(), $message->getHeaders()->get($this->headerName)->getBodyAsString()); + } +} diff --git a/tools/mailer/symfony/mime/Test/Constraint/EmailAttachmentCount.php b/tools/mailer/symfony/mime/Test/Constraint/EmailAttachmentCount.php new file mode 100644 index 000000000..aa29a05af --- /dev/null +++ b/tools/mailer/symfony/mime/Test/Constraint/EmailAttachmentCount.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +final class EmailAttachmentCount extends Constraint +{ + public function __construct( + private int $expectedValue, + private ?string $transport = null, + ) { + } + + public function toString(): string + { + return sprintf('has sent "%d" attachment(s)', $this->expectedValue); + } + + /** + * @param RawMessage $message + */ + protected function matches($message): bool + { + if (RawMessage::class === $message::class || Message::class === $message::class) { + throw new \LogicException('Unable to test a message attachment on a RawMessage or Message instance.'); + } + + return $this->expectedValue === \count($message->getAttachments()); + } + + /** + * @param RawMessage $message + */ + protected function failureDescription($message): string + { + return 'the Email '.$this->toString(); + } +} diff --git a/tools/mailer/symfony/mime/Test/Constraint/EmailHasHeader.php b/tools/mailer/symfony/mime/Test/Constraint/EmailHasHeader.php new file mode 100644 index 000000000..378426e75 --- /dev/null +++ b/tools/mailer/symfony/mime/Test/Constraint/EmailHasHeader.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mime\RawMessage; + +final class EmailHasHeader extends Constraint +{ + public function __construct( + private string $headerName, + ) { + } + + public function toString(): string + { + return sprintf('has header "%s"', $this->headerName); + } + + /** + * @param RawMessage $message + */ + protected function matches($message): bool + { + if (RawMessage::class === $message::class) { + throw new \LogicException('Unable to test a message header on a RawMessage instance.'); + } + + return $message->getHeaders()->has($this->headerName); + } + + /** + * @param RawMessage $message + */ + protected function failureDescription($message): string + { + return 'the Email '.$this->toString(); + } +} diff --git a/tools/mailer/symfony/mime/Test/Constraint/EmailHeaderSame.php b/tools/mailer/symfony/mime/Test/Constraint/EmailHeaderSame.php new file mode 100644 index 000000000..e79ddf8ec --- /dev/null +++ b/tools/mailer/symfony/mime/Test/Constraint/EmailHeaderSame.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mime\Header\UnstructuredHeader; +use Symfony\Component\Mime\RawMessage; + +final class EmailHeaderSame extends Constraint +{ + public function __construct( + private string $headerName, + private string $expectedValue, + ) { + } + + public function toString(): string + { + return sprintf('has header "%s" with value "%s"', $this->headerName, $this->expectedValue); + } + + /** + * @param RawMessage $message + */ + protected function matches($message): bool + { + if (RawMessage::class === $message::class) { + throw new \LogicException('Unable to test a message header on a RawMessage instance.'); + } + + return $this->expectedValue === $this->getHeaderValue($message); + } + + /** + * @param RawMessage $message + */ + protected function failureDescription($message): string + { + return sprintf('the Email %s (value is %s)', $this->toString(), $this->getHeaderValue($message) ?? 'null'); + } + + private function getHeaderValue($message): ?string + { + if (null === $header = $message->getHeaders()->get($this->headerName)) { + return null; + } + + return $header instanceof UnstructuredHeader ? $header->getValue() : $header->getBodyAsString(); + } +} diff --git a/tools/mailer/symfony/mime/Test/Constraint/EmailHtmlBodyContains.php b/tools/mailer/symfony/mime/Test/Constraint/EmailHtmlBodyContains.php new file mode 100644 index 000000000..fa4f0533a --- /dev/null +++ b/tools/mailer/symfony/mime/Test/Constraint/EmailHtmlBodyContains.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +final class EmailHtmlBodyContains extends Constraint +{ + public function __construct( + private string $expectedText, + ) { + } + + public function toString(): string + { + return sprintf('contains "%s"', $this->expectedText); + } + + /** + * @param RawMessage $message + */ + protected function matches($message): bool + { + if (RawMessage::class === $message::class || Message::class === $message::class) { + throw new \LogicException('Unable to test a message HTML body on a RawMessage or Message instance.'); + } + + return str_contains($message->getHtmlBody(), $this->expectedText); + } + + /** + * @param RawMessage $message + */ + protected function failureDescription($message): string + { + return 'the Email HTML body '.$this->toString(); + } +} diff --git a/tools/mailer/symfony/mime/Test/Constraint/EmailSubjectContains.php b/tools/mailer/symfony/mime/Test/Constraint/EmailSubjectContains.php new file mode 100644 index 000000000..310bc1dbc --- /dev/null +++ b/tools/mailer/symfony/mime/Test/Constraint/EmailSubjectContains.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mime\Email; + +final class EmailSubjectContains extends Constraint +{ + public function __construct( + private readonly string $expectedSubjectValue, + ) { + } + + public function toString(): string + { + return sprintf('contains subject with value "%s"', $this->expectedSubjectValue); + } + + protected function matches($other): bool + { + if (!$other instanceof Email) { + throw new \LogicException('Can only test a message subject on an Email instance.'); + } + + return str_contains((string) $other->getSubject(), $this->expectedSubjectValue); + } + + protected function failureDescription($other): string + { + $message = 'The email subject '.$this->toString(); + if ($other instanceof Email) { + $message .= sprintf('. The subject was: "%s"', $other->getSubject() ?? ''); + } + + return $message; + } +} diff --git a/tools/mailer/symfony/mime/Test/Constraint/EmailTextBodyContains.php b/tools/mailer/symfony/mime/Test/Constraint/EmailTextBodyContains.php new file mode 100644 index 000000000..79b18478e --- /dev/null +++ b/tools/mailer/symfony/mime/Test/Constraint/EmailTextBodyContains.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +final class EmailTextBodyContains extends Constraint +{ + public function __construct( + private string $expectedText, + ) { + } + + public function toString(): string + { + return sprintf('contains "%s"', $this->expectedText); + } + + /** + * @param RawMessage $message + */ + protected function matches($message): bool + { + if (RawMessage::class === $message::class || Message::class === $message::class) { + throw new \LogicException('Unable to test a message text body on a RawMessage or Message instance.'); + } + + return str_contains($message->getTextBody(), $this->expectedText); + } + + /** + * @param RawMessage $message + */ + protected function failureDescription($message): string + { + return 'the Email text body '.$this->toString(); + } +} diff --git a/tools/mailer/symfony/mime/composer.json b/tools/mailer/symfony/mime/composer.json new file mode 100644 index 000000000..5304bdf36 --- /dev/null +++ b/tools/mailer/symfony/mime/composer.json @@ -0,0 +1,47 @@ +{ + "name": "symfony/mime", + "type": "library", + "description": "Allows manipulating MIME messages", + "keywords": ["mime", "mime-type"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.2", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<6.4", + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Mime\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/tools/mailer/symfony/polyfill-intl-idn/Idn.php b/tools/mailer/symfony/polyfill-intl-idn/Idn.php new file mode 100644 index 000000000..334f8ee70 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/Idn.php @@ -0,0 +1,933 @@ + and Trevor Rowbotham + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Intl\Idn; + +use Symfony\Polyfill\Intl\Idn\Resources\unidata\DisallowedRanges; +use Symfony\Polyfill\Intl\Idn\Resources\unidata\Regex; + +/** + * @see https://www.unicode.org/reports/tr46/ + * + * @internal + */ +final class Idn +{ + public const ERROR_EMPTY_LABEL = 1; + public const ERROR_LABEL_TOO_LONG = 2; + public const ERROR_DOMAIN_NAME_TOO_LONG = 4; + public const ERROR_LEADING_HYPHEN = 8; + public const ERROR_TRAILING_HYPHEN = 0x10; + public const ERROR_HYPHEN_3_4 = 0x20; + public const ERROR_LEADING_COMBINING_MARK = 0x40; + public const ERROR_DISALLOWED = 0x80; + public const ERROR_PUNYCODE = 0x100; + public const ERROR_LABEL_HAS_DOT = 0x200; + public const ERROR_INVALID_ACE_LABEL = 0x400; + public const ERROR_BIDI = 0x800; + public const ERROR_CONTEXTJ = 0x1000; + public const ERROR_CONTEXTO_PUNCTUATION = 0x2000; + public const ERROR_CONTEXTO_DIGITS = 0x4000; + + public const INTL_IDNA_VARIANT_2003 = 0; + public const INTL_IDNA_VARIANT_UTS46 = 1; + + public const IDNA_DEFAULT = 0; + public const IDNA_ALLOW_UNASSIGNED = 1; + public const IDNA_USE_STD3_RULES = 2; + public const IDNA_CHECK_BIDI = 4; + public const IDNA_CHECK_CONTEXTJ = 8; + public const IDNA_NONTRANSITIONAL_TO_ASCII = 16; + public const IDNA_NONTRANSITIONAL_TO_UNICODE = 32; + + public const MAX_DOMAIN_SIZE = 253; + public const MAX_LABEL_SIZE = 63; + + public const BASE = 36; + public const TMIN = 1; + public const TMAX = 26; + public const SKEW = 38; + public const DAMP = 700; + public const INITIAL_BIAS = 72; + public const INITIAL_N = 128; + public const DELIMITER = '-'; + public const MAX_INT = 2147483647; + + /** + * Contains the numeric value of a basic code point (for use in representing integers) in the + * range 0 to BASE-1, or -1 if b is does not represent a value. + * + * @var array + */ + private static $basicToDigit = [ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, + + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + ]; + + /** + * @var array + */ + private static $virama; + + /** + * @var array + */ + private static $mapped; + + /** + * @var array + */ + private static $ignored; + + /** + * @var array + */ + private static $deviation; + + /** + * @var array + */ + private static $disallowed; + + /** + * @var array + */ + private static $disallowed_STD3_mapped; + + /** + * @var array + */ + private static $disallowed_STD3_valid; + + /** + * @var bool + */ + private static $mappingTableLoaded = false; + + /** + * @see https://www.unicode.org/reports/tr46/#ToASCII + * + * @param string $domainName + * @param int $options + * @param int $variant + * @param array $idna_info + * + * @return string|false + */ + public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = []) + { + if (self::INTL_IDNA_VARIANT_2003 === $variant) { + @trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED); + } + + $options = [ + 'CheckHyphens' => true, + 'CheckBidi' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 !== ($options & self::IDNA_CHECK_BIDI), + 'CheckJoiners' => self::INTL_IDNA_VARIANT_UTS46 === $variant && 0 !== ($options & self::IDNA_CHECK_CONTEXTJ), + 'UseSTD3ASCIIRules' => 0 !== ($options & self::IDNA_USE_STD3_RULES), + 'Transitional_Processing' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 === ($options & self::IDNA_NONTRANSITIONAL_TO_ASCII), + 'VerifyDnsLength' => true, + ]; + $info = new Info(); + $labels = self::process((string) $domainName, $options, $info); + + foreach ($labels as $i => $label) { + // Only convert labels to punycode that contain non-ASCII code points + if (1 === preg_match('/[^\x00-\x7F]/', $label)) { + try { + $label = 'xn--'.self::punycodeEncode($label); + } catch (\Exception $e) { + $info->errors |= self::ERROR_PUNYCODE; + } + + $labels[$i] = $label; + } + } + + if ($options['VerifyDnsLength']) { + self::validateDomainAndLabelLength($labels, $info); + } + + $idna_info = [ + 'result' => implode('.', $labels), + 'isTransitionalDifferent' => $info->transitionalDifferent, + 'errors' => $info->errors, + ]; + + return 0 === $info->errors ? $idna_info['result'] : false; + } + + /** + * @see https://www.unicode.org/reports/tr46/#ToUnicode + * + * @param string $domainName + * @param int $options + * @param int $variant + * @param array $idna_info + * + * @return string|false + */ + public static function idn_to_utf8($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = []) + { + if (self::INTL_IDNA_VARIANT_2003 === $variant) { + @trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED); + } + + $info = new Info(); + $labels = self::process((string) $domainName, [ + 'CheckHyphens' => true, + 'CheckBidi' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 !== ($options & self::IDNA_CHECK_BIDI), + 'CheckJoiners' => self::INTL_IDNA_VARIANT_UTS46 === $variant && 0 !== ($options & self::IDNA_CHECK_CONTEXTJ), + 'UseSTD3ASCIIRules' => 0 !== ($options & self::IDNA_USE_STD3_RULES), + 'Transitional_Processing' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 === ($options & self::IDNA_NONTRANSITIONAL_TO_UNICODE), + ], $info); + $idna_info = [ + 'result' => implode('.', $labels), + 'isTransitionalDifferent' => $info->transitionalDifferent, + 'errors' => $info->errors, + ]; + + return 0 === $info->errors ? $idna_info['result'] : false; + } + + /** + * @param string $label + * + * @return bool + */ + private static function isValidContextJ(array $codePoints, $label) + { + if (!isset(self::$virama)) { + self::$virama = require __DIR__.\DIRECTORY_SEPARATOR.'Resources'.\DIRECTORY_SEPARATOR.'unidata'.\DIRECTORY_SEPARATOR.'virama.php'; + } + + $offset = 0; + + foreach ($codePoints as $i => $codePoint) { + if (0x200C !== $codePoint && 0x200D !== $codePoint) { + continue; + } + + if (!isset($codePoints[$i - 1])) { + return false; + } + + // If Canonical_Combining_Class(Before(cp)) .eq. Virama Then True; + if (isset(self::$virama[$codePoints[$i - 1]])) { + continue; + } + + // If RegExpMatch((Joining_Type:{L,D})(Joining_Type:T)*\u200C(Joining_Type:T)*(Joining_Type:{R,D})) Then + // True; + // Generated RegExp = ([Joining_Type:{L,D}][Joining_Type:T]*\u200C[Joining_Type:T]*)[Joining_Type:{R,D}] + if (0x200C === $codePoint && 1 === preg_match(Regex::ZWNJ, $label, $matches, \PREG_OFFSET_CAPTURE, $offset)) { + $offset += \strlen($matches[1][0]); + + continue; + } + + return false; + } + + return true; + } + + /** + * @see https://www.unicode.org/reports/tr46/#ProcessingStepMap + * + * @param string $input + * @param array $options + * + * @return string + */ + private static function mapCodePoints($input, array $options, Info $info) + { + $str = ''; + $useSTD3ASCIIRules = $options['UseSTD3ASCIIRules']; + $transitional = $options['Transitional_Processing']; + + foreach (self::utf8Decode($input) as $codePoint) { + $data = self::lookupCodePointStatus($codePoint, $useSTD3ASCIIRules); + + switch ($data['status']) { + case 'disallowed': + case 'valid': + $str .= mb_chr($codePoint, 'utf-8'); + + break; + + case 'ignored': + // Do nothing. + break; + + case 'mapped': + $str .= $transitional && 0x1E9E === $codePoint ? 'ss' : $data['mapping']; + + break; + + case 'deviation': + $info->transitionalDifferent = true; + $str .= ($transitional ? $data['mapping'] : mb_chr($codePoint, 'utf-8')); + + break; + } + } + + return $str; + } + + /** + * @see https://www.unicode.org/reports/tr46/#Processing + * + * @param string $domain + * @param array $options + * + * @return array + */ + private static function process($domain, array $options, Info $info) + { + // If VerifyDnsLength is not set, we are doing ToUnicode otherwise we are doing ToASCII and + // we need to respect the VerifyDnsLength option. + $checkForEmptyLabels = !isset($options['VerifyDnsLength']) || $options['VerifyDnsLength']; + + if ($checkForEmptyLabels && '' === $domain) { + $info->errors |= self::ERROR_EMPTY_LABEL; + + return [$domain]; + } + + // Step 1. Map each code point in the domain name string + $domain = self::mapCodePoints($domain, $options, $info); + + // Step 2. Normalize the domain name string to Unicode Normalization Form C. + if (!\Normalizer::isNormalized($domain, \Normalizer::FORM_C)) { + $domain = \Normalizer::normalize($domain, \Normalizer::FORM_C); + } + + // Step 3. Break the string into labels at U+002E (.) FULL STOP. + $labels = explode('.', $domain); + $lastLabelIndex = \count($labels) - 1; + + // Step 4. Convert and validate each label in the domain name string. + foreach ($labels as $i => $label) { + $validationOptions = $options; + + if ('xn--' === substr($label, 0, 4)) { + // Step 4.1. If the label contains any non-ASCII code point (i.e., a code point greater than U+007F), + // record that there was an error, and continue with the next label. + if (preg_match('/[^\x00-\x7F]/', $label)) { + $info->errors |= self::ERROR_PUNYCODE; + + continue; + } + + // Step 4.2. Attempt to convert the rest of the label to Unicode according to Punycode [RFC3492]. If + // that conversion fails, record that there was an error, and continue + // with the next label. Otherwise replace the original label in the string by the results of the + // conversion. + try { + $label = self::punycodeDecode(substr($label, 4)); + } catch (\Exception $e) { + $info->errors |= self::ERROR_PUNYCODE; + + continue; + } + + $validationOptions['Transitional_Processing'] = false; + $labels[$i] = $label; + } + + self::validateLabel($label, $info, $validationOptions, $i > 0 && $i === $lastLabelIndex); + } + + if ($info->bidiDomain && !$info->validBidiDomain) { + $info->errors |= self::ERROR_BIDI; + } + + // Any input domain name string that does not record an error has been successfully + // processed according to this specification. Conversely, if an input domain_name string + // causes an error, then the processing of the input domain_name string fails. Determining + // what to do with error input is up to the caller, and not in the scope of this document. + return $labels; + } + + /** + * @see https://tools.ietf.org/html/rfc5893#section-2 + * + * @param string $label + */ + private static function validateBidiLabel($label, Info $info) + { + if (1 === preg_match(Regex::RTL_LABEL, $label)) { + $info->bidiDomain = true; + + // Step 1. The first character must be a character with Bidi property L, R, or AL. + // If it has the R or AL property, it is an RTL label + if (1 !== preg_match(Regex::BIDI_STEP_1_RTL, $label)) { + $info->validBidiDomain = false; + + return; + } + + // Step 2. In an RTL label, only characters with the Bidi properties R, AL, AN, EN, ES, + // CS, ET, ON, BN, or NSM are allowed. + if (1 === preg_match(Regex::BIDI_STEP_2, $label)) { + $info->validBidiDomain = false; + + return; + } + + // Step 3. In an RTL label, the end of the label must be a character with Bidi property + // R, AL, EN, or AN, followed by zero or more characters with Bidi property NSM. + if (1 !== preg_match(Regex::BIDI_STEP_3, $label)) { + $info->validBidiDomain = false; + + return; + } + + // Step 4. In an RTL label, if an EN is present, no AN may be present, and vice versa. + if (1 === preg_match(Regex::BIDI_STEP_4_AN, $label) && 1 === preg_match(Regex::BIDI_STEP_4_EN, $label)) { + $info->validBidiDomain = false; + + return; + } + + return; + } + + // We are a LTR label + // Step 1. The first character must be a character with Bidi property L, R, or AL. + // If it has the L property, it is an LTR label. + if (1 !== preg_match(Regex::BIDI_STEP_1_LTR, $label)) { + $info->validBidiDomain = false; + + return; + } + + // Step 5. In an LTR label, only characters with the Bidi properties L, EN, + // ES, CS, ET, ON, BN, or NSM are allowed. + if (1 === preg_match(Regex::BIDI_STEP_5, $label)) { + $info->validBidiDomain = false; + + return; + } + + // Step 6.In an LTR label, the end of the label must be a character with Bidi property L or + // EN, followed by zero or more characters with Bidi property NSM. + if (1 !== preg_match(Regex::BIDI_STEP_6, $label)) { + $info->validBidiDomain = false; + + return; + } + } + + /** + * @param array $labels + */ + private static function validateDomainAndLabelLength(array $labels, Info $info) + { + $maxDomainSize = self::MAX_DOMAIN_SIZE; + $length = \count($labels); + + // Number of "." delimiters. + $domainLength = $length - 1; + + // If the last label is empty and it is not the first label, then it is the root label. + // Increase the max size by 1, making it 254, to account for the root label's "." + // delimiter. This also means we don't need to check the last label's length for being too + // long. + if ($length > 1 && '' === $labels[$length - 1]) { + ++$maxDomainSize; + --$length; + } + + for ($i = 0; $i < $length; ++$i) { + $bytes = \strlen($labels[$i]); + $domainLength += $bytes; + + if ($bytes > self::MAX_LABEL_SIZE) { + $info->errors |= self::ERROR_LABEL_TOO_LONG; + } + } + + if ($domainLength > $maxDomainSize) { + $info->errors |= self::ERROR_DOMAIN_NAME_TOO_LONG; + } + } + + /** + * @see https://www.unicode.org/reports/tr46/#Validity_Criteria + * + * @param string $label + * @param array $options + * @param bool $canBeEmpty + */ + private static function validateLabel($label, Info $info, array $options, $canBeEmpty) + { + if ('' === $label) { + if (!$canBeEmpty && (!isset($options['VerifyDnsLength']) || $options['VerifyDnsLength'])) { + $info->errors |= self::ERROR_EMPTY_LABEL; + } + + return; + } + + // Step 1. The label must be in Unicode Normalization Form C. + if (!\Normalizer::isNormalized($label, \Normalizer::FORM_C)) { + $info->errors |= self::ERROR_INVALID_ACE_LABEL; + } + + $codePoints = self::utf8Decode($label); + + if ($options['CheckHyphens']) { + // Step 2. If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character + // in both the thrid and fourth positions. + if (isset($codePoints[2], $codePoints[3]) && 0x002D === $codePoints[2] && 0x002D === $codePoints[3]) { + $info->errors |= self::ERROR_HYPHEN_3_4; + } + + // Step 3. If CheckHyphens, the label must neither begin nor end with a U+002D + // HYPHEN-MINUS character. + if ('-' === substr($label, 0, 1)) { + $info->errors |= self::ERROR_LEADING_HYPHEN; + } + + if ('-' === substr($label, -1, 1)) { + $info->errors |= self::ERROR_TRAILING_HYPHEN; + } + } elseif ('xn--' === substr($label, 0, 4)) { + $info->errors |= self::ERROR_PUNYCODE; + } + + // Step 4. The label must not contain a U+002E (.) FULL STOP. + if (false !== strpos($label, '.')) { + $info->errors |= self::ERROR_LABEL_HAS_DOT; + } + + // Step 5. The label must not begin with a combining mark, that is: General_Category=Mark. + if (1 === preg_match(Regex::COMBINING_MARK, $label)) { + $info->errors |= self::ERROR_LEADING_COMBINING_MARK; + } + + // Step 6. Each code point in the label must only have certain status values according to + // Section 5, IDNA Mapping Table: + $transitional = $options['Transitional_Processing']; + $useSTD3ASCIIRules = $options['UseSTD3ASCIIRules']; + + foreach ($codePoints as $codePoint) { + $data = self::lookupCodePointStatus($codePoint, $useSTD3ASCIIRules); + $status = $data['status']; + + if ('valid' === $status || (!$transitional && 'deviation' === $status)) { + continue; + } + + $info->errors |= self::ERROR_DISALLOWED; + + break; + } + + // Step 7. If CheckJoiners, the label must satisify the ContextJ rules from Appendix A, in + // The Unicode Code Points and Internationalized Domain Names for Applications (IDNA) + // [IDNA2008]. + if ($options['CheckJoiners'] && !self::isValidContextJ($codePoints, $label)) { + $info->errors |= self::ERROR_CONTEXTJ; + } + + // Step 8. If CheckBidi, and if the domain name is a Bidi domain name, then the label must + // satisfy all six of the numbered conditions in [IDNA2008] RFC 5893, Section 2. + if ($options['CheckBidi'] && (!$info->bidiDomain || $info->validBidiDomain)) { + self::validateBidiLabel($label, $info); + } + } + + /** + * @see https://tools.ietf.org/html/rfc3492#section-6.2 + * + * @param string $input + * + * @return string + */ + private static function punycodeDecode($input) + { + $n = self::INITIAL_N; + $out = 0; + $i = 0; + $bias = self::INITIAL_BIAS; + $lastDelimIndex = strrpos($input, self::DELIMITER); + $b = false === $lastDelimIndex ? 0 : $lastDelimIndex; + $inputLength = \strlen($input); + $output = []; + $bytes = array_map('ord', str_split($input)); + + for ($j = 0; $j < $b; ++$j) { + if ($bytes[$j] > 0x7F) { + throw new \Exception('Invalid input'); + } + + $output[$out++] = $input[$j]; + } + + if ($b > 0) { + ++$b; + } + + for ($in = $b; $in < $inputLength; ++$out) { + $oldi = $i; + $w = 1; + + for ($k = self::BASE; /* no condition */; $k += self::BASE) { + if ($in >= $inputLength) { + throw new \Exception('Invalid input'); + } + + $digit = self::$basicToDigit[$bytes[$in++] & 0xFF]; + + if ($digit < 0) { + throw new \Exception('Invalid input'); + } + + if ($digit > intdiv(self::MAX_INT - $i, $w)) { + throw new \Exception('Integer overflow'); + } + + $i += $digit * $w; + + if ($k <= $bias) { + $t = self::TMIN; + } elseif ($k >= $bias + self::TMAX) { + $t = self::TMAX; + } else { + $t = $k - $bias; + } + + if ($digit < $t) { + break; + } + + $baseMinusT = self::BASE - $t; + + if ($w > intdiv(self::MAX_INT, $baseMinusT)) { + throw new \Exception('Integer overflow'); + } + + $w *= $baseMinusT; + } + + $outPlusOne = $out + 1; + $bias = self::adaptBias($i - $oldi, $outPlusOne, 0 === $oldi); + + if (intdiv($i, $outPlusOne) > self::MAX_INT - $n) { + throw new \Exception('Integer overflow'); + } + + $n += intdiv($i, $outPlusOne); + $i %= $outPlusOne; + array_splice($output, $i++, 0, [mb_chr($n, 'utf-8')]); + } + + return implode('', $output); + } + + /** + * @see https://tools.ietf.org/html/rfc3492#section-6.3 + * + * @param string $input + * + * @return string + */ + private static function punycodeEncode($input) + { + $n = self::INITIAL_N; + $delta = 0; + $out = 0; + $bias = self::INITIAL_BIAS; + $inputLength = 0; + $output = ''; + $iter = self::utf8Decode($input); + + foreach ($iter as $codePoint) { + ++$inputLength; + + if ($codePoint < 0x80) { + $output .= \chr($codePoint); + ++$out; + } + } + + $h = $out; + $b = $out; + + if ($b > 0) { + $output .= self::DELIMITER; + ++$out; + } + + while ($h < $inputLength) { + $m = self::MAX_INT; + + foreach ($iter as $codePoint) { + if ($codePoint >= $n && $codePoint < $m) { + $m = $codePoint; + } + } + + if ($m - $n > intdiv(self::MAX_INT - $delta, $h + 1)) { + throw new \Exception('Integer overflow'); + } + + $delta += ($m - $n) * ($h + 1); + $n = $m; + + foreach ($iter as $codePoint) { + if ($codePoint < $n && 0 === ++$delta) { + throw new \Exception('Integer overflow'); + } + + if ($codePoint === $n) { + $q = $delta; + + for ($k = self::BASE; /* no condition */; $k += self::BASE) { + if ($k <= $bias) { + $t = self::TMIN; + } elseif ($k >= $bias + self::TMAX) { + $t = self::TMAX; + } else { + $t = $k - $bias; + } + + if ($q < $t) { + break; + } + + $qMinusT = $q - $t; + $baseMinusT = self::BASE - $t; + $output .= self::encodeDigit($t + $qMinusT % $baseMinusT, false); + ++$out; + $q = intdiv($qMinusT, $baseMinusT); + } + + $output .= self::encodeDigit($q, false); + ++$out; + $bias = self::adaptBias($delta, $h + 1, $h === $b); + $delta = 0; + ++$h; + } + } + + ++$delta; + ++$n; + } + + return $output; + } + + /** + * @see https://tools.ietf.org/html/rfc3492#section-6.1 + * + * @param int $delta + * @param int $numPoints + * @param bool $firstTime + * + * @return int + */ + private static function adaptBias($delta, $numPoints, $firstTime) + { + // xxx >> 1 is a faster way of doing intdiv(xxx, 2) + $delta = $firstTime ? intdiv($delta, self::DAMP) : $delta >> 1; + $delta += intdiv($delta, $numPoints); + $k = 0; + + while ($delta > ((self::BASE - self::TMIN) * self::TMAX) >> 1) { + $delta = intdiv($delta, self::BASE - self::TMIN); + $k += self::BASE; + } + + return $k + intdiv((self::BASE - self::TMIN + 1) * $delta, $delta + self::SKEW); + } + + /** + * @param int $d + * @param bool $flag + * + * @return string + */ + private static function encodeDigit($d, $flag) + { + return \chr($d + 22 + 75 * ($d < 26 ? 1 : 0) - (($flag ? 1 : 0) << 5)); + } + + /** + * Takes a UTF-8 encoded string and converts it into a series of integer code points. Any + * invalid byte sequences will be replaced by a U+FFFD replacement code point. + * + * @see https://encoding.spec.whatwg.org/#utf-8-decoder + * + * @param string $input + * + * @return array + */ + private static function utf8Decode($input) + { + $bytesSeen = 0; + $bytesNeeded = 0; + $lowerBoundary = 0x80; + $upperBoundary = 0xBF; + $codePoint = 0; + $codePoints = []; + $length = \strlen($input); + + for ($i = 0; $i < $length; ++$i) { + $byte = \ord($input[$i]); + + if (0 === $bytesNeeded) { + if ($byte >= 0x00 && $byte <= 0x7F) { + $codePoints[] = $byte; + + continue; + } + + if ($byte >= 0xC2 && $byte <= 0xDF) { + $bytesNeeded = 1; + $codePoint = $byte & 0x1F; + } elseif ($byte >= 0xE0 && $byte <= 0xEF) { + if (0xE0 === $byte) { + $lowerBoundary = 0xA0; + } elseif (0xED === $byte) { + $upperBoundary = 0x9F; + } + + $bytesNeeded = 2; + $codePoint = $byte & 0xF; + } elseif ($byte >= 0xF0 && $byte <= 0xF4) { + if (0xF0 === $byte) { + $lowerBoundary = 0x90; + } elseif (0xF4 === $byte) { + $upperBoundary = 0x8F; + } + + $bytesNeeded = 3; + $codePoint = $byte & 0x7; + } else { + $codePoints[] = 0xFFFD; + } + + continue; + } + + if ($byte < $lowerBoundary || $byte > $upperBoundary) { + $codePoint = 0; + $bytesNeeded = 0; + $bytesSeen = 0; + $lowerBoundary = 0x80; + $upperBoundary = 0xBF; + --$i; + $codePoints[] = 0xFFFD; + + continue; + } + + $lowerBoundary = 0x80; + $upperBoundary = 0xBF; + $codePoint = ($codePoint << 6) | ($byte & 0x3F); + + if (++$bytesSeen !== $bytesNeeded) { + continue; + } + + $codePoints[] = $codePoint; + $codePoint = 0; + $bytesNeeded = 0; + $bytesSeen = 0; + } + + // String unexpectedly ended, so append a U+FFFD code point. + if (0 !== $bytesNeeded) { + $codePoints[] = 0xFFFD; + } + + return $codePoints; + } + + /** + * @param int $codePoint + * @param bool $useSTD3ASCIIRules + * + * @return array{status: string, mapping?: string} + */ + private static function lookupCodePointStatus($codePoint, $useSTD3ASCIIRules) + { + if (!self::$mappingTableLoaded) { + self::$mappingTableLoaded = true; + self::$mapped = require __DIR__.'/Resources/unidata/mapped.php'; + self::$ignored = require __DIR__.'/Resources/unidata/ignored.php'; + self::$deviation = require __DIR__.'/Resources/unidata/deviation.php'; + self::$disallowed = require __DIR__.'/Resources/unidata/disallowed.php'; + self::$disallowed_STD3_mapped = require __DIR__.'/Resources/unidata/disallowed_STD3_mapped.php'; + self::$disallowed_STD3_valid = require __DIR__.'/Resources/unidata/disallowed_STD3_valid.php'; + } + + if (isset(self::$mapped[$codePoint])) { + return ['status' => 'mapped', 'mapping' => self::$mapped[$codePoint]]; + } + + if (isset(self::$ignored[$codePoint])) { + return ['status' => 'ignored']; + } + + if (isset(self::$deviation[$codePoint])) { + return ['status' => 'deviation', 'mapping' => self::$deviation[$codePoint]]; + } + + if (isset(self::$disallowed[$codePoint]) || DisallowedRanges::inRange($codePoint)) { + return ['status' => 'disallowed']; + } + + $isDisallowedMapped = isset(self::$disallowed_STD3_mapped[$codePoint]); + + if ($isDisallowedMapped || isset(self::$disallowed_STD3_valid[$codePoint])) { + $status = 'disallowed'; + + if (!$useSTD3ASCIIRules) { + $status = $isDisallowedMapped ? 'mapped' : 'valid'; + } + + if ($isDisallowedMapped) { + return ['status' => $status, 'mapping' => self::$disallowed_STD3_mapped[$codePoint]]; + } + + return ['status' => $status]; + } + + return ['status' => 'valid']; + } +} diff --git a/tools/mailer/symfony/polyfill-intl-idn/Info.php b/tools/mailer/symfony/polyfill-intl-idn/Info.php new file mode 100644 index 000000000..25c3582b2 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/Info.php @@ -0,0 +1,23 @@ + and Trevor Rowbotham + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Intl\Idn; + +/** + * @internal + */ +class Info +{ + public $bidiDomain = false; + public $errors = 0; + public $validBidiDomain = true; + public $transitionalDifferent = false; +} diff --git a/tools/mailer/symfony/polyfill-intl-idn/LICENSE b/tools/mailer/symfony/polyfill-intl-idn/LICENSE new file mode 100644 index 000000000..fd0a0626a --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-present Fabien Potencier and Trevor Rowbotham + +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/tools/mailer/symfony/polyfill-intl-idn/README.md b/tools/mailer/symfony/polyfill-intl-idn/README.md new file mode 100644 index 000000000..cae551705 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/README.md @@ -0,0 +1,12 @@ +Symfony Polyfill / Intl: Idn +============================ + +This component provides [`idn_to_ascii`](https://php.net/idn-to-ascii) and [`idn_to_utf8`](https://php.net/idn-to-utf8) functions to users who run php versions without the [Intl](https://php.net/intl) extension. + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php new file mode 100644 index 000000000..d285acd13 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php @@ -0,0 +1,384 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Intl\Idn\Resources\unidata; + +/** + * @internal + */ +final class DisallowedRanges +{ + /** + * @param int $codePoint + * + * @return bool + */ + public static function inRange($codePoint) + { + if ($codePoint >= 128 && $codePoint <= 159) { + return true; + } + + if ($codePoint >= 2155 && $codePoint <= 2207) { + return true; + } + + if ($codePoint >= 3676 && $codePoint <= 3712) { + return true; + } + + if ($codePoint >= 3808 && $codePoint <= 3839) { + return true; + } + + if ($codePoint >= 4059 && $codePoint <= 4095) { + return true; + } + + if ($codePoint >= 4256 && $codePoint <= 4293) { + return true; + } + + if ($codePoint >= 6849 && $codePoint <= 6911) { + return true; + } + + if ($codePoint >= 11859 && $codePoint <= 11903) { + return true; + } + + if ($codePoint >= 42955 && $codePoint <= 42996) { + return true; + } + + if ($codePoint >= 55296 && $codePoint <= 57343) { + return true; + } + + if ($codePoint >= 57344 && $codePoint <= 63743) { + return true; + } + + if ($codePoint >= 64218 && $codePoint <= 64255) { + return true; + } + + if ($codePoint >= 64976 && $codePoint <= 65007) { + return true; + } + + if ($codePoint >= 65630 && $codePoint <= 65663) { + return true; + } + + if ($codePoint >= 65953 && $codePoint <= 65999) { + return true; + } + + if ($codePoint >= 66046 && $codePoint <= 66175) { + return true; + } + + if ($codePoint >= 66518 && $codePoint <= 66559) { + return true; + } + + if ($codePoint >= 66928 && $codePoint <= 67071) { + return true; + } + + if ($codePoint >= 67432 && $codePoint <= 67583) { + return true; + } + + if ($codePoint >= 67760 && $codePoint <= 67807) { + return true; + } + + if ($codePoint >= 67904 && $codePoint <= 67967) { + return true; + } + + if ($codePoint >= 68256 && $codePoint <= 68287) { + return true; + } + + if ($codePoint >= 68528 && $codePoint <= 68607) { + return true; + } + + if ($codePoint >= 68681 && $codePoint <= 68735) { + return true; + } + + if ($codePoint >= 68922 && $codePoint <= 69215) { + return true; + } + + if ($codePoint >= 69298 && $codePoint <= 69375) { + return true; + } + + if ($codePoint >= 69466 && $codePoint <= 69551) { + return true; + } + + if ($codePoint >= 70207 && $codePoint <= 70271) { + return true; + } + + if ($codePoint >= 70517 && $codePoint <= 70655) { + return true; + } + + if ($codePoint >= 70874 && $codePoint <= 71039) { + return true; + } + + if ($codePoint >= 71134 && $codePoint <= 71167) { + return true; + } + + if ($codePoint >= 71370 && $codePoint <= 71423) { + return true; + } + + if ($codePoint >= 71488 && $codePoint <= 71679) { + return true; + } + + if ($codePoint >= 71740 && $codePoint <= 71839) { + return true; + } + + if ($codePoint >= 72026 && $codePoint <= 72095) { + return true; + } + + if ($codePoint >= 72441 && $codePoint <= 72703) { + return true; + } + + if ($codePoint >= 72887 && $codePoint <= 72959) { + return true; + } + + if ($codePoint >= 73130 && $codePoint <= 73439) { + return true; + } + + if ($codePoint >= 73465 && $codePoint <= 73647) { + return true; + } + + if ($codePoint >= 74650 && $codePoint <= 74751) { + return true; + } + + if ($codePoint >= 75076 && $codePoint <= 77823) { + return true; + } + + if ($codePoint >= 78905 && $codePoint <= 82943) { + return true; + } + + if ($codePoint >= 83527 && $codePoint <= 92159) { + return true; + } + + if ($codePoint >= 92784 && $codePoint <= 92879) { + return true; + } + + if ($codePoint >= 93072 && $codePoint <= 93759) { + return true; + } + + if ($codePoint >= 93851 && $codePoint <= 93951) { + return true; + } + + if ($codePoint >= 94112 && $codePoint <= 94175) { + return true; + } + + if ($codePoint >= 101590 && $codePoint <= 101631) { + return true; + } + + if ($codePoint >= 101641 && $codePoint <= 110591) { + return true; + } + + if ($codePoint >= 110879 && $codePoint <= 110927) { + return true; + } + + if ($codePoint >= 111356 && $codePoint <= 113663) { + return true; + } + + if ($codePoint >= 113828 && $codePoint <= 118783) { + return true; + } + + if ($codePoint >= 119366 && $codePoint <= 119519) { + return true; + } + + if ($codePoint >= 119673 && $codePoint <= 119807) { + return true; + } + + if ($codePoint >= 121520 && $codePoint <= 122879) { + return true; + } + + if ($codePoint >= 122923 && $codePoint <= 123135) { + return true; + } + + if ($codePoint >= 123216 && $codePoint <= 123583) { + return true; + } + + if ($codePoint >= 123648 && $codePoint <= 124927) { + return true; + } + + if ($codePoint >= 125143 && $codePoint <= 125183) { + return true; + } + + if ($codePoint >= 125280 && $codePoint <= 126064) { + return true; + } + + if ($codePoint >= 126133 && $codePoint <= 126208) { + return true; + } + + if ($codePoint >= 126270 && $codePoint <= 126463) { + return true; + } + + if ($codePoint >= 126652 && $codePoint <= 126703) { + return true; + } + + if ($codePoint >= 126706 && $codePoint <= 126975) { + return true; + } + + if ($codePoint >= 127406 && $codePoint <= 127461) { + return true; + } + + if ($codePoint >= 127590 && $codePoint <= 127743) { + return true; + } + + if ($codePoint >= 129202 && $codePoint <= 129279) { + return true; + } + + if ($codePoint >= 129751 && $codePoint <= 129791) { + return true; + } + + if ($codePoint >= 129995 && $codePoint <= 130031) { + return true; + } + + if ($codePoint >= 130042 && $codePoint <= 131069) { + return true; + } + + if ($codePoint >= 173790 && $codePoint <= 173823) { + return true; + } + + if ($codePoint >= 191457 && $codePoint <= 194559) { + return true; + } + + if ($codePoint >= 195102 && $codePoint <= 196605) { + return true; + } + + if ($codePoint >= 201547 && $codePoint <= 262141) { + return true; + } + + if ($codePoint >= 262144 && $codePoint <= 327677) { + return true; + } + + if ($codePoint >= 327680 && $codePoint <= 393213) { + return true; + } + + if ($codePoint >= 393216 && $codePoint <= 458749) { + return true; + } + + if ($codePoint >= 458752 && $codePoint <= 524285) { + return true; + } + + if ($codePoint >= 524288 && $codePoint <= 589821) { + return true; + } + + if ($codePoint >= 589824 && $codePoint <= 655357) { + return true; + } + + if ($codePoint >= 655360 && $codePoint <= 720893) { + return true; + } + + if ($codePoint >= 720896 && $codePoint <= 786429) { + return true; + } + + if ($codePoint >= 786432 && $codePoint <= 851965) { + return true; + } + + if ($codePoint >= 851968 && $codePoint <= 917501) { + return true; + } + + if ($codePoint >= 917536 && $codePoint <= 917631) { + return true; + } + + if ($codePoint >= 917632 && $codePoint <= 917759) { + return true; + } + + if ($codePoint >= 918000 && $codePoint <= 983037) { + return true; + } + + if ($codePoint >= 983040 && $codePoint <= 1048573) { + return true; + } + + if ($codePoint >= 1048576 && $codePoint <= 1114109) { + return true; + } + + return false; + } +} diff --git a/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/Regex.php b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/Regex.php new file mode 100644 index 000000000..3c6af0c13 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/Regex.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Intl\Idn\Resources\unidata; + +/** + * @internal + */ +final class Regex +{ + const COMBINING_MARK = '/^[\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{0903}\x{093A}\x{093B}\x{093C}\x{093E}-\x{0940}\x{0941}-\x{0948}\x{0949}-\x{094C}\x{094D}\x{094E}-\x{094F}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{0982}-\x{0983}\x{09BC}\x{09BE}-\x{09C0}\x{09C1}-\x{09C4}\x{09C7}-\x{09C8}\x{09CB}-\x{09CC}\x{09CD}\x{09D7}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A03}\x{0A3C}\x{0A3E}-\x{0A40}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0A83}\x{0ABC}\x{0ABE}-\x{0AC0}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0AC9}\x{0ACB}-\x{0ACC}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B02}-\x{0B03}\x{0B3C}\x{0B3E}\x{0B3F}\x{0B40}\x{0B41}-\x{0B44}\x{0B47}-\x{0B48}\x{0B4B}-\x{0B4C}\x{0B4D}\x{0B55}-\x{0B56}\x{0B57}\x{0B62}-\x{0B63}\x{0B82}\x{0BBE}-\x{0BBF}\x{0BC0}\x{0BC1}-\x{0BC2}\x{0BC6}-\x{0BC8}\x{0BCA}-\x{0BCC}\x{0BCD}\x{0BD7}\x{0C00}\x{0C01}-\x{0C03}\x{0C04}\x{0C3E}-\x{0C40}\x{0C41}-\x{0C44}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0C82}-\x{0C83}\x{0CBC}\x{0CBE}\x{0CBF}\x{0CC0}-\x{0CC4}\x{0CC6}\x{0CC7}-\x{0CC8}\x{0CCA}-\x{0CCB}\x{0CCC}-\x{0CCD}\x{0CD5}-\x{0CD6}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D02}-\x{0D03}\x{0D3B}-\x{0D3C}\x{0D3E}-\x{0D40}\x{0D41}-\x{0D44}\x{0D46}-\x{0D48}\x{0D4A}-\x{0D4C}\x{0D4D}\x{0D57}\x{0D62}-\x{0D63}\x{0D81}\x{0D82}-\x{0D83}\x{0DCA}\x{0DCF}-\x{0DD1}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0DD8}-\x{0DDF}\x{0DF2}-\x{0DF3}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3E}-\x{0F3F}\x{0F71}-\x{0F7E}\x{0F7F}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102B}-\x{102C}\x{102D}-\x{1030}\x{1031}\x{1032}-\x{1037}\x{1038}\x{1039}-\x{103A}\x{103B}-\x{103C}\x{103D}-\x{103E}\x{1056}-\x{1057}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1062}-\x{1064}\x{1067}-\x{106D}\x{1071}-\x{1074}\x{1082}\x{1083}-\x{1084}\x{1085}-\x{1086}\x{1087}-\x{108C}\x{108D}\x{108F}\x{109A}-\x{109C}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B6}\x{17B7}-\x{17BD}\x{17BE}-\x{17C5}\x{17C6}\x{17C7}-\x{17C8}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1923}-\x{1926}\x{1927}-\x{1928}\x{1929}-\x{192B}\x{1930}-\x{1931}\x{1932}\x{1933}-\x{1938}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A19}-\x{1A1A}\x{1A1B}\x{1A55}\x{1A56}\x{1A57}\x{1A58}-\x{1A5E}\x{1A60}\x{1A61}\x{1A62}\x{1A63}-\x{1A64}\x{1A65}-\x{1A6C}\x{1A6D}-\x{1A72}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B04}\x{1B34}\x{1B35}\x{1B36}-\x{1B3A}\x{1B3B}\x{1B3C}\x{1B3D}-\x{1B41}\x{1B42}\x{1B43}-\x{1B44}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1B82}\x{1BA1}\x{1BA2}-\x{1BA5}\x{1BA6}-\x{1BA7}\x{1BA8}-\x{1BA9}\x{1BAA}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE7}\x{1BE8}-\x{1BE9}\x{1BEA}-\x{1BEC}\x{1BED}\x{1BEE}\x{1BEF}-\x{1BF1}\x{1BF2}-\x{1BF3}\x{1C24}-\x{1C2B}\x{1C2C}-\x{1C33}\x{1C34}-\x{1C35}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE1}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF7}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{302E}-\x{302F}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A823}-\x{A824}\x{A825}-\x{A826}\x{A827}\x{A82C}\x{A880}-\x{A881}\x{A8B4}-\x{A8C3}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A952}-\x{A953}\x{A980}-\x{A982}\x{A983}\x{A9B3}\x{A9B4}-\x{A9B5}\x{A9B6}-\x{A9B9}\x{A9BA}-\x{A9BB}\x{A9BC}-\x{A9BD}\x{A9BE}-\x{A9C0}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA2F}-\x{AA30}\x{AA31}-\x{AA32}\x{AA33}-\x{AA34}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA4D}\x{AA7B}\x{AA7C}\x{AA7D}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEB}\x{AAEC}-\x{AAED}\x{AAEE}-\x{AAEF}\x{AAF5}\x{AAF6}\x{ABE3}-\x{ABE4}\x{ABE5}\x{ABE6}-\x{ABE7}\x{ABE8}\x{ABE9}-\x{ABEA}\x{ABEC}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11000}\x{11001}\x{11002}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{11082}\x{110B0}-\x{110B2}\x{110B3}-\x{110B6}\x{110B7}-\x{110B8}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112C}\x{1112D}-\x{11134}\x{11145}-\x{11146}\x{11173}\x{11180}-\x{11181}\x{11182}\x{111B3}-\x{111B5}\x{111B6}-\x{111BE}\x{111BF}-\x{111C0}\x{111C9}-\x{111CC}\x{111CE}\x{111CF}\x{1122C}-\x{1122E}\x{1122F}-\x{11231}\x{11232}-\x{11233}\x{11234}\x{11235}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E0}-\x{112E2}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{11302}-\x{11303}\x{1133B}-\x{1133C}\x{1133E}-\x{1133F}\x{11340}\x{11341}-\x{11344}\x{11347}-\x{11348}\x{1134B}-\x{1134D}\x{11357}\x{11362}-\x{11363}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11435}-\x{11437}\x{11438}-\x{1143F}\x{11440}-\x{11441}\x{11442}-\x{11444}\x{11445}\x{11446}\x{1145E}\x{114B0}-\x{114B2}\x{114B3}-\x{114B8}\x{114B9}\x{114BA}\x{114BB}-\x{114BE}\x{114BF}-\x{114C0}\x{114C1}\x{114C2}-\x{114C3}\x{115AF}-\x{115B1}\x{115B2}-\x{115B5}\x{115B8}-\x{115BB}\x{115BC}-\x{115BD}\x{115BE}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11630}-\x{11632}\x{11633}-\x{1163A}\x{1163B}-\x{1163C}\x{1163D}\x{1163E}\x{1163F}-\x{11640}\x{116AB}\x{116AC}\x{116AD}\x{116AE}-\x{116AF}\x{116B0}-\x{116B5}\x{116B6}\x{116B7}\x{1171D}-\x{1171F}\x{11720}-\x{11721}\x{11722}-\x{11725}\x{11726}\x{11727}-\x{1172B}\x{1182C}-\x{1182E}\x{1182F}-\x{11837}\x{11838}\x{11839}-\x{1183A}\x{11930}-\x{11935}\x{11937}-\x{11938}\x{1193B}-\x{1193C}\x{1193D}\x{1193E}\x{11940}\x{11942}\x{11943}\x{119D1}-\x{119D3}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119DC}-\x{119DF}\x{119E0}\x{119E4}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A39}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A57}-\x{11A58}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A97}\x{11A98}-\x{11A99}\x{11C2F}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3E}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CA9}\x{11CAA}-\x{11CB0}\x{11CB1}\x{11CB2}-\x{11CB3}\x{11CB4}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D8A}-\x{11D8E}\x{11D90}-\x{11D91}\x{11D93}-\x{11D94}\x{11D95}\x{11D96}\x{11D97}\x{11EF3}-\x{11EF4}\x{11EF5}-\x{11EF6}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F51}-\x{16F87}\x{16F8F}-\x{16F92}\x{16FE4}\x{16FF0}-\x{16FF1}\x{1BC9D}-\x{1BC9E}\x{1D165}-\x{1D166}\x{1D167}-\x{1D169}\x{1D16D}-\x{1D172}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]/u'; + + const RTL_LABEL = '/[\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{200F}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u'; + + const BIDI_STEP_1_LTR = '/^[^\x{0000}-\x{0008}\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{000E}-\x{001B}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{0030}-\x{0039}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0085}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B2}-\x{00B3}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00B9}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{1680}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{2000}-\x{200A}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{205F}\x{2060}-\x{2064}\x{2065}\x{2066}\x{2067}\x{2068}\x{2069}\x{206A}-\x{206F}\x{2070}\x{2074}-\x{2079}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{2080}-\x{2089}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{2488}-\x{249B}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3000}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF10}-\x{FF19}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{102E1}-\x{102FB}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1D7CE}-\x{1D7FF}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F100}-\x{1F10A}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FBF0}-\x{1FBF9}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}]/u'; + const BIDI_STEP_1_RTL = '/^[\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{200F}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u'; + const BIDI_STEP_2 = '/[^\x{0000}-\x{0008}\x{000E}-\x{001B}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{0030}-\x{0039}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B2}-\x{00B3}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00B9}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{2060}-\x{2064}\x{2065}\x{206A}-\x{206F}\x{2070}\x{2074}-\x{2079}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{2080}-\x{2089}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{2488}-\x{249B}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF10}-\x{FF19}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{102E1}-\x{102FB}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1D7CE}-\x{1D7FF}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F100}-\x{1F10A}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FBF0}-\x{1FBF9}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}]/u'; + const BIDI_STEP_3 = '/[\x{0030}-\x{0039}\x{00B2}-\x{00B3}\x{00B9}\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{200F}\x{2070}\x{2074}-\x{2079}\x{2080}-\x{2089}\x{2488}-\x{249B}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FF10}-\x{FF19}\x{102E1}-\x{102FB}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1D7CE}-\x{1D7FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F100}-\x{1F10A}\x{1FBF0}-\x{1FBF9}][\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1D167}-\x{1D169}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]*$/u'; + const BIDI_STEP_4_AN = '/[\x{0600}-\x{0605}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{06DD}\x{08E2}\x{10D30}-\x{10D39}\x{10E60}-\x{10E7E}]/u'; + const BIDI_STEP_4_EN = '/[\x{0030}-\x{0039}\x{00B2}-\x{00B3}\x{00B9}\x{06F0}-\x{06F9}\x{2070}\x{2074}-\x{2079}\x{2080}-\x{2089}\x{2488}-\x{249B}\x{FF10}-\x{FF19}\x{102E1}-\x{102FB}\x{1D7CE}-\x{1D7FF}\x{1F100}-\x{1F10A}\x{1FBF0}-\x{1FBF9}]/u'; + const BIDI_STEP_5 = '/[\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0085}\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{1680}\x{2000}-\x{200A}\x{200F}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{205F}\x{2066}\x{2067}\x{2068}\x{2069}\x{3000}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u'; + const BIDI_STEP_6 = '/[^\x{0000}-\x{0008}\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{000E}-\x{001B}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0085}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{1680}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{2000}-\x{200A}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{205F}\x{2060}-\x{2064}\x{2065}\x{2066}\x{2067}\x{2068}\x{2069}\x{206A}-\x{206F}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3000}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}][\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1D167}-\x{1D169}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]*$/u'; + + const ZWNJ = '/([\x{A872}\x{10ACD}\x{10AD7}\x{10D00}\x{10FCB}\x{0620}\x{0626}\x{0628}\x{062A}-\x{062E}\x{0633}-\x{063F}\x{0641}-\x{0647}\x{0649}-\x{064A}\x{066E}-\x{066F}\x{0678}-\x{0687}\x{069A}-\x{06BF}\x{06C1}-\x{06C2}\x{06CC}\x{06CE}\x{06D0}-\x{06D1}\x{06FA}-\x{06FC}\x{06FF}\x{0712}-\x{0714}\x{071A}-\x{071D}\x{071F}-\x{0727}\x{0729}\x{072B}\x{072D}-\x{072E}\x{074E}-\x{0758}\x{075C}-\x{076A}\x{076D}-\x{0770}\x{0772}\x{0775}-\x{0777}\x{077A}-\x{077F}\x{07CA}-\x{07EA}\x{0841}-\x{0845}\x{0848}\x{084A}-\x{0853}\x{0855}\x{0860}\x{0862}-\x{0865}\x{0868}\x{08A0}-\x{08A9}\x{08AF}-\x{08B0}\x{08B3}-\x{08B4}\x{08B6}-\x{08B8}\x{08BA}-\x{08C7}\x{1807}\x{1820}-\x{1842}\x{1843}\x{1844}-\x{1878}\x{1887}-\x{18A8}\x{18AA}\x{A840}-\x{A871}\x{10AC0}-\x{10AC4}\x{10AD3}-\x{10AD6}\x{10AD8}-\x{10ADC}\x{10ADE}-\x{10AE0}\x{10AEB}-\x{10AEE}\x{10B80}\x{10B82}\x{10B86}-\x{10B88}\x{10B8A}-\x{10B8B}\x{10B8D}\x{10B90}\x{10BAD}-\x{10BAE}\x{10D01}-\x{10D21}\x{10D23}\x{10F30}-\x{10F32}\x{10F34}-\x{10F44}\x{10F51}-\x{10F53}\x{10FB0}\x{10FB2}-\x{10FB3}\x{10FB8}\x{10FBB}-\x{10FBC}\x{10FBE}-\x{10FBF}\x{10FC1}\x{10FC4}\x{10FCA}\x{1E900}-\x{1E943}][\x{00AD}\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{061C}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{200B}\x{200E}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{206A}-\x{206F}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{FEFF}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{13430}-\x{13438}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1E94B}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}]*\x{200C}[\x{00AD}\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{061C}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{200B}\x{200E}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{206A}-\x{206F}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{FEFF}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{13430}-\x{13438}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1E94B}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}]*)[\x{0622}-\x{0625}\x{0627}\x{0629}\x{062F}-\x{0632}\x{0648}\x{0671}-\x{0673}\x{0675}-\x{0677}\x{0688}-\x{0699}\x{06C0}\x{06C3}-\x{06CB}\x{06CD}\x{06CF}\x{06D2}-\x{06D3}\x{06D5}\x{06EE}-\x{06EF}\x{0710}\x{0715}-\x{0719}\x{071E}\x{0728}\x{072A}\x{072C}\x{072F}\x{074D}\x{0759}-\x{075B}\x{076B}-\x{076C}\x{0771}\x{0773}-\x{0774}\x{0778}-\x{0779}\x{0840}\x{0846}-\x{0847}\x{0849}\x{0854}\x{0856}-\x{0858}\x{0867}\x{0869}-\x{086A}\x{08AA}-\x{08AC}\x{08AE}\x{08B1}-\x{08B2}\x{08B9}\x{10AC5}\x{10AC7}\x{10AC9}-\x{10ACA}\x{10ACE}-\x{10AD2}\x{10ADD}\x{10AE1}\x{10AE4}\x{10AEF}\x{10B81}\x{10B83}-\x{10B85}\x{10B89}\x{10B8C}\x{10B8E}-\x{10B8F}\x{10B91}\x{10BA9}-\x{10BAC}\x{10D22}\x{10F33}\x{10F54}\x{10FB4}-\x{10FB6}\x{10FB9}-\x{10FBA}\x{10FBD}\x{10FC2}-\x{10FC3}\x{10FC9}\x{0620}\x{0626}\x{0628}\x{062A}-\x{062E}\x{0633}-\x{063F}\x{0641}-\x{0647}\x{0649}-\x{064A}\x{066E}-\x{066F}\x{0678}-\x{0687}\x{069A}-\x{06BF}\x{06C1}-\x{06C2}\x{06CC}\x{06CE}\x{06D0}-\x{06D1}\x{06FA}-\x{06FC}\x{06FF}\x{0712}-\x{0714}\x{071A}-\x{071D}\x{071F}-\x{0727}\x{0729}\x{072B}\x{072D}-\x{072E}\x{074E}-\x{0758}\x{075C}-\x{076A}\x{076D}-\x{0770}\x{0772}\x{0775}-\x{0777}\x{077A}-\x{077F}\x{07CA}-\x{07EA}\x{0841}-\x{0845}\x{0848}\x{084A}-\x{0853}\x{0855}\x{0860}\x{0862}-\x{0865}\x{0868}\x{08A0}-\x{08A9}\x{08AF}-\x{08B0}\x{08B3}-\x{08B4}\x{08B6}-\x{08B8}\x{08BA}-\x{08C7}\x{1807}\x{1820}-\x{1842}\x{1843}\x{1844}-\x{1878}\x{1887}-\x{18A8}\x{18AA}\x{A840}-\x{A871}\x{10AC0}-\x{10AC4}\x{10AD3}-\x{10AD6}\x{10AD8}-\x{10ADC}\x{10ADE}-\x{10AE0}\x{10AEB}-\x{10AEE}\x{10B80}\x{10B82}\x{10B86}-\x{10B88}\x{10B8A}-\x{10B8B}\x{10B8D}\x{10B90}\x{10BAD}-\x{10BAE}\x{10D01}-\x{10D21}\x{10D23}\x{10F30}-\x{10F32}\x{10F34}-\x{10F44}\x{10F51}-\x{10F53}\x{10FB0}\x{10FB2}-\x{10FB3}\x{10FB8}\x{10FBB}-\x{10FBC}\x{10FBE}-\x{10FBF}\x{10FC1}\x{10FC4}\x{10FCA}\x{1E900}-\x{1E943}]/u'; +} diff --git a/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/deviation.php b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/deviation.php new file mode 100644 index 000000000..0bbd33567 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/deviation.php @@ -0,0 +1,8 @@ + 'ss', + 962 => 'σ', + 8204 => '', + 8205 => '', +); diff --git a/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php new file mode 100644 index 000000000..25a5f564d --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php @@ -0,0 +1,2638 @@ + true, + 889 => true, + 896 => true, + 897 => true, + 898 => true, + 899 => true, + 907 => true, + 909 => true, + 930 => true, + 1216 => true, + 1328 => true, + 1367 => true, + 1368 => true, + 1419 => true, + 1420 => true, + 1424 => true, + 1480 => true, + 1481 => true, + 1482 => true, + 1483 => true, + 1484 => true, + 1485 => true, + 1486 => true, + 1487 => true, + 1515 => true, + 1516 => true, + 1517 => true, + 1518 => true, + 1525 => true, + 1526 => true, + 1527 => true, + 1528 => true, + 1529 => true, + 1530 => true, + 1531 => true, + 1532 => true, + 1533 => true, + 1534 => true, + 1535 => true, + 1536 => true, + 1537 => true, + 1538 => true, + 1539 => true, + 1540 => true, + 1541 => true, + 1564 => true, + 1565 => true, + 1757 => true, + 1806 => true, + 1807 => true, + 1867 => true, + 1868 => true, + 1970 => true, + 1971 => true, + 1972 => true, + 1973 => true, + 1974 => true, + 1975 => true, + 1976 => true, + 1977 => true, + 1978 => true, + 1979 => true, + 1980 => true, + 1981 => true, + 1982 => true, + 1983 => true, + 2043 => true, + 2044 => true, + 2094 => true, + 2095 => true, + 2111 => true, + 2140 => true, + 2141 => true, + 2143 => true, + 2229 => true, + 2248 => true, + 2249 => true, + 2250 => true, + 2251 => true, + 2252 => true, + 2253 => true, + 2254 => true, + 2255 => true, + 2256 => true, + 2257 => true, + 2258 => true, + 2274 => true, + 2436 => true, + 2445 => true, + 2446 => true, + 2449 => true, + 2450 => true, + 2473 => true, + 2481 => true, + 2483 => true, + 2484 => true, + 2485 => true, + 2490 => true, + 2491 => true, + 2501 => true, + 2502 => true, + 2505 => true, + 2506 => true, + 2511 => true, + 2512 => true, + 2513 => true, + 2514 => true, + 2515 => true, + 2516 => true, + 2517 => true, + 2518 => true, + 2520 => true, + 2521 => true, + 2522 => true, + 2523 => true, + 2526 => true, + 2532 => true, + 2533 => true, + 2559 => true, + 2560 => true, + 2564 => true, + 2571 => true, + 2572 => true, + 2573 => true, + 2574 => true, + 2577 => true, + 2578 => true, + 2601 => true, + 2609 => true, + 2612 => true, + 2615 => true, + 2618 => true, + 2619 => true, + 2621 => true, + 2627 => true, + 2628 => true, + 2629 => true, + 2630 => true, + 2633 => true, + 2634 => true, + 2638 => true, + 2639 => true, + 2640 => true, + 2642 => true, + 2643 => true, + 2644 => true, + 2645 => true, + 2646 => true, + 2647 => true, + 2648 => true, + 2653 => true, + 2655 => true, + 2656 => true, + 2657 => true, + 2658 => true, + 2659 => true, + 2660 => true, + 2661 => true, + 2679 => true, + 2680 => true, + 2681 => true, + 2682 => true, + 2683 => true, + 2684 => true, + 2685 => true, + 2686 => true, + 2687 => true, + 2688 => true, + 2692 => true, + 2702 => true, + 2706 => true, + 2729 => true, + 2737 => true, + 2740 => true, + 2746 => true, + 2747 => true, + 2758 => true, + 2762 => true, + 2766 => true, + 2767 => true, + 2769 => true, + 2770 => true, + 2771 => true, + 2772 => true, + 2773 => true, + 2774 => true, + 2775 => true, + 2776 => true, + 2777 => true, + 2778 => true, + 2779 => true, + 2780 => true, + 2781 => true, + 2782 => true, + 2783 => true, + 2788 => true, + 2789 => true, + 2802 => true, + 2803 => true, + 2804 => true, + 2805 => true, + 2806 => true, + 2807 => true, + 2808 => true, + 2816 => true, + 2820 => true, + 2829 => true, + 2830 => true, + 2833 => true, + 2834 => true, + 2857 => true, + 2865 => true, + 2868 => true, + 2874 => true, + 2875 => true, + 2885 => true, + 2886 => true, + 2889 => true, + 2890 => true, + 2894 => true, + 2895 => true, + 2896 => true, + 2897 => true, + 2898 => true, + 2899 => true, + 2900 => true, + 2904 => true, + 2905 => true, + 2906 => true, + 2907 => true, + 2910 => true, + 2916 => true, + 2917 => true, + 2936 => true, + 2937 => true, + 2938 => true, + 2939 => true, + 2940 => true, + 2941 => true, + 2942 => true, + 2943 => true, + 2944 => true, + 2945 => true, + 2948 => true, + 2955 => true, + 2956 => true, + 2957 => true, + 2961 => true, + 2966 => true, + 2967 => true, + 2968 => true, + 2971 => true, + 2973 => true, + 2976 => true, + 2977 => true, + 2978 => true, + 2981 => true, + 2982 => true, + 2983 => true, + 2987 => true, + 2988 => true, + 2989 => true, + 3002 => true, + 3003 => true, + 3004 => true, + 3005 => true, + 3011 => true, + 3012 => true, + 3013 => true, + 3017 => true, + 3022 => true, + 3023 => true, + 3025 => true, + 3026 => true, + 3027 => true, + 3028 => true, + 3029 => true, + 3030 => true, + 3032 => true, + 3033 => true, + 3034 => true, + 3035 => true, + 3036 => true, + 3037 => true, + 3038 => true, + 3039 => true, + 3040 => true, + 3041 => true, + 3042 => true, + 3043 => true, + 3044 => true, + 3045 => true, + 3067 => true, + 3068 => true, + 3069 => true, + 3070 => true, + 3071 => true, + 3085 => true, + 3089 => true, + 3113 => true, + 3130 => true, + 3131 => true, + 3132 => true, + 3141 => true, + 3145 => true, + 3150 => true, + 3151 => true, + 3152 => true, + 3153 => true, + 3154 => true, + 3155 => true, + 3156 => true, + 3159 => true, + 3163 => true, + 3164 => true, + 3165 => true, + 3166 => true, + 3167 => true, + 3172 => true, + 3173 => true, + 3184 => true, + 3185 => true, + 3186 => true, + 3187 => true, + 3188 => true, + 3189 => true, + 3190 => true, + 3213 => true, + 3217 => true, + 3241 => true, + 3252 => true, + 3258 => true, + 3259 => true, + 3269 => true, + 3273 => true, + 3278 => true, + 3279 => true, + 3280 => true, + 3281 => true, + 3282 => true, + 3283 => true, + 3284 => true, + 3287 => true, + 3288 => true, + 3289 => true, + 3290 => true, + 3291 => true, + 3292 => true, + 3293 => true, + 3295 => true, + 3300 => true, + 3301 => true, + 3312 => true, + 3315 => true, + 3316 => true, + 3317 => true, + 3318 => true, + 3319 => true, + 3320 => true, + 3321 => true, + 3322 => true, + 3323 => true, + 3324 => true, + 3325 => true, + 3326 => true, + 3327 => true, + 3341 => true, + 3345 => true, + 3397 => true, + 3401 => true, + 3408 => true, + 3409 => true, + 3410 => true, + 3411 => true, + 3428 => true, + 3429 => true, + 3456 => true, + 3460 => true, + 3479 => true, + 3480 => true, + 3481 => true, + 3506 => true, + 3516 => true, + 3518 => true, + 3519 => true, + 3527 => true, + 3528 => true, + 3529 => true, + 3531 => true, + 3532 => true, + 3533 => true, + 3534 => true, + 3541 => true, + 3543 => true, + 3552 => true, + 3553 => true, + 3554 => true, + 3555 => true, + 3556 => true, + 3557 => true, + 3568 => true, + 3569 => true, + 3573 => true, + 3574 => true, + 3575 => true, + 3576 => true, + 3577 => true, + 3578 => true, + 3579 => true, + 3580 => true, + 3581 => true, + 3582 => true, + 3583 => true, + 3584 => true, + 3643 => true, + 3644 => true, + 3645 => true, + 3646 => true, + 3715 => true, + 3717 => true, + 3723 => true, + 3748 => true, + 3750 => true, + 3774 => true, + 3775 => true, + 3781 => true, + 3783 => true, + 3790 => true, + 3791 => true, + 3802 => true, + 3803 => true, + 3912 => true, + 3949 => true, + 3950 => true, + 3951 => true, + 3952 => true, + 3992 => true, + 4029 => true, + 4045 => true, + 4294 => true, + 4296 => true, + 4297 => true, + 4298 => true, + 4299 => true, + 4300 => true, + 4302 => true, + 4303 => true, + 4447 => true, + 4448 => true, + 4681 => true, + 4686 => true, + 4687 => true, + 4695 => true, + 4697 => true, + 4702 => true, + 4703 => true, + 4745 => true, + 4750 => true, + 4751 => true, + 4785 => true, + 4790 => true, + 4791 => true, + 4799 => true, + 4801 => true, + 4806 => true, + 4807 => true, + 4823 => true, + 4881 => true, + 4886 => true, + 4887 => true, + 4955 => true, + 4956 => true, + 4989 => true, + 4990 => true, + 4991 => true, + 5018 => true, + 5019 => true, + 5020 => true, + 5021 => true, + 5022 => true, + 5023 => true, + 5110 => true, + 5111 => true, + 5118 => true, + 5119 => true, + 5760 => true, + 5789 => true, + 5790 => true, + 5791 => true, + 5881 => true, + 5882 => true, + 5883 => true, + 5884 => true, + 5885 => true, + 5886 => true, + 5887 => true, + 5901 => true, + 5909 => true, + 5910 => true, + 5911 => true, + 5912 => true, + 5913 => true, + 5914 => true, + 5915 => true, + 5916 => true, + 5917 => true, + 5918 => true, + 5919 => true, + 5943 => true, + 5944 => true, + 5945 => true, + 5946 => true, + 5947 => true, + 5948 => true, + 5949 => true, + 5950 => true, + 5951 => true, + 5972 => true, + 5973 => true, + 5974 => true, + 5975 => true, + 5976 => true, + 5977 => true, + 5978 => true, + 5979 => true, + 5980 => true, + 5981 => true, + 5982 => true, + 5983 => true, + 5997 => true, + 6001 => true, + 6004 => true, + 6005 => true, + 6006 => true, + 6007 => true, + 6008 => true, + 6009 => true, + 6010 => true, + 6011 => true, + 6012 => true, + 6013 => true, + 6014 => true, + 6015 => true, + 6068 => true, + 6069 => true, + 6110 => true, + 6111 => true, + 6122 => true, + 6123 => true, + 6124 => true, + 6125 => true, + 6126 => true, + 6127 => true, + 6138 => true, + 6139 => true, + 6140 => true, + 6141 => true, + 6142 => true, + 6143 => true, + 6150 => true, + 6158 => true, + 6159 => true, + 6170 => true, + 6171 => true, + 6172 => true, + 6173 => true, + 6174 => true, + 6175 => true, + 6265 => true, + 6266 => true, + 6267 => true, + 6268 => true, + 6269 => true, + 6270 => true, + 6271 => true, + 6315 => true, + 6316 => true, + 6317 => true, + 6318 => true, + 6319 => true, + 6390 => true, + 6391 => true, + 6392 => true, + 6393 => true, + 6394 => true, + 6395 => true, + 6396 => true, + 6397 => true, + 6398 => true, + 6399 => true, + 6431 => true, + 6444 => true, + 6445 => true, + 6446 => true, + 6447 => true, + 6460 => true, + 6461 => true, + 6462 => true, + 6463 => true, + 6465 => true, + 6466 => true, + 6467 => true, + 6510 => true, + 6511 => true, + 6517 => true, + 6518 => true, + 6519 => true, + 6520 => true, + 6521 => true, + 6522 => true, + 6523 => true, + 6524 => true, + 6525 => true, + 6526 => true, + 6527 => true, + 6572 => true, + 6573 => true, + 6574 => true, + 6575 => true, + 6602 => true, + 6603 => true, + 6604 => true, + 6605 => true, + 6606 => true, + 6607 => true, + 6619 => true, + 6620 => true, + 6621 => true, + 6684 => true, + 6685 => true, + 6751 => true, + 6781 => true, + 6782 => true, + 6794 => true, + 6795 => true, + 6796 => true, + 6797 => true, + 6798 => true, + 6799 => true, + 6810 => true, + 6811 => true, + 6812 => true, + 6813 => true, + 6814 => true, + 6815 => true, + 6830 => true, + 6831 => true, + 6988 => true, + 6989 => true, + 6990 => true, + 6991 => true, + 7037 => true, + 7038 => true, + 7039 => true, + 7156 => true, + 7157 => true, + 7158 => true, + 7159 => true, + 7160 => true, + 7161 => true, + 7162 => true, + 7163 => true, + 7224 => true, + 7225 => true, + 7226 => true, + 7242 => true, + 7243 => true, + 7244 => true, + 7305 => true, + 7306 => true, + 7307 => true, + 7308 => true, + 7309 => true, + 7310 => true, + 7311 => true, + 7355 => true, + 7356 => true, + 7368 => true, + 7369 => true, + 7370 => true, + 7371 => true, + 7372 => true, + 7373 => true, + 7374 => true, + 7375 => true, + 7419 => true, + 7420 => true, + 7421 => true, + 7422 => true, + 7423 => true, + 7674 => true, + 7958 => true, + 7959 => true, + 7966 => true, + 7967 => true, + 8006 => true, + 8007 => true, + 8014 => true, + 8015 => true, + 8024 => true, + 8026 => true, + 8028 => true, + 8030 => true, + 8062 => true, + 8063 => true, + 8117 => true, + 8133 => true, + 8148 => true, + 8149 => true, + 8156 => true, + 8176 => true, + 8177 => true, + 8181 => true, + 8191 => true, + 8206 => true, + 8207 => true, + 8228 => true, + 8229 => true, + 8230 => true, + 8232 => true, + 8233 => true, + 8234 => true, + 8235 => true, + 8236 => true, + 8237 => true, + 8238 => true, + 8289 => true, + 8290 => true, + 8291 => true, + 8293 => true, + 8294 => true, + 8295 => true, + 8296 => true, + 8297 => true, + 8298 => true, + 8299 => true, + 8300 => true, + 8301 => true, + 8302 => true, + 8303 => true, + 8306 => true, + 8307 => true, + 8335 => true, + 8349 => true, + 8350 => true, + 8351 => true, + 8384 => true, + 8385 => true, + 8386 => true, + 8387 => true, + 8388 => true, + 8389 => true, + 8390 => true, + 8391 => true, + 8392 => true, + 8393 => true, + 8394 => true, + 8395 => true, + 8396 => true, + 8397 => true, + 8398 => true, + 8399 => true, + 8433 => true, + 8434 => true, + 8435 => true, + 8436 => true, + 8437 => true, + 8438 => true, + 8439 => true, + 8440 => true, + 8441 => true, + 8442 => true, + 8443 => true, + 8444 => true, + 8445 => true, + 8446 => true, + 8447 => true, + 8498 => true, + 8579 => true, + 8588 => true, + 8589 => true, + 8590 => true, + 8591 => true, + 9255 => true, + 9256 => true, + 9257 => true, + 9258 => true, + 9259 => true, + 9260 => true, + 9261 => true, + 9262 => true, + 9263 => true, + 9264 => true, + 9265 => true, + 9266 => true, + 9267 => true, + 9268 => true, + 9269 => true, + 9270 => true, + 9271 => true, + 9272 => true, + 9273 => true, + 9274 => true, + 9275 => true, + 9276 => true, + 9277 => true, + 9278 => true, + 9279 => true, + 9291 => true, + 9292 => true, + 9293 => true, + 9294 => true, + 9295 => true, + 9296 => true, + 9297 => true, + 9298 => true, + 9299 => true, + 9300 => true, + 9301 => true, + 9302 => true, + 9303 => true, + 9304 => true, + 9305 => true, + 9306 => true, + 9307 => true, + 9308 => true, + 9309 => true, + 9310 => true, + 9311 => true, + 9352 => true, + 9353 => true, + 9354 => true, + 9355 => true, + 9356 => true, + 9357 => true, + 9358 => true, + 9359 => true, + 9360 => true, + 9361 => true, + 9362 => true, + 9363 => true, + 9364 => true, + 9365 => true, + 9366 => true, + 9367 => true, + 9368 => true, + 9369 => true, + 9370 => true, + 9371 => true, + 11124 => true, + 11125 => true, + 11158 => true, + 11311 => true, + 11359 => true, + 11508 => true, + 11509 => true, + 11510 => true, + 11511 => true, + 11512 => true, + 11558 => true, + 11560 => true, + 11561 => true, + 11562 => true, + 11563 => true, + 11564 => true, + 11566 => true, + 11567 => true, + 11624 => true, + 11625 => true, + 11626 => true, + 11627 => true, + 11628 => true, + 11629 => true, + 11630 => true, + 11633 => true, + 11634 => true, + 11635 => true, + 11636 => true, + 11637 => true, + 11638 => true, + 11639 => true, + 11640 => true, + 11641 => true, + 11642 => true, + 11643 => true, + 11644 => true, + 11645 => true, + 11646 => true, + 11671 => true, + 11672 => true, + 11673 => true, + 11674 => true, + 11675 => true, + 11676 => true, + 11677 => true, + 11678 => true, + 11679 => true, + 11687 => true, + 11695 => true, + 11703 => true, + 11711 => true, + 11719 => true, + 11727 => true, + 11735 => true, + 11743 => true, + 11930 => true, + 12020 => true, + 12021 => true, + 12022 => true, + 12023 => true, + 12024 => true, + 12025 => true, + 12026 => true, + 12027 => true, + 12028 => true, + 12029 => true, + 12030 => true, + 12031 => true, + 12246 => true, + 12247 => true, + 12248 => true, + 12249 => true, + 12250 => true, + 12251 => true, + 12252 => true, + 12253 => true, + 12254 => true, + 12255 => true, + 12256 => true, + 12257 => true, + 12258 => true, + 12259 => true, + 12260 => true, + 12261 => true, + 12262 => true, + 12263 => true, + 12264 => true, + 12265 => true, + 12266 => true, + 12267 => true, + 12268 => true, + 12269 => true, + 12270 => true, + 12271 => true, + 12272 => true, + 12273 => true, + 12274 => true, + 12275 => true, + 12276 => true, + 12277 => true, + 12278 => true, + 12279 => true, + 12280 => true, + 12281 => true, + 12282 => true, + 12283 => true, + 12284 => true, + 12285 => true, + 12286 => true, + 12287 => true, + 12352 => true, + 12439 => true, + 12440 => true, + 12544 => true, + 12545 => true, + 12546 => true, + 12547 => true, + 12548 => true, + 12592 => true, + 12644 => true, + 12687 => true, + 12772 => true, + 12773 => true, + 12774 => true, + 12775 => true, + 12776 => true, + 12777 => true, + 12778 => true, + 12779 => true, + 12780 => true, + 12781 => true, + 12782 => true, + 12783 => true, + 12831 => true, + 13250 => true, + 13255 => true, + 13272 => true, + 40957 => true, + 40958 => true, + 40959 => true, + 42125 => true, + 42126 => true, + 42127 => true, + 42183 => true, + 42184 => true, + 42185 => true, + 42186 => true, + 42187 => true, + 42188 => true, + 42189 => true, + 42190 => true, + 42191 => true, + 42540 => true, + 42541 => true, + 42542 => true, + 42543 => true, + 42544 => true, + 42545 => true, + 42546 => true, + 42547 => true, + 42548 => true, + 42549 => true, + 42550 => true, + 42551 => true, + 42552 => true, + 42553 => true, + 42554 => true, + 42555 => true, + 42556 => true, + 42557 => true, + 42558 => true, + 42559 => true, + 42744 => true, + 42745 => true, + 42746 => true, + 42747 => true, + 42748 => true, + 42749 => true, + 42750 => true, + 42751 => true, + 42944 => true, + 42945 => true, + 43053 => true, + 43054 => true, + 43055 => true, + 43066 => true, + 43067 => true, + 43068 => true, + 43069 => true, + 43070 => true, + 43071 => true, + 43128 => true, + 43129 => true, + 43130 => true, + 43131 => true, + 43132 => true, + 43133 => true, + 43134 => true, + 43135 => true, + 43206 => true, + 43207 => true, + 43208 => true, + 43209 => true, + 43210 => true, + 43211 => true, + 43212 => true, + 43213 => true, + 43226 => true, + 43227 => true, + 43228 => true, + 43229 => true, + 43230 => true, + 43231 => true, + 43348 => true, + 43349 => true, + 43350 => true, + 43351 => true, + 43352 => true, + 43353 => true, + 43354 => true, + 43355 => true, + 43356 => true, + 43357 => true, + 43358 => true, + 43389 => true, + 43390 => true, + 43391 => true, + 43470 => true, + 43482 => true, + 43483 => true, + 43484 => true, + 43485 => true, + 43519 => true, + 43575 => true, + 43576 => true, + 43577 => true, + 43578 => true, + 43579 => true, + 43580 => true, + 43581 => true, + 43582 => true, + 43583 => true, + 43598 => true, + 43599 => true, + 43610 => true, + 43611 => true, + 43715 => true, + 43716 => true, + 43717 => true, + 43718 => true, + 43719 => true, + 43720 => true, + 43721 => true, + 43722 => true, + 43723 => true, + 43724 => true, + 43725 => true, + 43726 => true, + 43727 => true, + 43728 => true, + 43729 => true, + 43730 => true, + 43731 => true, + 43732 => true, + 43733 => true, + 43734 => true, + 43735 => true, + 43736 => true, + 43737 => true, + 43738 => true, + 43767 => true, + 43768 => true, + 43769 => true, + 43770 => true, + 43771 => true, + 43772 => true, + 43773 => true, + 43774 => true, + 43775 => true, + 43776 => true, + 43783 => true, + 43784 => true, + 43791 => true, + 43792 => true, + 43799 => true, + 43800 => true, + 43801 => true, + 43802 => true, + 43803 => true, + 43804 => true, + 43805 => true, + 43806 => true, + 43807 => true, + 43815 => true, + 43823 => true, + 43884 => true, + 43885 => true, + 43886 => true, + 43887 => true, + 44014 => true, + 44015 => true, + 44026 => true, + 44027 => true, + 44028 => true, + 44029 => true, + 44030 => true, + 44031 => true, + 55204 => true, + 55205 => true, + 55206 => true, + 55207 => true, + 55208 => true, + 55209 => true, + 55210 => true, + 55211 => true, + 55212 => true, + 55213 => true, + 55214 => true, + 55215 => true, + 55239 => true, + 55240 => true, + 55241 => true, + 55242 => true, + 55292 => true, + 55293 => true, + 55294 => true, + 55295 => true, + 64110 => true, + 64111 => true, + 64263 => true, + 64264 => true, + 64265 => true, + 64266 => true, + 64267 => true, + 64268 => true, + 64269 => true, + 64270 => true, + 64271 => true, + 64272 => true, + 64273 => true, + 64274 => true, + 64280 => true, + 64281 => true, + 64282 => true, + 64283 => true, + 64284 => true, + 64311 => true, + 64317 => true, + 64319 => true, + 64322 => true, + 64325 => true, + 64450 => true, + 64451 => true, + 64452 => true, + 64453 => true, + 64454 => true, + 64455 => true, + 64456 => true, + 64457 => true, + 64458 => true, + 64459 => true, + 64460 => true, + 64461 => true, + 64462 => true, + 64463 => true, + 64464 => true, + 64465 => true, + 64466 => true, + 64832 => true, + 64833 => true, + 64834 => true, + 64835 => true, + 64836 => true, + 64837 => true, + 64838 => true, + 64839 => true, + 64840 => true, + 64841 => true, + 64842 => true, + 64843 => true, + 64844 => true, + 64845 => true, + 64846 => true, + 64847 => true, + 64912 => true, + 64913 => true, + 64968 => true, + 64969 => true, + 64970 => true, + 64971 => true, + 64972 => true, + 64973 => true, + 64974 => true, + 64975 => true, + 65022 => true, + 65023 => true, + 65042 => true, + 65049 => true, + 65050 => true, + 65051 => true, + 65052 => true, + 65053 => true, + 65054 => true, + 65055 => true, + 65072 => true, + 65106 => true, + 65107 => true, + 65127 => true, + 65132 => true, + 65133 => true, + 65134 => true, + 65135 => true, + 65141 => true, + 65277 => true, + 65278 => true, + 65280 => true, + 65440 => true, + 65471 => true, + 65472 => true, + 65473 => true, + 65480 => true, + 65481 => true, + 65488 => true, + 65489 => true, + 65496 => true, + 65497 => true, + 65501 => true, + 65502 => true, + 65503 => true, + 65511 => true, + 65519 => true, + 65520 => true, + 65521 => true, + 65522 => true, + 65523 => true, + 65524 => true, + 65525 => true, + 65526 => true, + 65527 => true, + 65528 => true, + 65529 => true, + 65530 => true, + 65531 => true, + 65532 => true, + 65533 => true, + 65534 => true, + 65535 => true, + 65548 => true, + 65575 => true, + 65595 => true, + 65598 => true, + 65614 => true, + 65615 => true, + 65787 => true, + 65788 => true, + 65789 => true, + 65790 => true, + 65791 => true, + 65795 => true, + 65796 => true, + 65797 => true, + 65798 => true, + 65844 => true, + 65845 => true, + 65846 => true, + 65935 => true, + 65949 => true, + 65950 => true, + 65951 => true, + 66205 => true, + 66206 => true, + 66207 => true, + 66257 => true, + 66258 => true, + 66259 => true, + 66260 => true, + 66261 => true, + 66262 => true, + 66263 => true, + 66264 => true, + 66265 => true, + 66266 => true, + 66267 => true, + 66268 => true, + 66269 => true, + 66270 => true, + 66271 => true, + 66300 => true, + 66301 => true, + 66302 => true, + 66303 => true, + 66340 => true, + 66341 => true, + 66342 => true, + 66343 => true, + 66344 => true, + 66345 => true, + 66346 => true, + 66347 => true, + 66348 => true, + 66379 => true, + 66380 => true, + 66381 => true, + 66382 => true, + 66383 => true, + 66427 => true, + 66428 => true, + 66429 => true, + 66430 => true, + 66431 => true, + 66462 => true, + 66500 => true, + 66501 => true, + 66502 => true, + 66503 => true, + 66718 => true, + 66719 => true, + 66730 => true, + 66731 => true, + 66732 => true, + 66733 => true, + 66734 => true, + 66735 => true, + 66772 => true, + 66773 => true, + 66774 => true, + 66775 => true, + 66812 => true, + 66813 => true, + 66814 => true, + 66815 => true, + 66856 => true, + 66857 => true, + 66858 => true, + 66859 => true, + 66860 => true, + 66861 => true, + 66862 => true, + 66863 => true, + 66916 => true, + 66917 => true, + 66918 => true, + 66919 => true, + 66920 => true, + 66921 => true, + 66922 => true, + 66923 => true, + 66924 => true, + 66925 => true, + 66926 => true, + 67383 => true, + 67384 => true, + 67385 => true, + 67386 => true, + 67387 => true, + 67388 => true, + 67389 => true, + 67390 => true, + 67391 => true, + 67414 => true, + 67415 => true, + 67416 => true, + 67417 => true, + 67418 => true, + 67419 => true, + 67420 => true, + 67421 => true, + 67422 => true, + 67423 => true, + 67590 => true, + 67591 => true, + 67593 => true, + 67638 => true, + 67641 => true, + 67642 => true, + 67643 => true, + 67645 => true, + 67646 => true, + 67670 => true, + 67743 => true, + 67744 => true, + 67745 => true, + 67746 => true, + 67747 => true, + 67748 => true, + 67749 => true, + 67750 => true, + 67827 => true, + 67830 => true, + 67831 => true, + 67832 => true, + 67833 => true, + 67834 => true, + 67868 => true, + 67869 => true, + 67870 => true, + 67898 => true, + 67899 => true, + 67900 => true, + 67901 => true, + 67902 => true, + 68024 => true, + 68025 => true, + 68026 => true, + 68027 => true, + 68048 => true, + 68049 => true, + 68100 => true, + 68103 => true, + 68104 => true, + 68105 => true, + 68106 => true, + 68107 => true, + 68116 => true, + 68120 => true, + 68150 => true, + 68151 => true, + 68155 => true, + 68156 => true, + 68157 => true, + 68158 => true, + 68169 => true, + 68170 => true, + 68171 => true, + 68172 => true, + 68173 => true, + 68174 => true, + 68175 => true, + 68185 => true, + 68186 => true, + 68187 => true, + 68188 => true, + 68189 => true, + 68190 => true, + 68191 => true, + 68327 => true, + 68328 => true, + 68329 => true, + 68330 => true, + 68343 => true, + 68344 => true, + 68345 => true, + 68346 => true, + 68347 => true, + 68348 => true, + 68349 => true, + 68350 => true, + 68351 => true, + 68406 => true, + 68407 => true, + 68408 => true, + 68438 => true, + 68439 => true, + 68467 => true, + 68468 => true, + 68469 => true, + 68470 => true, + 68471 => true, + 68498 => true, + 68499 => true, + 68500 => true, + 68501 => true, + 68502 => true, + 68503 => true, + 68504 => true, + 68509 => true, + 68510 => true, + 68511 => true, + 68512 => true, + 68513 => true, + 68514 => true, + 68515 => true, + 68516 => true, + 68517 => true, + 68518 => true, + 68519 => true, + 68520 => true, + 68787 => true, + 68788 => true, + 68789 => true, + 68790 => true, + 68791 => true, + 68792 => true, + 68793 => true, + 68794 => true, + 68795 => true, + 68796 => true, + 68797 => true, + 68798 => true, + 68799 => true, + 68851 => true, + 68852 => true, + 68853 => true, + 68854 => true, + 68855 => true, + 68856 => true, + 68857 => true, + 68904 => true, + 68905 => true, + 68906 => true, + 68907 => true, + 68908 => true, + 68909 => true, + 68910 => true, + 68911 => true, + 69247 => true, + 69290 => true, + 69294 => true, + 69295 => true, + 69416 => true, + 69417 => true, + 69418 => true, + 69419 => true, + 69420 => true, + 69421 => true, + 69422 => true, + 69423 => true, + 69580 => true, + 69581 => true, + 69582 => true, + 69583 => true, + 69584 => true, + 69585 => true, + 69586 => true, + 69587 => true, + 69588 => true, + 69589 => true, + 69590 => true, + 69591 => true, + 69592 => true, + 69593 => true, + 69594 => true, + 69595 => true, + 69596 => true, + 69597 => true, + 69598 => true, + 69599 => true, + 69623 => true, + 69624 => true, + 69625 => true, + 69626 => true, + 69627 => true, + 69628 => true, + 69629 => true, + 69630 => true, + 69631 => true, + 69710 => true, + 69711 => true, + 69712 => true, + 69713 => true, + 69744 => true, + 69745 => true, + 69746 => true, + 69747 => true, + 69748 => true, + 69749 => true, + 69750 => true, + 69751 => true, + 69752 => true, + 69753 => true, + 69754 => true, + 69755 => true, + 69756 => true, + 69757 => true, + 69758 => true, + 69821 => true, + 69826 => true, + 69827 => true, + 69828 => true, + 69829 => true, + 69830 => true, + 69831 => true, + 69832 => true, + 69833 => true, + 69834 => true, + 69835 => true, + 69836 => true, + 69837 => true, + 69838 => true, + 69839 => true, + 69865 => true, + 69866 => true, + 69867 => true, + 69868 => true, + 69869 => true, + 69870 => true, + 69871 => true, + 69882 => true, + 69883 => true, + 69884 => true, + 69885 => true, + 69886 => true, + 69887 => true, + 69941 => true, + 69960 => true, + 69961 => true, + 69962 => true, + 69963 => true, + 69964 => true, + 69965 => true, + 69966 => true, + 69967 => true, + 70007 => true, + 70008 => true, + 70009 => true, + 70010 => true, + 70011 => true, + 70012 => true, + 70013 => true, + 70014 => true, + 70015 => true, + 70112 => true, + 70133 => true, + 70134 => true, + 70135 => true, + 70136 => true, + 70137 => true, + 70138 => true, + 70139 => true, + 70140 => true, + 70141 => true, + 70142 => true, + 70143 => true, + 70162 => true, + 70279 => true, + 70281 => true, + 70286 => true, + 70302 => true, + 70314 => true, + 70315 => true, + 70316 => true, + 70317 => true, + 70318 => true, + 70319 => true, + 70379 => true, + 70380 => true, + 70381 => true, + 70382 => true, + 70383 => true, + 70394 => true, + 70395 => true, + 70396 => true, + 70397 => true, + 70398 => true, + 70399 => true, + 70404 => true, + 70413 => true, + 70414 => true, + 70417 => true, + 70418 => true, + 70441 => true, + 70449 => true, + 70452 => true, + 70458 => true, + 70469 => true, + 70470 => true, + 70473 => true, + 70474 => true, + 70478 => true, + 70479 => true, + 70481 => true, + 70482 => true, + 70483 => true, + 70484 => true, + 70485 => true, + 70486 => true, + 70488 => true, + 70489 => true, + 70490 => true, + 70491 => true, + 70492 => true, + 70500 => true, + 70501 => true, + 70509 => true, + 70510 => true, + 70511 => true, + 70748 => true, + 70754 => true, + 70755 => true, + 70756 => true, + 70757 => true, + 70758 => true, + 70759 => true, + 70760 => true, + 70761 => true, + 70762 => true, + 70763 => true, + 70764 => true, + 70765 => true, + 70766 => true, + 70767 => true, + 70768 => true, + 70769 => true, + 70770 => true, + 70771 => true, + 70772 => true, + 70773 => true, + 70774 => true, + 70775 => true, + 70776 => true, + 70777 => true, + 70778 => true, + 70779 => true, + 70780 => true, + 70781 => true, + 70782 => true, + 70783 => true, + 70856 => true, + 70857 => true, + 70858 => true, + 70859 => true, + 70860 => true, + 70861 => true, + 70862 => true, + 70863 => true, + 71094 => true, + 71095 => true, + 71237 => true, + 71238 => true, + 71239 => true, + 71240 => true, + 71241 => true, + 71242 => true, + 71243 => true, + 71244 => true, + 71245 => true, + 71246 => true, + 71247 => true, + 71258 => true, + 71259 => true, + 71260 => true, + 71261 => true, + 71262 => true, + 71263 => true, + 71277 => true, + 71278 => true, + 71279 => true, + 71280 => true, + 71281 => true, + 71282 => true, + 71283 => true, + 71284 => true, + 71285 => true, + 71286 => true, + 71287 => true, + 71288 => true, + 71289 => true, + 71290 => true, + 71291 => true, + 71292 => true, + 71293 => true, + 71294 => true, + 71295 => true, + 71353 => true, + 71354 => true, + 71355 => true, + 71356 => true, + 71357 => true, + 71358 => true, + 71359 => true, + 71451 => true, + 71452 => true, + 71468 => true, + 71469 => true, + 71470 => true, + 71471 => true, + 71923 => true, + 71924 => true, + 71925 => true, + 71926 => true, + 71927 => true, + 71928 => true, + 71929 => true, + 71930 => true, + 71931 => true, + 71932 => true, + 71933 => true, + 71934 => true, + 71943 => true, + 71944 => true, + 71946 => true, + 71947 => true, + 71956 => true, + 71959 => true, + 71990 => true, + 71993 => true, + 71994 => true, + 72007 => true, + 72008 => true, + 72009 => true, + 72010 => true, + 72011 => true, + 72012 => true, + 72013 => true, + 72014 => true, + 72015 => true, + 72104 => true, + 72105 => true, + 72152 => true, + 72153 => true, + 72165 => true, + 72166 => true, + 72167 => true, + 72168 => true, + 72169 => true, + 72170 => true, + 72171 => true, + 72172 => true, + 72173 => true, + 72174 => true, + 72175 => true, + 72176 => true, + 72177 => true, + 72178 => true, + 72179 => true, + 72180 => true, + 72181 => true, + 72182 => true, + 72183 => true, + 72184 => true, + 72185 => true, + 72186 => true, + 72187 => true, + 72188 => true, + 72189 => true, + 72190 => true, + 72191 => true, + 72264 => true, + 72265 => true, + 72266 => true, + 72267 => true, + 72268 => true, + 72269 => true, + 72270 => true, + 72271 => true, + 72355 => true, + 72356 => true, + 72357 => true, + 72358 => true, + 72359 => true, + 72360 => true, + 72361 => true, + 72362 => true, + 72363 => true, + 72364 => true, + 72365 => true, + 72366 => true, + 72367 => true, + 72368 => true, + 72369 => true, + 72370 => true, + 72371 => true, + 72372 => true, + 72373 => true, + 72374 => true, + 72375 => true, + 72376 => true, + 72377 => true, + 72378 => true, + 72379 => true, + 72380 => true, + 72381 => true, + 72382 => true, + 72383 => true, + 72713 => true, + 72759 => true, + 72774 => true, + 72775 => true, + 72776 => true, + 72777 => true, + 72778 => true, + 72779 => true, + 72780 => true, + 72781 => true, + 72782 => true, + 72783 => true, + 72813 => true, + 72814 => true, + 72815 => true, + 72848 => true, + 72849 => true, + 72872 => true, + 72967 => true, + 72970 => true, + 73015 => true, + 73016 => true, + 73017 => true, + 73019 => true, + 73022 => true, + 73032 => true, + 73033 => true, + 73034 => true, + 73035 => true, + 73036 => true, + 73037 => true, + 73038 => true, + 73039 => true, + 73050 => true, + 73051 => true, + 73052 => true, + 73053 => true, + 73054 => true, + 73055 => true, + 73062 => true, + 73065 => true, + 73103 => true, + 73106 => true, + 73113 => true, + 73114 => true, + 73115 => true, + 73116 => true, + 73117 => true, + 73118 => true, + 73119 => true, + 73649 => true, + 73650 => true, + 73651 => true, + 73652 => true, + 73653 => true, + 73654 => true, + 73655 => true, + 73656 => true, + 73657 => true, + 73658 => true, + 73659 => true, + 73660 => true, + 73661 => true, + 73662 => true, + 73663 => true, + 73714 => true, + 73715 => true, + 73716 => true, + 73717 => true, + 73718 => true, + 73719 => true, + 73720 => true, + 73721 => true, + 73722 => true, + 73723 => true, + 73724 => true, + 73725 => true, + 73726 => true, + 74863 => true, + 74869 => true, + 74870 => true, + 74871 => true, + 74872 => true, + 74873 => true, + 74874 => true, + 74875 => true, + 74876 => true, + 74877 => true, + 74878 => true, + 74879 => true, + 78895 => true, + 78896 => true, + 78897 => true, + 78898 => true, + 78899 => true, + 78900 => true, + 78901 => true, + 78902 => true, + 78903 => true, + 78904 => true, + 92729 => true, + 92730 => true, + 92731 => true, + 92732 => true, + 92733 => true, + 92734 => true, + 92735 => true, + 92767 => true, + 92778 => true, + 92779 => true, + 92780 => true, + 92781 => true, + 92910 => true, + 92911 => true, + 92918 => true, + 92919 => true, + 92920 => true, + 92921 => true, + 92922 => true, + 92923 => true, + 92924 => true, + 92925 => true, + 92926 => true, + 92927 => true, + 92998 => true, + 92999 => true, + 93000 => true, + 93001 => true, + 93002 => true, + 93003 => true, + 93004 => true, + 93005 => true, + 93006 => true, + 93007 => true, + 93018 => true, + 93026 => true, + 93048 => true, + 93049 => true, + 93050 => true, + 93051 => true, + 93052 => true, + 94027 => true, + 94028 => true, + 94029 => true, + 94030 => true, + 94088 => true, + 94089 => true, + 94090 => true, + 94091 => true, + 94092 => true, + 94093 => true, + 94094 => true, + 94181 => true, + 94182 => true, + 94183 => true, + 94184 => true, + 94185 => true, + 94186 => true, + 94187 => true, + 94188 => true, + 94189 => true, + 94190 => true, + 94191 => true, + 94194 => true, + 94195 => true, + 94196 => true, + 94197 => true, + 94198 => true, + 94199 => true, + 94200 => true, + 94201 => true, + 94202 => true, + 94203 => true, + 94204 => true, + 94205 => true, + 94206 => true, + 94207 => true, + 100344 => true, + 100345 => true, + 100346 => true, + 100347 => true, + 100348 => true, + 100349 => true, + 100350 => true, + 100351 => true, + 110931 => true, + 110932 => true, + 110933 => true, + 110934 => true, + 110935 => true, + 110936 => true, + 110937 => true, + 110938 => true, + 110939 => true, + 110940 => true, + 110941 => true, + 110942 => true, + 110943 => true, + 110944 => true, + 110945 => true, + 110946 => true, + 110947 => true, + 110952 => true, + 110953 => true, + 110954 => true, + 110955 => true, + 110956 => true, + 110957 => true, + 110958 => true, + 110959 => true, + 113771 => true, + 113772 => true, + 113773 => true, + 113774 => true, + 113775 => true, + 113789 => true, + 113790 => true, + 113791 => true, + 113801 => true, + 113802 => true, + 113803 => true, + 113804 => true, + 113805 => true, + 113806 => true, + 113807 => true, + 113818 => true, + 113819 => true, + 119030 => true, + 119031 => true, + 119032 => true, + 119033 => true, + 119034 => true, + 119035 => true, + 119036 => true, + 119037 => true, + 119038 => true, + 119039 => true, + 119079 => true, + 119080 => true, + 119155 => true, + 119156 => true, + 119157 => true, + 119158 => true, + 119159 => true, + 119160 => true, + 119161 => true, + 119162 => true, + 119273 => true, + 119274 => true, + 119275 => true, + 119276 => true, + 119277 => true, + 119278 => true, + 119279 => true, + 119280 => true, + 119281 => true, + 119282 => true, + 119283 => true, + 119284 => true, + 119285 => true, + 119286 => true, + 119287 => true, + 119288 => true, + 119289 => true, + 119290 => true, + 119291 => true, + 119292 => true, + 119293 => true, + 119294 => true, + 119295 => true, + 119540 => true, + 119541 => true, + 119542 => true, + 119543 => true, + 119544 => true, + 119545 => true, + 119546 => true, + 119547 => true, + 119548 => true, + 119549 => true, + 119550 => true, + 119551 => true, + 119639 => true, + 119640 => true, + 119641 => true, + 119642 => true, + 119643 => true, + 119644 => true, + 119645 => true, + 119646 => true, + 119647 => true, + 119893 => true, + 119965 => true, + 119968 => true, + 119969 => true, + 119971 => true, + 119972 => true, + 119975 => true, + 119976 => true, + 119981 => true, + 119994 => true, + 119996 => true, + 120004 => true, + 120070 => true, + 120075 => true, + 120076 => true, + 120085 => true, + 120093 => true, + 120122 => true, + 120127 => true, + 120133 => true, + 120135 => true, + 120136 => true, + 120137 => true, + 120145 => true, + 120486 => true, + 120487 => true, + 120780 => true, + 120781 => true, + 121484 => true, + 121485 => true, + 121486 => true, + 121487 => true, + 121488 => true, + 121489 => true, + 121490 => true, + 121491 => true, + 121492 => true, + 121493 => true, + 121494 => true, + 121495 => true, + 121496 => true, + 121497 => true, + 121498 => true, + 121504 => true, + 122887 => true, + 122905 => true, + 122906 => true, + 122914 => true, + 122917 => true, + 123181 => true, + 123182 => true, + 123183 => true, + 123198 => true, + 123199 => true, + 123210 => true, + 123211 => true, + 123212 => true, + 123213 => true, + 123642 => true, + 123643 => true, + 123644 => true, + 123645 => true, + 123646 => true, + 125125 => true, + 125126 => true, + 125260 => true, + 125261 => true, + 125262 => true, + 125263 => true, + 125274 => true, + 125275 => true, + 125276 => true, + 125277 => true, + 126468 => true, + 126496 => true, + 126499 => true, + 126501 => true, + 126502 => true, + 126504 => true, + 126515 => true, + 126520 => true, + 126522 => true, + 126524 => true, + 126525 => true, + 126526 => true, + 126527 => true, + 126528 => true, + 126529 => true, + 126531 => true, + 126532 => true, + 126533 => true, + 126534 => true, + 126536 => true, + 126538 => true, + 126540 => true, + 126544 => true, + 126547 => true, + 126549 => true, + 126550 => true, + 126552 => true, + 126554 => true, + 126556 => true, + 126558 => true, + 126560 => true, + 126563 => true, + 126565 => true, + 126566 => true, + 126571 => true, + 126579 => true, + 126584 => true, + 126589 => true, + 126591 => true, + 126602 => true, + 126620 => true, + 126621 => true, + 126622 => true, + 126623 => true, + 126624 => true, + 126628 => true, + 126634 => true, + 127020 => true, + 127021 => true, + 127022 => true, + 127023 => true, + 127124 => true, + 127125 => true, + 127126 => true, + 127127 => true, + 127128 => true, + 127129 => true, + 127130 => true, + 127131 => true, + 127132 => true, + 127133 => true, + 127134 => true, + 127135 => true, + 127151 => true, + 127152 => true, + 127168 => true, + 127184 => true, + 127222 => true, + 127223 => true, + 127224 => true, + 127225 => true, + 127226 => true, + 127227 => true, + 127228 => true, + 127229 => true, + 127230 => true, + 127231 => true, + 127232 => true, + 127491 => true, + 127492 => true, + 127493 => true, + 127494 => true, + 127495 => true, + 127496 => true, + 127497 => true, + 127498 => true, + 127499 => true, + 127500 => true, + 127501 => true, + 127502 => true, + 127503 => true, + 127548 => true, + 127549 => true, + 127550 => true, + 127551 => true, + 127561 => true, + 127562 => true, + 127563 => true, + 127564 => true, + 127565 => true, + 127566 => true, + 127567 => true, + 127570 => true, + 127571 => true, + 127572 => true, + 127573 => true, + 127574 => true, + 127575 => true, + 127576 => true, + 127577 => true, + 127578 => true, + 127579 => true, + 127580 => true, + 127581 => true, + 127582 => true, + 127583 => true, + 128728 => true, + 128729 => true, + 128730 => true, + 128731 => true, + 128732 => true, + 128733 => true, + 128734 => true, + 128735 => true, + 128749 => true, + 128750 => true, + 128751 => true, + 128765 => true, + 128766 => true, + 128767 => true, + 128884 => true, + 128885 => true, + 128886 => true, + 128887 => true, + 128888 => true, + 128889 => true, + 128890 => true, + 128891 => true, + 128892 => true, + 128893 => true, + 128894 => true, + 128895 => true, + 128985 => true, + 128986 => true, + 128987 => true, + 128988 => true, + 128989 => true, + 128990 => true, + 128991 => true, + 129004 => true, + 129005 => true, + 129006 => true, + 129007 => true, + 129008 => true, + 129009 => true, + 129010 => true, + 129011 => true, + 129012 => true, + 129013 => true, + 129014 => true, + 129015 => true, + 129016 => true, + 129017 => true, + 129018 => true, + 129019 => true, + 129020 => true, + 129021 => true, + 129022 => true, + 129023 => true, + 129036 => true, + 129037 => true, + 129038 => true, + 129039 => true, + 129096 => true, + 129097 => true, + 129098 => true, + 129099 => true, + 129100 => true, + 129101 => true, + 129102 => true, + 129103 => true, + 129114 => true, + 129115 => true, + 129116 => true, + 129117 => true, + 129118 => true, + 129119 => true, + 129160 => true, + 129161 => true, + 129162 => true, + 129163 => true, + 129164 => true, + 129165 => true, + 129166 => true, + 129167 => true, + 129198 => true, + 129199 => true, + 129401 => true, + 129484 => true, + 129620 => true, + 129621 => true, + 129622 => true, + 129623 => true, + 129624 => true, + 129625 => true, + 129626 => true, + 129627 => true, + 129628 => true, + 129629 => true, + 129630 => true, + 129631 => true, + 129646 => true, + 129647 => true, + 129653 => true, + 129654 => true, + 129655 => true, + 129659 => true, + 129660 => true, + 129661 => true, + 129662 => true, + 129663 => true, + 129671 => true, + 129672 => true, + 129673 => true, + 129674 => true, + 129675 => true, + 129676 => true, + 129677 => true, + 129678 => true, + 129679 => true, + 129705 => true, + 129706 => true, + 129707 => true, + 129708 => true, + 129709 => true, + 129710 => true, + 129711 => true, + 129719 => true, + 129720 => true, + 129721 => true, + 129722 => true, + 129723 => true, + 129724 => true, + 129725 => true, + 129726 => true, + 129727 => true, + 129731 => true, + 129732 => true, + 129733 => true, + 129734 => true, + 129735 => true, + 129736 => true, + 129737 => true, + 129738 => true, + 129739 => true, + 129740 => true, + 129741 => true, + 129742 => true, + 129743 => true, + 129939 => true, + 131070 => true, + 131071 => true, + 177973 => true, + 177974 => true, + 177975 => true, + 177976 => true, + 177977 => true, + 177978 => true, + 177979 => true, + 177980 => true, + 177981 => true, + 177982 => true, + 177983 => true, + 178206 => true, + 178207 => true, + 183970 => true, + 183971 => true, + 183972 => true, + 183973 => true, + 183974 => true, + 183975 => true, + 183976 => true, + 183977 => true, + 183978 => true, + 183979 => true, + 183980 => true, + 183981 => true, + 183982 => true, + 183983 => true, + 194664 => true, + 194676 => true, + 194847 => true, + 194911 => true, + 195007 => true, + 196606 => true, + 196607 => true, + 262142 => true, + 262143 => true, + 327678 => true, + 327679 => true, + 393214 => true, + 393215 => true, + 458750 => true, + 458751 => true, + 524286 => true, + 524287 => true, + 589822 => true, + 589823 => true, + 655358 => true, + 655359 => true, + 720894 => true, + 720895 => true, + 786430 => true, + 786431 => true, + 851966 => true, + 851967 => true, + 917502 => true, + 917503 => true, + 917504 => true, + 917505 => true, + 917506 => true, + 917507 => true, + 917508 => true, + 917509 => true, + 917510 => true, + 917511 => true, + 917512 => true, + 917513 => true, + 917514 => true, + 917515 => true, + 917516 => true, + 917517 => true, + 917518 => true, + 917519 => true, + 917520 => true, + 917521 => true, + 917522 => true, + 917523 => true, + 917524 => true, + 917525 => true, + 917526 => true, + 917527 => true, + 917528 => true, + 917529 => true, + 917530 => true, + 917531 => true, + 917532 => true, + 917533 => true, + 917534 => true, + 917535 => true, + 983038 => true, + 983039 => true, + 1048574 => true, + 1048575 => true, + 1114110 => true, + 1114111 => true, +); diff --git a/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php new file mode 100644 index 000000000..54f21cc0c --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php @@ -0,0 +1,308 @@ + ' ', + 168 => ' ̈', + 175 => ' ̄', + 180 => ' ́', + 184 => ' ̧', + 728 => ' ̆', + 729 => ' ̇', + 730 => ' ̊', + 731 => ' ̨', + 732 => ' ̃', + 733 => ' ̋', + 890 => ' ι', + 894 => ';', + 900 => ' ́', + 901 => ' ̈́', + 8125 => ' ̓', + 8127 => ' ̓', + 8128 => ' ͂', + 8129 => ' ̈͂', + 8141 => ' ̓̀', + 8142 => ' ̓́', + 8143 => ' ̓͂', + 8157 => ' ̔̀', + 8158 => ' ̔́', + 8159 => ' ̔͂', + 8173 => ' ̈̀', + 8174 => ' ̈́', + 8175 => '`', + 8189 => ' ́', + 8190 => ' ̔', + 8192 => ' ', + 8193 => ' ', + 8194 => ' ', + 8195 => ' ', + 8196 => ' ', + 8197 => ' ', + 8198 => ' ', + 8199 => ' ', + 8200 => ' ', + 8201 => ' ', + 8202 => ' ', + 8215 => ' ̳', + 8239 => ' ', + 8252 => '!!', + 8254 => ' ̅', + 8263 => '??', + 8264 => '?!', + 8265 => '!?', + 8287 => ' ', + 8314 => '+', + 8316 => '=', + 8317 => '(', + 8318 => ')', + 8330 => '+', + 8332 => '=', + 8333 => '(', + 8334 => ')', + 8448 => 'a/c', + 8449 => 'a/s', + 8453 => 'c/o', + 8454 => 'c/u', + 9332 => '(1)', + 9333 => '(2)', + 9334 => '(3)', + 9335 => '(4)', + 9336 => '(5)', + 9337 => '(6)', + 9338 => '(7)', + 9339 => '(8)', + 9340 => '(9)', + 9341 => '(10)', + 9342 => '(11)', + 9343 => '(12)', + 9344 => '(13)', + 9345 => '(14)', + 9346 => '(15)', + 9347 => '(16)', + 9348 => '(17)', + 9349 => '(18)', + 9350 => '(19)', + 9351 => '(20)', + 9372 => '(a)', + 9373 => '(b)', + 9374 => '(c)', + 9375 => '(d)', + 9376 => '(e)', + 9377 => '(f)', + 9378 => '(g)', + 9379 => '(h)', + 9380 => '(i)', + 9381 => '(j)', + 9382 => '(k)', + 9383 => '(l)', + 9384 => '(m)', + 9385 => '(n)', + 9386 => '(o)', + 9387 => '(p)', + 9388 => '(q)', + 9389 => '(r)', + 9390 => '(s)', + 9391 => '(t)', + 9392 => '(u)', + 9393 => '(v)', + 9394 => '(w)', + 9395 => '(x)', + 9396 => '(y)', + 9397 => '(z)', + 10868 => '::=', + 10869 => '==', + 10870 => '===', + 12288 => ' ', + 12443 => ' ゙', + 12444 => ' ゚', + 12800 => '(ᄀ)', + 12801 => '(ᄂ)', + 12802 => '(ᄃ)', + 12803 => '(ᄅ)', + 12804 => '(ᄆ)', + 12805 => '(ᄇ)', + 12806 => '(ᄉ)', + 12807 => '(ᄋ)', + 12808 => '(ᄌ)', + 12809 => '(ᄎ)', + 12810 => '(ᄏ)', + 12811 => '(ᄐ)', + 12812 => '(ᄑ)', + 12813 => '(ᄒ)', + 12814 => '(가)', + 12815 => '(나)', + 12816 => '(다)', + 12817 => '(라)', + 12818 => '(마)', + 12819 => '(바)', + 12820 => '(사)', + 12821 => '(아)', + 12822 => '(자)', + 12823 => '(차)', + 12824 => '(카)', + 12825 => '(타)', + 12826 => '(파)', + 12827 => '(하)', + 12828 => '(주)', + 12829 => '(오전)', + 12830 => '(오후)', + 12832 => '(一)', + 12833 => '(二)', + 12834 => '(三)', + 12835 => '(四)', + 12836 => '(五)', + 12837 => '(六)', + 12838 => '(七)', + 12839 => '(八)', + 12840 => '(九)', + 12841 => '(十)', + 12842 => '(月)', + 12843 => '(火)', + 12844 => '(水)', + 12845 => '(木)', + 12846 => '(金)', + 12847 => '(土)', + 12848 => '(日)', + 12849 => '(株)', + 12850 => '(有)', + 12851 => '(社)', + 12852 => '(名)', + 12853 => '(特)', + 12854 => '(財)', + 12855 => '(祝)', + 12856 => '(労)', + 12857 => '(代)', + 12858 => '(呼)', + 12859 => '(学)', + 12860 => '(監)', + 12861 => '(企)', + 12862 => '(資)', + 12863 => '(協)', + 12864 => '(祭)', + 12865 => '(休)', + 12866 => '(自)', + 12867 => '(至)', + 64297 => '+', + 64606 => ' ٌّ', + 64607 => ' ٍّ', + 64608 => ' َّ', + 64609 => ' ُّ', + 64610 => ' ِّ', + 64611 => ' ّٰ', + 65018 => 'صلى الله عليه وسلم', + 65019 => 'جل جلاله', + 65040 => ',', + 65043 => ':', + 65044 => ';', + 65045 => '!', + 65046 => '?', + 65075 => '_', + 65076 => '_', + 65077 => '(', + 65078 => ')', + 65079 => '{', + 65080 => '}', + 65095 => '[', + 65096 => ']', + 65097 => ' ̅', + 65098 => ' ̅', + 65099 => ' ̅', + 65100 => ' ̅', + 65101 => '_', + 65102 => '_', + 65103 => '_', + 65104 => ',', + 65108 => ';', + 65109 => ':', + 65110 => '?', + 65111 => '!', + 65113 => '(', + 65114 => ')', + 65115 => '{', + 65116 => '}', + 65119 => '#', + 65120 => '&', + 65121 => '*', + 65122 => '+', + 65124 => '<', + 65125 => '>', + 65126 => '=', + 65128 => '\\', + 65129 => '$', + 65130 => '%', + 65131 => '@', + 65136 => ' ً', + 65138 => ' ٌ', + 65140 => ' ٍ', + 65142 => ' َ', + 65144 => ' ُ', + 65146 => ' ِ', + 65148 => ' ّ', + 65150 => ' ْ', + 65281 => '!', + 65282 => '"', + 65283 => '#', + 65284 => '$', + 65285 => '%', + 65286 => '&', + 65287 => '\'', + 65288 => '(', + 65289 => ')', + 65290 => '*', + 65291 => '+', + 65292 => ',', + 65295 => '/', + 65306 => ':', + 65307 => ';', + 65308 => '<', + 65309 => '=', + 65310 => '>', + 65311 => '?', + 65312 => '@', + 65339 => '[', + 65340 => '\\', + 65341 => ']', + 65342 => '^', + 65343 => '_', + 65344 => '`', + 65371 => '{', + 65372 => '|', + 65373 => '}', + 65374 => '~', + 65507 => ' ̄', + 127233 => '0,', + 127234 => '1,', + 127235 => '2,', + 127236 => '3,', + 127237 => '4,', + 127238 => '5,', + 127239 => '6,', + 127240 => '7,', + 127241 => '8,', + 127242 => '9,', + 127248 => '(a)', + 127249 => '(b)', + 127250 => '(c)', + 127251 => '(d)', + 127252 => '(e)', + 127253 => '(f)', + 127254 => '(g)', + 127255 => '(h)', + 127256 => '(i)', + 127257 => '(j)', + 127258 => '(k)', + 127259 => '(l)', + 127260 => '(m)', + 127261 => '(n)', + 127262 => '(o)', + 127263 => '(p)', + 127264 => '(q)', + 127265 => '(r)', + 127266 => '(s)', + 127267 => '(t)', + 127268 => '(u)', + 127269 => '(v)', + 127270 => '(w)', + 127271 => '(x)', + 127272 => '(y)', + 127273 => '(z)', +); diff --git a/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php new file mode 100644 index 000000000..223396ec4 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php @@ -0,0 +1,71 @@ + true, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true, + 6 => true, + 7 => true, + 8 => true, + 9 => true, + 10 => true, + 11 => true, + 12 => true, + 13 => true, + 14 => true, + 15 => true, + 16 => true, + 17 => true, + 18 => true, + 19 => true, + 20 => true, + 21 => true, + 22 => true, + 23 => true, + 24 => true, + 25 => true, + 26 => true, + 27 => true, + 28 => true, + 29 => true, + 30 => true, + 31 => true, + 32 => true, + 33 => true, + 34 => true, + 35 => true, + 36 => true, + 37 => true, + 38 => true, + 39 => true, + 40 => true, + 41 => true, + 42 => true, + 43 => true, + 44 => true, + 47 => true, + 58 => true, + 59 => true, + 60 => true, + 61 => true, + 62 => true, + 63 => true, + 64 => true, + 91 => true, + 92 => true, + 93 => true, + 94 => true, + 95 => true, + 96 => true, + 123 => true, + 124 => true, + 125 => true, + 126 => true, + 127 => true, + 8800 => true, + 8814 => true, + 8815 => true, +); diff --git a/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/ignored.php b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/ignored.php new file mode 100644 index 000000000..b37784413 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/ignored.php @@ -0,0 +1,273 @@ + true, + 847 => true, + 6155 => true, + 6156 => true, + 6157 => true, + 8203 => true, + 8288 => true, + 8292 => true, + 65024 => true, + 65025 => true, + 65026 => true, + 65027 => true, + 65028 => true, + 65029 => true, + 65030 => true, + 65031 => true, + 65032 => true, + 65033 => true, + 65034 => true, + 65035 => true, + 65036 => true, + 65037 => true, + 65038 => true, + 65039 => true, + 65279 => true, + 113824 => true, + 113825 => true, + 113826 => true, + 113827 => true, + 917760 => true, + 917761 => true, + 917762 => true, + 917763 => true, + 917764 => true, + 917765 => true, + 917766 => true, + 917767 => true, + 917768 => true, + 917769 => true, + 917770 => true, + 917771 => true, + 917772 => true, + 917773 => true, + 917774 => true, + 917775 => true, + 917776 => true, + 917777 => true, + 917778 => true, + 917779 => true, + 917780 => true, + 917781 => true, + 917782 => true, + 917783 => true, + 917784 => true, + 917785 => true, + 917786 => true, + 917787 => true, + 917788 => true, + 917789 => true, + 917790 => true, + 917791 => true, + 917792 => true, + 917793 => true, + 917794 => true, + 917795 => true, + 917796 => true, + 917797 => true, + 917798 => true, + 917799 => true, + 917800 => true, + 917801 => true, + 917802 => true, + 917803 => true, + 917804 => true, + 917805 => true, + 917806 => true, + 917807 => true, + 917808 => true, + 917809 => true, + 917810 => true, + 917811 => true, + 917812 => true, + 917813 => true, + 917814 => true, + 917815 => true, + 917816 => true, + 917817 => true, + 917818 => true, + 917819 => true, + 917820 => true, + 917821 => true, + 917822 => true, + 917823 => true, + 917824 => true, + 917825 => true, + 917826 => true, + 917827 => true, + 917828 => true, + 917829 => true, + 917830 => true, + 917831 => true, + 917832 => true, + 917833 => true, + 917834 => true, + 917835 => true, + 917836 => true, + 917837 => true, + 917838 => true, + 917839 => true, + 917840 => true, + 917841 => true, + 917842 => true, + 917843 => true, + 917844 => true, + 917845 => true, + 917846 => true, + 917847 => true, + 917848 => true, + 917849 => true, + 917850 => true, + 917851 => true, + 917852 => true, + 917853 => true, + 917854 => true, + 917855 => true, + 917856 => true, + 917857 => true, + 917858 => true, + 917859 => true, + 917860 => true, + 917861 => true, + 917862 => true, + 917863 => true, + 917864 => true, + 917865 => true, + 917866 => true, + 917867 => true, + 917868 => true, + 917869 => true, + 917870 => true, + 917871 => true, + 917872 => true, + 917873 => true, + 917874 => true, + 917875 => true, + 917876 => true, + 917877 => true, + 917878 => true, + 917879 => true, + 917880 => true, + 917881 => true, + 917882 => true, + 917883 => true, + 917884 => true, + 917885 => true, + 917886 => true, + 917887 => true, + 917888 => true, + 917889 => true, + 917890 => true, + 917891 => true, + 917892 => true, + 917893 => true, + 917894 => true, + 917895 => true, + 917896 => true, + 917897 => true, + 917898 => true, + 917899 => true, + 917900 => true, + 917901 => true, + 917902 => true, + 917903 => true, + 917904 => true, + 917905 => true, + 917906 => true, + 917907 => true, + 917908 => true, + 917909 => true, + 917910 => true, + 917911 => true, + 917912 => true, + 917913 => true, + 917914 => true, + 917915 => true, + 917916 => true, + 917917 => true, + 917918 => true, + 917919 => true, + 917920 => true, + 917921 => true, + 917922 => true, + 917923 => true, + 917924 => true, + 917925 => true, + 917926 => true, + 917927 => true, + 917928 => true, + 917929 => true, + 917930 => true, + 917931 => true, + 917932 => true, + 917933 => true, + 917934 => true, + 917935 => true, + 917936 => true, + 917937 => true, + 917938 => true, + 917939 => true, + 917940 => true, + 917941 => true, + 917942 => true, + 917943 => true, + 917944 => true, + 917945 => true, + 917946 => true, + 917947 => true, + 917948 => true, + 917949 => true, + 917950 => true, + 917951 => true, + 917952 => true, + 917953 => true, + 917954 => true, + 917955 => true, + 917956 => true, + 917957 => true, + 917958 => true, + 917959 => true, + 917960 => true, + 917961 => true, + 917962 => true, + 917963 => true, + 917964 => true, + 917965 => true, + 917966 => true, + 917967 => true, + 917968 => true, + 917969 => true, + 917970 => true, + 917971 => true, + 917972 => true, + 917973 => true, + 917974 => true, + 917975 => true, + 917976 => true, + 917977 => true, + 917978 => true, + 917979 => true, + 917980 => true, + 917981 => true, + 917982 => true, + 917983 => true, + 917984 => true, + 917985 => true, + 917986 => true, + 917987 => true, + 917988 => true, + 917989 => true, + 917990 => true, + 917991 => true, + 917992 => true, + 917993 => true, + 917994 => true, + 917995 => true, + 917996 => true, + 917997 => true, + 917998 => true, + 917999 => true, +); diff --git a/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/mapped.php b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/mapped.php new file mode 100644 index 000000000..9b85fe9d3 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/mapped.php @@ -0,0 +1,5778 @@ + 'a', + 66 => 'b', + 67 => 'c', + 68 => 'd', + 69 => 'e', + 70 => 'f', + 71 => 'g', + 72 => 'h', + 73 => 'i', + 74 => 'j', + 75 => 'k', + 76 => 'l', + 77 => 'm', + 78 => 'n', + 79 => 'o', + 80 => 'p', + 81 => 'q', + 82 => 'r', + 83 => 's', + 84 => 't', + 85 => 'u', + 86 => 'v', + 87 => 'w', + 88 => 'x', + 89 => 'y', + 90 => 'z', + 170 => 'a', + 178 => '2', + 179 => '3', + 181 => 'μ', + 185 => '1', + 186 => 'o', + 188 => '1⁄4', + 189 => '1⁄2', + 190 => '3⁄4', + 192 => 'à', + 193 => 'á', + 194 => 'â', + 195 => 'ã', + 196 => 'ä', + 197 => 'å', + 198 => 'æ', + 199 => 'ç', + 200 => 'è', + 201 => 'é', + 202 => 'ê', + 203 => 'ë', + 204 => 'ì', + 205 => 'í', + 206 => 'î', + 207 => 'ï', + 208 => 'ð', + 209 => 'ñ', + 210 => 'ò', + 211 => 'ó', + 212 => 'ô', + 213 => 'õ', + 214 => 'ö', + 216 => 'ø', + 217 => 'ù', + 218 => 'ú', + 219 => 'û', + 220 => 'ü', + 221 => 'ý', + 222 => 'þ', + 256 => 'ā', + 258 => 'ă', + 260 => 'ą', + 262 => 'ć', + 264 => 'ĉ', + 266 => 'ċ', + 268 => 'č', + 270 => 'ď', + 272 => 'đ', + 274 => 'ē', + 276 => 'ĕ', + 278 => 'ė', + 280 => 'ę', + 282 => 'ě', + 284 => 'ĝ', + 286 => 'ğ', + 288 => 'ġ', + 290 => 'ģ', + 292 => 'ĥ', + 294 => 'ħ', + 296 => 'ĩ', + 298 => 'ī', + 300 => 'ĭ', + 302 => 'į', + 304 => 'i̇', + 306 => 'ij', + 307 => 'ij', + 308 => 'ĵ', + 310 => 'ķ', + 313 => 'ĺ', + 315 => 'ļ', + 317 => 'ľ', + 319 => 'l·', + 320 => 'l·', + 321 => 'ł', + 323 => 'ń', + 325 => 'ņ', + 327 => 'ň', + 329 => 'ʼn', + 330 => 'ŋ', + 332 => 'ō', + 334 => 'ŏ', + 336 => 'ő', + 338 => 'œ', + 340 => 'ŕ', + 342 => 'ŗ', + 344 => 'ř', + 346 => 'ś', + 348 => 'ŝ', + 350 => 'ş', + 352 => 'š', + 354 => 'ţ', + 356 => 'ť', + 358 => 'ŧ', + 360 => 'ũ', + 362 => 'ū', + 364 => 'ŭ', + 366 => 'ů', + 368 => 'ű', + 370 => 'ų', + 372 => 'ŵ', + 374 => 'ŷ', + 376 => 'ÿ', + 377 => 'ź', + 379 => 'ż', + 381 => 'ž', + 383 => 's', + 385 => 'ɓ', + 386 => 'ƃ', + 388 => 'ƅ', + 390 => 'ɔ', + 391 => 'ƈ', + 393 => 'ɖ', + 394 => 'ɗ', + 395 => 'ƌ', + 398 => 'ǝ', + 399 => 'ə', + 400 => 'ɛ', + 401 => 'ƒ', + 403 => 'ɠ', + 404 => 'ɣ', + 406 => 'ɩ', + 407 => 'ɨ', + 408 => 'ƙ', + 412 => 'ɯ', + 413 => 'ɲ', + 415 => 'ɵ', + 416 => 'ơ', + 418 => 'ƣ', + 420 => 'ƥ', + 422 => 'ʀ', + 423 => 'ƨ', + 425 => 'ʃ', + 428 => 'ƭ', + 430 => 'ʈ', + 431 => 'ư', + 433 => 'ʊ', + 434 => 'ʋ', + 435 => 'ƴ', + 437 => 'ƶ', + 439 => 'ʒ', + 440 => 'ƹ', + 444 => 'ƽ', + 452 => 'dž', + 453 => 'dž', + 454 => 'dž', + 455 => 'lj', + 456 => 'lj', + 457 => 'lj', + 458 => 'nj', + 459 => 'nj', + 460 => 'nj', + 461 => 'ǎ', + 463 => 'ǐ', + 465 => 'ǒ', + 467 => 'ǔ', + 469 => 'ǖ', + 471 => 'ǘ', + 473 => 'ǚ', + 475 => 'ǜ', + 478 => 'ǟ', + 480 => 'ǡ', + 482 => 'ǣ', + 484 => 'ǥ', + 486 => 'ǧ', + 488 => 'ǩ', + 490 => 'ǫ', + 492 => 'ǭ', + 494 => 'ǯ', + 497 => 'dz', + 498 => 'dz', + 499 => 'dz', + 500 => 'ǵ', + 502 => 'ƕ', + 503 => 'ƿ', + 504 => 'ǹ', + 506 => 'ǻ', + 508 => 'ǽ', + 510 => 'ǿ', + 512 => 'ȁ', + 514 => 'ȃ', + 516 => 'ȅ', + 518 => 'ȇ', + 520 => 'ȉ', + 522 => 'ȋ', + 524 => 'ȍ', + 526 => 'ȏ', + 528 => 'ȑ', + 530 => 'ȓ', + 532 => 'ȕ', + 534 => 'ȗ', + 536 => 'ș', + 538 => 'ț', + 540 => 'ȝ', + 542 => 'ȟ', + 544 => 'ƞ', + 546 => 'ȣ', + 548 => 'ȥ', + 550 => 'ȧ', + 552 => 'ȩ', + 554 => 'ȫ', + 556 => 'ȭ', + 558 => 'ȯ', + 560 => 'ȱ', + 562 => 'ȳ', + 570 => 'ⱥ', + 571 => 'ȼ', + 573 => 'ƚ', + 574 => 'ⱦ', + 577 => 'ɂ', + 579 => 'ƀ', + 580 => 'ʉ', + 581 => 'ʌ', + 582 => 'ɇ', + 584 => 'ɉ', + 586 => 'ɋ', + 588 => 'ɍ', + 590 => 'ɏ', + 688 => 'h', + 689 => 'ɦ', + 690 => 'j', + 691 => 'r', + 692 => 'ɹ', + 693 => 'ɻ', + 694 => 'ʁ', + 695 => 'w', + 696 => 'y', + 736 => 'ɣ', + 737 => 'l', + 738 => 's', + 739 => 'x', + 740 => 'ʕ', + 832 => '̀', + 833 => '́', + 835 => '̓', + 836 => '̈́', + 837 => 'ι', + 880 => 'ͱ', + 882 => 'ͳ', + 884 => 'ʹ', + 886 => 'ͷ', + 895 => 'ϳ', + 902 => 'ά', + 903 => '·', + 904 => 'έ', + 905 => 'ή', + 906 => 'ί', + 908 => 'ό', + 910 => 'ύ', + 911 => 'ώ', + 913 => 'α', + 914 => 'β', + 915 => 'γ', + 916 => 'δ', + 917 => 'ε', + 918 => 'ζ', + 919 => 'η', + 920 => 'θ', + 921 => 'ι', + 922 => 'κ', + 923 => 'λ', + 924 => 'μ', + 925 => 'ν', + 926 => 'ξ', + 927 => 'ο', + 928 => 'π', + 929 => 'ρ', + 931 => 'σ', + 932 => 'τ', + 933 => 'υ', + 934 => 'φ', + 935 => 'χ', + 936 => 'ψ', + 937 => 'ω', + 938 => 'ϊ', + 939 => 'ϋ', + 975 => 'ϗ', + 976 => 'β', + 977 => 'θ', + 978 => 'υ', + 979 => 'ύ', + 980 => 'ϋ', + 981 => 'φ', + 982 => 'π', + 984 => 'ϙ', + 986 => 'ϛ', + 988 => 'ϝ', + 990 => 'ϟ', + 992 => 'ϡ', + 994 => 'ϣ', + 996 => 'ϥ', + 998 => 'ϧ', + 1000 => 'ϩ', + 1002 => 'ϫ', + 1004 => 'ϭ', + 1006 => 'ϯ', + 1008 => 'κ', + 1009 => 'ρ', + 1010 => 'σ', + 1012 => 'θ', + 1013 => 'ε', + 1015 => 'ϸ', + 1017 => 'σ', + 1018 => 'ϻ', + 1021 => 'ͻ', + 1022 => 'ͼ', + 1023 => 'ͽ', + 1024 => 'ѐ', + 1025 => 'ё', + 1026 => 'ђ', + 1027 => 'ѓ', + 1028 => 'є', + 1029 => 'ѕ', + 1030 => 'і', + 1031 => 'ї', + 1032 => 'ј', + 1033 => 'љ', + 1034 => 'њ', + 1035 => 'ћ', + 1036 => 'ќ', + 1037 => 'ѝ', + 1038 => 'ў', + 1039 => 'џ', + 1040 => 'а', + 1041 => 'б', + 1042 => 'в', + 1043 => 'г', + 1044 => 'д', + 1045 => 'е', + 1046 => 'ж', + 1047 => 'з', + 1048 => 'и', + 1049 => 'й', + 1050 => 'к', + 1051 => 'л', + 1052 => 'м', + 1053 => 'н', + 1054 => 'о', + 1055 => 'п', + 1056 => 'р', + 1057 => 'с', + 1058 => 'т', + 1059 => 'у', + 1060 => 'ф', + 1061 => 'х', + 1062 => 'ц', + 1063 => 'ч', + 1064 => 'ш', + 1065 => 'щ', + 1066 => 'ъ', + 1067 => 'ы', + 1068 => 'ь', + 1069 => 'э', + 1070 => 'ю', + 1071 => 'я', + 1120 => 'ѡ', + 1122 => 'ѣ', + 1124 => 'ѥ', + 1126 => 'ѧ', + 1128 => 'ѩ', + 1130 => 'ѫ', + 1132 => 'ѭ', + 1134 => 'ѯ', + 1136 => 'ѱ', + 1138 => 'ѳ', + 1140 => 'ѵ', + 1142 => 'ѷ', + 1144 => 'ѹ', + 1146 => 'ѻ', + 1148 => 'ѽ', + 1150 => 'ѿ', + 1152 => 'ҁ', + 1162 => 'ҋ', + 1164 => 'ҍ', + 1166 => 'ҏ', + 1168 => 'ґ', + 1170 => 'ғ', + 1172 => 'ҕ', + 1174 => 'җ', + 1176 => 'ҙ', + 1178 => 'қ', + 1180 => 'ҝ', + 1182 => 'ҟ', + 1184 => 'ҡ', + 1186 => 'ң', + 1188 => 'ҥ', + 1190 => 'ҧ', + 1192 => 'ҩ', + 1194 => 'ҫ', + 1196 => 'ҭ', + 1198 => 'ү', + 1200 => 'ұ', + 1202 => 'ҳ', + 1204 => 'ҵ', + 1206 => 'ҷ', + 1208 => 'ҹ', + 1210 => 'һ', + 1212 => 'ҽ', + 1214 => 'ҿ', + 1217 => 'ӂ', + 1219 => 'ӄ', + 1221 => 'ӆ', + 1223 => 'ӈ', + 1225 => 'ӊ', + 1227 => 'ӌ', + 1229 => 'ӎ', + 1232 => 'ӑ', + 1234 => 'ӓ', + 1236 => 'ӕ', + 1238 => 'ӗ', + 1240 => 'ә', + 1242 => 'ӛ', + 1244 => 'ӝ', + 1246 => 'ӟ', + 1248 => 'ӡ', + 1250 => 'ӣ', + 1252 => 'ӥ', + 1254 => 'ӧ', + 1256 => 'ө', + 1258 => 'ӫ', + 1260 => 'ӭ', + 1262 => 'ӯ', + 1264 => 'ӱ', + 1266 => 'ӳ', + 1268 => 'ӵ', + 1270 => 'ӷ', + 1272 => 'ӹ', + 1274 => 'ӻ', + 1276 => 'ӽ', + 1278 => 'ӿ', + 1280 => 'ԁ', + 1282 => 'ԃ', + 1284 => 'ԅ', + 1286 => 'ԇ', + 1288 => 'ԉ', + 1290 => 'ԋ', + 1292 => 'ԍ', + 1294 => 'ԏ', + 1296 => 'ԑ', + 1298 => 'ԓ', + 1300 => 'ԕ', + 1302 => 'ԗ', + 1304 => 'ԙ', + 1306 => 'ԛ', + 1308 => 'ԝ', + 1310 => 'ԟ', + 1312 => 'ԡ', + 1314 => 'ԣ', + 1316 => 'ԥ', + 1318 => 'ԧ', + 1320 => 'ԩ', + 1322 => 'ԫ', + 1324 => 'ԭ', + 1326 => 'ԯ', + 1329 => 'ա', + 1330 => 'բ', + 1331 => 'գ', + 1332 => 'դ', + 1333 => 'ե', + 1334 => 'զ', + 1335 => 'է', + 1336 => 'ը', + 1337 => 'թ', + 1338 => 'ժ', + 1339 => 'ի', + 1340 => 'լ', + 1341 => 'խ', + 1342 => 'ծ', + 1343 => 'կ', + 1344 => 'հ', + 1345 => 'ձ', + 1346 => 'ղ', + 1347 => 'ճ', + 1348 => 'մ', + 1349 => 'յ', + 1350 => 'ն', + 1351 => 'շ', + 1352 => 'ո', + 1353 => 'չ', + 1354 => 'պ', + 1355 => 'ջ', + 1356 => 'ռ', + 1357 => 'ս', + 1358 => 'վ', + 1359 => 'տ', + 1360 => 'ր', + 1361 => 'ց', + 1362 => 'ւ', + 1363 => 'փ', + 1364 => 'ք', + 1365 => 'օ', + 1366 => 'ֆ', + 1415 => 'եւ', + 1653 => 'اٴ', + 1654 => 'وٴ', + 1655 => 'ۇٴ', + 1656 => 'يٴ', + 2392 => 'क़', + 2393 => 'ख़', + 2394 => 'ग़', + 2395 => 'ज़', + 2396 => 'ड़', + 2397 => 'ढ़', + 2398 => 'फ़', + 2399 => 'य़', + 2524 => 'ড়', + 2525 => 'ঢ়', + 2527 => 'য়', + 2611 => 'ਲ਼', + 2614 => 'ਸ਼', + 2649 => 'ਖ਼', + 2650 => 'ਗ਼', + 2651 => 'ਜ਼', + 2654 => 'ਫ਼', + 2908 => 'ଡ଼', + 2909 => 'ଢ଼', + 3635 => 'ํา', + 3763 => 'ໍາ', + 3804 => 'ຫນ', + 3805 => 'ຫມ', + 3852 => '་', + 3907 => 'གྷ', + 3917 => 'ཌྷ', + 3922 => 'དྷ', + 3927 => 'བྷ', + 3932 => 'ཛྷ', + 3945 => 'ཀྵ', + 3955 => 'ཱི', + 3957 => 'ཱུ', + 3958 => 'ྲྀ', + 3959 => 'ྲཱྀ', + 3960 => 'ླྀ', + 3961 => 'ླཱྀ', + 3969 => 'ཱྀ', + 3987 => 'ྒྷ', + 3997 => 'ྜྷ', + 4002 => 'ྡྷ', + 4007 => 'ྦྷ', + 4012 => 'ྫྷ', + 4025 => 'ྐྵ', + 4295 => 'ⴧ', + 4301 => 'ⴭ', + 4348 => 'ნ', + 5112 => 'Ᏸ', + 5113 => 'Ᏹ', + 5114 => 'Ᏺ', + 5115 => 'Ᏻ', + 5116 => 'Ᏼ', + 5117 => 'Ᏽ', + 7296 => 'в', + 7297 => 'д', + 7298 => 'о', + 7299 => 'с', + 7300 => 'т', + 7301 => 'т', + 7302 => 'ъ', + 7303 => 'ѣ', + 7304 => 'ꙋ', + 7312 => 'ა', + 7313 => 'ბ', + 7314 => 'გ', + 7315 => 'დ', + 7316 => 'ე', + 7317 => 'ვ', + 7318 => 'ზ', + 7319 => 'თ', + 7320 => 'ი', + 7321 => 'კ', + 7322 => 'ლ', + 7323 => 'მ', + 7324 => 'ნ', + 7325 => 'ო', + 7326 => 'პ', + 7327 => 'ჟ', + 7328 => 'რ', + 7329 => 'ს', + 7330 => 'ტ', + 7331 => 'უ', + 7332 => 'ფ', + 7333 => 'ქ', + 7334 => 'ღ', + 7335 => 'ყ', + 7336 => 'შ', + 7337 => 'ჩ', + 7338 => 'ც', + 7339 => 'ძ', + 7340 => 'წ', + 7341 => 'ჭ', + 7342 => 'ხ', + 7343 => 'ჯ', + 7344 => 'ჰ', + 7345 => 'ჱ', + 7346 => 'ჲ', + 7347 => 'ჳ', + 7348 => 'ჴ', + 7349 => 'ჵ', + 7350 => 'ჶ', + 7351 => 'ჷ', + 7352 => 'ჸ', + 7353 => 'ჹ', + 7354 => 'ჺ', + 7357 => 'ჽ', + 7358 => 'ჾ', + 7359 => 'ჿ', + 7468 => 'a', + 7469 => 'æ', + 7470 => 'b', + 7472 => 'd', + 7473 => 'e', + 7474 => 'ǝ', + 7475 => 'g', + 7476 => 'h', + 7477 => 'i', + 7478 => 'j', + 7479 => 'k', + 7480 => 'l', + 7481 => 'm', + 7482 => 'n', + 7484 => 'o', + 7485 => 'ȣ', + 7486 => 'p', + 7487 => 'r', + 7488 => 't', + 7489 => 'u', + 7490 => 'w', + 7491 => 'a', + 7492 => 'ɐ', + 7493 => 'ɑ', + 7494 => 'ᴂ', + 7495 => 'b', + 7496 => 'd', + 7497 => 'e', + 7498 => 'ə', + 7499 => 'ɛ', + 7500 => 'ɜ', + 7501 => 'g', + 7503 => 'k', + 7504 => 'm', + 7505 => 'ŋ', + 7506 => 'o', + 7507 => 'ɔ', + 7508 => 'ᴖ', + 7509 => 'ᴗ', + 7510 => 'p', + 7511 => 't', + 7512 => 'u', + 7513 => 'ᴝ', + 7514 => 'ɯ', + 7515 => 'v', + 7516 => 'ᴥ', + 7517 => 'β', + 7518 => 'γ', + 7519 => 'δ', + 7520 => 'φ', + 7521 => 'χ', + 7522 => 'i', + 7523 => 'r', + 7524 => 'u', + 7525 => 'v', + 7526 => 'β', + 7527 => 'γ', + 7528 => 'ρ', + 7529 => 'φ', + 7530 => 'χ', + 7544 => 'н', + 7579 => 'ɒ', + 7580 => 'c', + 7581 => 'ɕ', + 7582 => 'ð', + 7583 => 'ɜ', + 7584 => 'f', + 7585 => 'ɟ', + 7586 => 'ɡ', + 7587 => 'ɥ', + 7588 => 'ɨ', + 7589 => 'ɩ', + 7590 => 'ɪ', + 7591 => 'ᵻ', + 7592 => 'ʝ', + 7593 => 'ɭ', + 7594 => 'ᶅ', + 7595 => 'ʟ', + 7596 => 'ɱ', + 7597 => 'ɰ', + 7598 => 'ɲ', + 7599 => 'ɳ', + 7600 => 'ɴ', + 7601 => 'ɵ', + 7602 => 'ɸ', + 7603 => 'ʂ', + 7604 => 'ʃ', + 7605 => 'ƫ', + 7606 => 'ʉ', + 7607 => 'ʊ', + 7608 => 'ᴜ', + 7609 => 'ʋ', + 7610 => 'ʌ', + 7611 => 'z', + 7612 => 'ʐ', + 7613 => 'ʑ', + 7614 => 'ʒ', + 7615 => 'θ', + 7680 => 'ḁ', + 7682 => 'ḃ', + 7684 => 'ḅ', + 7686 => 'ḇ', + 7688 => 'ḉ', + 7690 => 'ḋ', + 7692 => 'ḍ', + 7694 => 'ḏ', + 7696 => 'ḑ', + 7698 => 'ḓ', + 7700 => 'ḕ', + 7702 => 'ḗ', + 7704 => 'ḙ', + 7706 => 'ḛ', + 7708 => 'ḝ', + 7710 => 'ḟ', + 7712 => 'ḡ', + 7714 => 'ḣ', + 7716 => 'ḥ', + 7718 => 'ḧ', + 7720 => 'ḩ', + 7722 => 'ḫ', + 7724 => 'ḭ', + 7726 => 'ḯ', + 7728 => 'ḱ', + 7730 => 'ḳ', + 7732 => 'ḵ', + 7734 => 'ḷ', + 7736 => 'ḹ', + 7738 => 'ḻ', + 7740 => 'ḽ', + 7742 => 'ḿ', + 7744 => 'ṁ', + 7746 => 'ṃ', + 7748 => 'ṅ', + 7750 => 'ṇ', + 7752 => 'ṉ', + 7754 => 'ṋ', + 7756 => 'ṍ', + 7758 => 'ṏ', + 7760 => 'ṑ', + 7762 => 'ṓ', + 7764 => 'ṕ', + 7766 => 'ṗ', + 7768 => 'ṙ', + 7770 => 'ṛ', + 7772 => 'ṝ', + 7774 => 'ṟ', + 7776 => 'ṡ', + 7778 => 'ṣ', + 7780 => 'ṥ', + 7782 => 'ṧ', + 7784 => 'ṩ', + 7786 => 'ṫ', + 7788 => 'ṭ', + 7790 => 'ṯ', + 7792 => 'ṱ', + 7794 => 'ṳ', + 7796 => 'ṵ', + 7798 => 'ṷ', + 7800 => 'ṹ', + 7802 => 'ṻ', + 7804 => 'ṽ', + 7806 => 'ṿ', + 7808 => 'ẁ', + 7810 => 'ẃ', + 7812 => 'ẅ', + 7814 => 'ẇ', + 7816 => 'ẉ', + 7818 => 'ẋ', + 7820 => 'ẍ', + 7822 => 'ẏ', + 7824 => 'ẑ', + 7826 => 'ẓ', + 7828 => 'ẕ', + 7834 => 'aʾ', + 7835 => 'ṡ', + 7838 => 'ss', + 7840 => 'ạ', + 7842 => 'ả', + 7844 => 'ấ', + 7846 => 'ầ', + 7848 => 'ẩ', + 7850 => 'ẫ', + 7852 => 'ậ', + 7854 => 'ắ', + 7856 => 'ằ', + 7858 => 'ẳ', + 7860 => 'ẵ', + 7862 => 'ặ', + 7864 => 'ẹ', + 7866 => 'ẻ', + 7868 => 'ẽ', + 7870 => 'ế', + 7872 => 'ề', + 7874 => 'ể', + 7876 => 'ễ', + 7878 => 'ệ', + 7880 => 'ỉ', + 7882 => 'ị', + 7884 => 'ọ', + 7886 => 'ỏ', + 7888 => 'ố', + 7890 => 'ồ', + 7892 => 'ổ', + 7894 => 'ỗ', + 7896 => 'ộ', + 7898 => 'ớ', + 7900 => 'ờ', + 7902 => 'ở', + 7904 => 'ỡ', + 7906 => 'ợ', + 7908 => 'ụ', + 7910 => 'ủ', + 7912 => 'ứ', + 7914 => 'ừ', + 7916 => 'ử', + 7918 => 'ữ', + 7920 => 'ự', + 7922 => 'ỳ', + 7924 => 'ỵ', + 7926 => 'ỷ', + 7928 => 'ỹ', + 7930 => 'ỻ', + 7932 => 'ỽ', + 7934 => 'ỿ', + 7944 => 'ἀ', + 7945 => 'ἁ', + 7946 => 'ἂ', + 7947 => 'ἃ', + 7948 => 'ἄ', + 7949 => 'ἅ', + 7950 => 'ἆ', + 7951 => 'ἇ', + 7960 => 'ἐ', + 7961 => 'ἑ', + 7962 => 'ἒ', + 7963 => 'ἓ', + 7964 => 'ἔ', + 7965 => 'ἕ', + 7976 => 'ἠ', + 7977 => 'ἡ', + 7978 => 'ἢ', + 7979 => 'ἣ', + 7980 => 'ἤ', + 7981 => 'ἥ', + 7982 => 'ἦ', + 7983 => 'ἧ', + 7992 => 'ἰ', + 7993 => 'ἱ', + 7994 => 'ἲ', + 7995 => 'ἳ', + 7996 => 'ἴ', + 7997 => 'ἵ', + 7998 => 'ἶ', + 7999 => 'ἷ', + 8008 => 'ὀ', + 8009 => 'ὁ', + 8010 => 'ὂ', + 8011 => 'ὃ', + 8012 => 'ὄ', + 8013 => 'ὅ', + 8025 => 'ὑ', + 8027 => 'ὓ', + 8029 => 'ὕ', + 8031 => 'ὗ', + 8040 => 'ὠ', + 8041 => 'ὡ', + 8042 => 'ὢ', + 8043 => 'ὣ', + 8044 => 'ὤ', + 8045 => 'ὥ', + 8046 => 'ὦ', + 8047 => 'ὧ', + 8049 => 'ά', + 8051 => 'έ', + 8053 => 'ή', + 8055 => 'ί', + 8057 => 'ό', + 8059 => 'ύ', + 8061 => 'ώ', + 8064 => 'ἀι', + 8065 => 'ἁι', + 8066 => 'ἂι', + 8067 => 'ἃι', + 8068 => 'ἄι', + 8069 => 'ἅι', + 8070 => 'ἆι', + 8071 => 'ἇι', + 8072 => 'ἀι', + 8073 => 'ἁι', + 8074 => 'ἂι', + 8075 => 'ἃι', + 8076 => 'ἄι', + 8077 => 'ἅι', + 8078 => 'ἆι', + 8079 => 'ἇι', + 8080 => 'ἠι', + 8081 => 'ἡι', + 8082 => 'ἢι', + 8083 => 'ἣι', + 8084 => 'ἤι', + 8085 => 'ἥι', + 8086 => 'ἦι', + 8087 => 'ἧι', + 8088 => 'ἠι', + 8089 => 'ἡι', + 8090 => 'ἢι', + 8091 => 'ἣι', + 8092 => 'ἤι', + 8093 => 'ἥι', + 8094 => 'ἦι', + 8095 => 'ἧι', + 8096 => 'ὠι', + 8097 => 'ὡι', + 8098 => 'ὢι', + 8099 => 'ὣι', + 8100 => 'ὤι', + 8101 => 'ὥι', + 8102 => 'ὦι', + 8103 => 'ὧι', + 8104 => 'ὠι', + 8105 => 'ὡι', + 8106 => 'ὢι', + 8107 => 'ὣι', + 8108 => 'ὤι', + 8109 => 'ὥι', + 8110 => 'ὦι', + 8111 => 'ὧι', + 8114 => 'ὰι', + 8115 => 'αι', + 8116 => 'άι', + 8119 => 'ᾶι', + 8120 => 'ᾰ', + 8121 => 'ᾱ', + 8122 => 'ὰ', + 8123 => 'ά', + 8124 => 'αι', + 8126 => 'ι', + 8130 => 'ὴι', + 8131 => 'ηι', + 8132 => 'ήι', + 8135 => 'ῆι', + 8136 => 'ὲ', + 8137 => 'έ', + 8138 => 'ὴ', + 8139 => 'ή', + 8140 => 'ηι', + 8147 => 'ΐ', + 8152 => 'ῐ', + 8153 => 'ῑ', + 8154 => 'ὶ', + 8155 => 'ί', + 8163 => 'ΰ', + 8168 => 'ῠ', + 8169 => 'ῡ', + 8170 => 'ὺ', + 8171 => 'ύ', + 8172 => 'ῥ', + 8178 => 'ὼι', + 8179 => 'ωι', + 8180 => 'ώι', + 8183 => 'ῶι', + 8184 => 'ὸ', + 8185 => 'ό', + 8186 => 'ὼ', + 8187 => 'ώ', + 8188 => 'ωι', + 8209 => '‐', + 8243 => '′′', + 8244 => '′′′', + 8246 => '‵‵', + 8247 => '‵‵‵', + 8279 => '′′′′', + 8304 => '0', + 8305 => 'i', + 8308 => '4', + 8309 => '5', + 8310 => '6', + 8311 => '7', + 8312 => '8', + 8313 => '9', + 8315 => '−', + 8319 => 'n', + 8320 => '0', + 8321 => '1', + 8322 => '2', + 8323 => '3', + 8324 => '4', + 8325 => '5', + 8326 => '6', + 8327 => '7', + 8328 => '8', + 8329 => '9', + 8331 => '−', + 8336 => 'a', + 8337 => 'e', + 8338 => 'o', + 8339 => 'x', + 8340 => 'ə', + 8341 => 'h', + 8342 => 'k', + 8343 => 'l', + 8344 => 'm', + 8345 => 'n', + 8346 => 'p', + 8347 => 's', + 8348 => 't', + 8360 => 'rs', + 8450 => 'c', + 8451 => '°c', + 8455 => 'ɛ', + 8457 => '°f', + 8458 => 'g', + 8459 => 'h', + 8460 => 'h', + 8461 => 'h', + 8462 => 'h', + 8463 => 'ħ', + 8464 => 'i', + 8465 => 'i', + 8466 => 'l', + 8467 => 'l', + 8469 => 'n', + 8470 => 'no', + 8473 => 'p', + 8474 => 'q', + 8475 => 'r', + 8476 => 'r', + 8477 => 'r', + 8480 => 'sm', + 8481 => 'tel', + 8482 => 'tm', + 8484 => 'z', + 8486 => 'ω', + 8488 => 'z', + 8490 => 'k', + 8491 => 'å', + 8492 => 'b', + 8493 => 'c', + 8495 => 'e', + 8496 => 'e', + 8497 => 'f', + 8499 => 'm', + 8500 => 'o', + 8501 => 'א', + 8502 => 'ב', + 8503 => 'ג', + 8504 => 'ד', + 8505 => 'i', + 8507 => 'fax', + 8508 => 'π', + 8509 => 'γ', + 8510 => 'γ', + 8511 => 'π', + 8512 => '∑', + 8517 => 'd', + 8518 => 'd', + 8519 => 'e', + 8520 => 'i', + 8521 => 'j', + 8528 => '1⁄7', + 8529 => '1⁄9', + 8530 => '1⁄10', + 8531 => '1⁄3', + 8532 => '2⁄3', + 8533 => '1⁄5', + 8534 => '2⁄5', + 8535 => '3⁄5', + 8536 => '4⁄5', + 8537 => '1⁄6', + 8538 => '5⁄6', + 8539 => '1⁄8', + 8540 => '3⁄8', + 8541 => '5⁄8', + 8542 => '7⁄8', + 8543 => '1⁄', + 8544 => 'i', + 8545 => 'ii', + 8546 => 'iii', + 8547 => 'iv', + 8548 => 'v', + 8549 => 'vi', + 8550 => 'vii', + 8551 => 'viii', + 8552 => 'ix', + 8553 => 'x', + 8554 => 'xi', + 8555 => 'xii', + 8556 => 'l', + 8557 => 'c', + 8558 => 'd', + 8559 => 'm', + 8560 => 'i', + 8561 => 'ii', + 8562 => 'iii', + 8563 => 'iv', + 8564 => 'v', + 8565 => 'vi', + 8566 => 'vii', + 8567 => 'viii', + 8568 => 'ix', + 8569 => 'x', + 8570 => 'xi', + 8571 => 'xii', + 8572 => 'l', + 8573 => 'c', + 8574 => 'd', + 8575 => 'm', + 8585 => '0⁄3', + 8748 => '∫∫', + 8749 => '∫∫∫', + 8751 => '∮∮', + 8752 => '∮∮∮', + 9001 => '〈', + 9002 => '〉', + 9312 => '1', + 9313 => '2', + 9314 => '3', + 9315 => '4', + 9316 => '5', + 9317 => '6', + 9318 => '7', + 9319 => '8', + 9320 => '9', + 9321 => '10', + 9322 => '11', + 9323 => '12', + 9324 => '13', + 9325 => '14', + 9326 => '15', + 9327 => '16', + 9328 => '17', + 9329 => '18', + 9330 => '19', + 9331 => '20', + 9398 => 'a', + 9399 => 'b', + 9400 => 'c', + 9401 => 'd', + 9402 => 'e', + 9403 => 'f', + 9404 => 'g', + 9405 => 'h', + 9406 => 'i', + 9407 => 'j', + 9408 => 'k', + 9409 => 'l', + 9410 => 'm', + 9411 => 'n', + 9412 => 'o', + 9413 => 'p', + 9414 => 'q', + 9415 => 'r', + 9416 => 's', + 9417 => 't', + 9418 => 'u', + 9419 => 'v', + 9420 => 'w', + 9421 => 'x', + 9422 => 'y', + 9423 => 'z', + 9424 => 'a', + 9425 => 'b', + 9426 => 'c', + 9427 => 'd', + 9428 => 'e', + 9429 => 'f', + 9430 => 'g', + 9431 => 'h', + 9432 => 'i', + 9433 => 'j', + 9434 => 'k', + 9435 => 'l', + 9436 => 'm', + 9437 => 'n', + 9438 => 'o', + 9439 => 'p', + 9440 => 'q', + 9441 => 'r', + 9442 => 's', + 9443 => 't', + 9444 => 'u', + 9445 => 'v', + 9446 => 'w', + 9447 => 'x', + 9448 => 'y', + 9449 => 'z', + 9450 => '0', + 10764 => '∫∫∫∫', + 10972 => '⫝̸', + 11264 => 'ⰰ', + 11265 => 'ⰱ', + 11266 => 'ⰲ', + 11267 => 'ⰳ', + 11268 => 'ⰴ', + 11269 => 'ⰵ', + 11270 => 'ⰶ', + 11271 => 'ⰷ', + 11272 => 'ⰸ', + 11273 => 'ⰹ', + 11274 => 'ⰺ', + 11275 => 'ⰻ', + 11276 => 'ⰼ', + 11277 => 'ⰽ', + 11278 => 'ⰾ', + 11279 => 'ⰿ', + 11280 => 'ⱀ', + 11281 => 'ⱁ', + 11282 => 'ⱂ', + 11283 => 'ⱃ', + 11284 => 'ⱄ', + 11285 => 'ⱅ', + 11286 => 'ⱆ', + 11287 => 'ⱇ', + 11288 => 'ⱈ', + 11289 => 'ⱉ', + 11290 => 'ⱊ', + 11291 => 'ⱋ', + 11292 => 'ⱌ', + 11293 => 'ⱍ', + 11294 => 'ⱎ', + 11295 => 'ⱏ', + 11296 => 'ⱐ', + 11297 => 'ⱑ', + 11298 => 'ⱒ', + 11299 => 'ⱓ', + 11300 => 'ⱔ', + 11301 => 'ⱕ', + 11302 => 'ⱖ', + 11303 => 'ⱗ', + 11304 => 'ⱘ', + 11305 => 'ⱙ', + 11306 => 'ⱚ', + 11307 => 'ⱛ', + 11308 => 'ⱜ', + 11309 => 'ⱝ', + 11310 => 'ⱞ', + 11360 => 'ⱡ', + 11362 => 'ɫ', + 11363 => 'ᵽ', + 11364 => 'ɽ', + 11367 => 'ⱨ', + 11369 => 'ⱪ', + 11371 => 'ⱬ', + 11373 => 'ɑ', + 11374 => 'ɱ', + 11375 => 'ɐ', + 11376 => 'ɒ', + 11378 => 'ⱳ', + 11381 => 'ⱶ', + 11388 => 'j', + 11389 => 'v', + 11390 => 'ȿ', + 11391 => 'ɀ', + 11392 => 'ⲁ', + 11394 => 'ⲃ', + 11396 => 'ⲅ', + 11398 => 'ⲇ', + 11400 => 'ⲉ', + 11402 => 'ⲋ', + 11404 => 'ⲍ', + 11406 => 'ⲏ', + 11408 => 'ⲑ', + 11410 => 'ⲓ', + 11412 => 'ⲕ', + 11414 => 'ⲗ', + 11416 => 'ⲙ', + 11418 => 'ⲛ', + 11420 => 'ⲝ', + 11422 => 'ⲟ', + 11424 => 'ⲡ', + 11426 => 'ⲣ', + 11428 => 'ⲥ', + 11430 => 'ⲧ', + 11432 => 'ⲩ', + 11434 => 'ⲫ', + 11436 => 'ⲭ', + 11438 => 'ⲯ', + 11440 => 'ⲱ', + 11442 => 'ⲳ', + 11444 => 'ⲵ', + 11446 => 'ⲷ', + 11448 => 'ⲹ', + 11450 => 'ⲻ', + 11452 => 'ⲽ', + 11454 => 'ⲿ', + 11456 => 'ⳁ', + 11458 => 'ⳃ', + 11460 => 'ⳅ', + 11462 => 'ⳇ', + 11464 => 'ⳉ', + 11466 => 'ⳋ', + 11468 => 'ⳍ', + 11470 => 'ⳏ', + 11472 => 'ⳑ', + 11474 => 'ⳓ', + 11476 => 'ⳕ', + 11478 => 'ⳗ', + 11480 => 'ⳙ', + 11482 => 'ⳛ', + 11484 => 'ⳝ', + 11486 => 'ⳟ', + 11488 => 'ⳡ', + 11490 => 'ⳣ', + 11499 => 'ⳬ', + 11501 => 'ⳮ', + 11506 => 'ⳳ', + 11631 => 'ⵡ', + 11935 => '母', + 12019 => '龟', + 12032 => '一', + 12033 => '丨', + 12034 => '丶', + 12035 => '丿', + 12036 => '乙', + 12037 => '亅', + 12038 => '二', + 12039 => '亠', + 12040 => '人', + 12041 => '儿', + 12042 => '入', + 12043 => '八', + 12044 => '冂', + 12045 => '冖', + 12046 => '冫', + 12047 => '几', + 12048 => '凵', + 12049 => '刀', + 12050 => '力', + 12051 => '勹', + 12052 => '匕', + 12053 => '匚', + 12054 => '匸', + 12055 => '十', + 12056 => '卜', + 12057 => '卩', + 12058 => '厂', + 12059 => '厶', + 12060 => '又', + 12061 => '口', + 12062 => '囗', + 12063 => '土', + 12064 => '士', + 12065 => '夂', + 12066 => '夊', + 12067 => '夕', + 12068 => '大', + 12069 => '女', + 12070 => '子', + 12071 => '宀', + 12072 => '寸', + 12073 => '小', + 12074 => '尢', + 12075 => '尸', + 12076 => '屮', + 12077 => '山', + 12078 => '巛', + 12079 => '工', + 12080 => '己', + 12081 => '巾', + 12082 => '干', + 12083 => '幺', + 12084 => '广', + 12085 => '廴', + 12086 => '廾', + 12087 => '弋', + 12088 => '弓', + 12089 => '彐', + 12090 => '彡', + 12091 => '彳', + 12092 => '心', + 12093 => '戈', + 12094 => '戶', + 12095 => '手', + 12096 => '支', + 12097 => '攴', + 12098 => '文', + 12099 => '斗', + 12100 => '斤', + 12101 => '方', + 12102 => '无', + 12103 => '日', + 12104 => '曰', + 12105 => '月', + 12106 => '木', + 12107 => '欠', + 12108 => '止', + 12109 => '歹', + 12110 => '殳', + 12111 => '毋', + 12112 => '比', + 12113 => '毛', + 12114 => '氏', + 12115 => '气', + 12116 => '水', + 12117 => '火', + 12118 => '爪', + 12119 => '父', + 12120 => '爻', + 12121 => '爿', + 12122 => '片', + 12123 => '牙', + 12124 => '牛', + 12125 => '犬', + 12126 => '玄', + 12127 => '玉', + 12128 => '瓜', + 12129 => '瓦', + 12130 => '甘', + 12131 => '生', + 12132 => '用', + 12133 => '田', + 12134 => '疋', + 12135 => '疒', + 12136 => '癶', + 12137 => '白', + 12138 => '皮', + 12139 => '皿', + 12140 => '目', + 12141 => '矛', + 12142 => '矢', + 12143 => '石', + 12144 => '示', + 12145 => '禸', + 12146 => '禾', + 12147 => '穴', + 12148 => '立', + 12149 => '竹', + 12150 => '米', + 12151 => '糸', + 12152 => '缶', + 12153 => '网', + 12154 => '羊', + 12155 => '羽', + 12156 => '老', + 12157 => '而', + 12158 => '耒', + 12159 => '耳', + 12160 => '聿', + 12161 => '肉', + 12162 => '臣', + 12163 => '自', + 12164 => '至', + 12165 => '臼', + 12166 => '舌', + 12167 => '舛', + 12168 => '舟', + 12169 => '艮', + 12170 => '色', + 12171 => '艸', + 12172 => '虍', + 12173 => '虫', + 12174 => '血', + 12175 => '行', + 12176 => '衣', + 12177 => '襾', + 12178 => '見', + 12179 => '角', + 12180 => '言', + 12181 => '谷', + 12182 => '豆', + 12183 => '豕', + 12184 => '豸', + 12185 => '貝', + 12186 => '赤', + 12187 => '走', + 12188 => '足', + 12189 => '身', + 12190 => '車', + 12191 => '辛', + 12192 => '辰', + 12193 => '辵', + 12194 => '邑', + 12195 => '酉', + 12196 => '釆', + 12197 => '里', + 12198 => '金', + 12199 => '長', + 12200 => '門', + 12201 => '阜', + 12202 => '隶', + 12203 => '隹', + 12204 => '雨', + 12205 => '靑', + 12206 => '非', + 12207 => '面', + 12208 => '革', + 12209 => '韋', + 12210 => '韭', + 12211 => '音', + 12212 => '頁', + 12213 => '風', + 12214 => '飛', + 12215 => '食', + 12216 => '首', + 12217 => '香', + 12218 => '馬', + 12219 => '骨', + 12220 => '高', + 12221 => '髟', + 12222 => '鬥', + 12223 => '鬯', + 12224 => '鬲', + 12225 => '鬼', + 12226 => '魚', + 12227 => '鳥', + 12228 => '鹵', + 12229 => '鹿', + 12230 => '麥', + 12231 => '麻', + 12232 => '黃', + 12233 => '黍', + 12234 => '黑', + 12235 => '黹', + 12236 => '黽', + 12237 => '鼎', + 12238 => '鼓', + 12239 => '鼠', + 12240 => '鼻', + 12241 => '齊', + 12242 => '齒', + 12243 => '龍', + 12244 => '龜', + 12245 => '龠', + 12290 => '.', + 12342 => '〒', + 12344 => '十', + 12345 => '卄', + 12346 => '卅', + 12447 => 'より', + 12543 => 'コト', + 12593 => 'ᄀ', + 12594 => 'ᄁ', + 12595 => 'ᆪ', + 12596 => 'ᄂ', + 12597 => 'ᆬ', + 12598 => 'ᆭ', + 12599 => 'ᄃ', + 12600 => 'ᄄ', + 12601 => 'ᄅ', + 12602 => 'ᆰ', + 12603 => 'ᆱ', + 12604 => 'ᆲ', + 12605 => 'ᆳ', + 12606 => 'ᆴ', + 12607 => 'ᆵ', + 12608 => 'ᄚ', + 12609 => 'ᄆ', + 12610 => 'ᄇ', + 12611 => 'ᄈ', + 12612 => 'ᄡ', + 12613 => 'ᄉ', + 12614 => 'ᄊ', + 12615 => 'ᄋ', + 12616 => 'ᄌ', + 12617 => 'ᄍ', + 12618 => 'ᄎ', + 12619 => 'ᄏ', + 12620 => 'ᄐ', + 12621 => 'ᄑ', + 12622 => 'ᄒ', + 12623 => 'ᅡ', + 12624 => 'ᅢ', + 12625 => 'ᅣ', + 12626 => 'ᅤ', + 12627 => 'ᅥ', + 12628 => 'ᅦ', + 12629 => 'ᅧ', + 12630 => 'ᅨ', + 12631 => 'ᅩ', + 12632 => 'ᅪ', + 12633 => 'ᅫ', + 12634 => 'ᅬ', + 12635 => 'ᅭ', + 12636 => 'ᅮ', + 12637 => 'ᅯ', + 12638 => 'ᅰ', + 12639 => 'ᅱ', + 12640 => 'ᅲ', + 12641 => 'ᅳ', + 12642 => 'ᅴ', + 12643 => 'ᅵ', + 12645 => 'ᄔ', + 12646 => 'ᄕ', + 12647 => 'ᇇ', + 12648 => 'ᇈ', + 12649 => 'ᇌ', + 12650 => 'ᇎ', + 12651 => 'ᇓ', + 12652 => 'ᇗ', + 12653 => 'ᇙ', + 12654 => 'ᄜ', + 12655 => 'ᇝ', + 12656 => 'ᇟ', + 12657 => 'ᄝ', + 12658 => 'ᄞ', + 12659 => 'ᄠ', + 12660 => 'ᄢ', + 12661 => 'ᄣ', + 12662 => 'ᄧ', + 12663 => 'ᄩ', + 12664 => 'ᄫ', + 12665 => 'ᄬ', + 12666 => 'ᄭ', + 12667 => 'ᄮ', + 12668 => 'ᄯ', + 12669 => 'ᄲ', + 12670 => 'ᄶ', + 12671 => 'ᅀ', + 12672 => 'ᅇ', + 12673 => 'ᅌ', + 12674 => 'ᇱ', + 12675 => 'ᇲ', + 12676 => 'ᅗ', + 12677 => 'ᅘ', + 12678 => 'ᅙ', + 12679 => 'ᆄ', + 12680 => 'ᆅ', + 12681 => 'ᆈ', + 12682 => 'ᆑ', + 12683 => 'ᆒ', + 12684 => 'ᆔ', + 12685 => 'ᆞ', + 12686 => 'ᆡ', + 12690 => '一', + 12691 => '二', + 12692 => '三', + 12693 => '四', + 12694 => '上', + 12695 => '中', + 12696 => '下', + 12697 => '甲', + 12698 => '乙', + 12699 => '丙', + 12700 => '丁', + 12701 => '天', + 12702 => '地', + 12703 => '人', + 12868 => '問', + 12869 => '幼', + 12870 => '文', + 12871 => '箏', + 12880 => 'pte', + 12881 => '21', + 12882 => '22', + 12883 => '23', + 12884 => '24', + 12885 => '25', + 12886 => '26', + 12887 => '27', + 12888 => '28', + 12889 => '29', + 12890 => '30', + 12891 => '31', + 12892 => '32', + 12893 => '33', + 12894 => '34', + 12895 => '35', + 12896 => 'ᄀ', + 12897 => 'ᄂ', + 12898 => 'ᄃ', + 12899 => 'ᄅ', + 12900 => 'ᄆ', + 12901 => 'ᄇ', + 12902 => 'ᄉ', + 12903 => 'ᄋ', + 12904 => 'ᄌ', + 12905 => 'ᄎ', + 12906 => 'ᄏ', + 12907 => 'ᄐ', + 12908 => 'ᄑ', + 12909 => 'ᄒ', + 12910 => '가', + 12911 => '나', + 12912 => '다', + 12913 => '라', + 12914 => '마', + 12915 => '바', + 12916 => '사', + 12917 => '아', + 12918 => '자', + 12919 => '차', + 12920 => '카', + 12921 => '타', + 12922 => '파', + 12923 => '하', + 12924 => '참고', + 12925 => '주의', + 12926 => '우', + 12928 => '一', + 12929 => '二', + 12930 => '三', + 12931 => '四', + 12932 => '五', + 12933 => '六', + 12934 => '七', + 12935 => '八', + 12936 => '九', + 12937 => '十', + 12938 => '月', + 12939 => '火', + 12940 => '水', + 12941 => '木', + 12942 => '金', + 12943 => '土', + 12944 => '日', + 12945 => '株', + 12946 => '有', + 12947 => '社', + 12948 => '名', + 12949 => '特', + 12950 => '財', + 12951 => '祝', + 12952 => '労', + 12953 => '秘', + 12954 => '男', + 12955 => '女', + 12956 => '適', + 12957 => '優', + 12958 => '印', + 12959 => '注', + 12960 => '項', + 12961 => '休', + 12962 => '写', + 12963 => '正', + 12964 => '上', + 12965 => '中', + 12966 => '下', + 12967 => '左', + 12968 => '右', + 12969 => '医', + 12970 => '宗', + 12971 => '学', + 12972 => '監', + 12973 => '企', + 12974 => '資', + 12975 => '協', + 12976 => '夜', + 12977 => '36', + 12978 => '37', + 12979 => '38', + 12980 => '39', + 12981 => '40', + 12982 => '41', + 12983 => '42', + 12984 => '43', + 12985 => '44', + 12986 => '45', + 12987 => '46', + 12988 => '47', + 12989 => '48', + 12990 => '49', + 12991 => '50', + 12992 => '1月', + 12993 => '2月', + 12994 => '3月', + 12995 => '4月', + 12996 => '5月', + 12997 => '6月', + 12998 => '7月', + 12999 => '8月', + 13000 => '9月', + 13001 => '10月', + 13002 => '11月', + 13003 => '12月', + 13004 => 'hg', + 13005 => 'erg', + 13006 => 'ev', + 13007 => 'ltd', + 13008 => 'ア', + 13009 => 'イ', + 13010 => 'ウ', + 13011 => 'エ', + 13012 => 'オ', + 13013 => 'カ', + 13014 => 'キ', + 13015 => 'ク', + 13016 => 'ケ', + 13017 => 'コ', + 13018 => 'サ', + 13019 => 'シ', + 13020 => 'ス', + 13021 => 'セ', + 13022 => 'ソ', + 13023 => 'タ', + 13024 => 'チ', + 13025 => 'ツ', + 13026 => 'テ', + 13027 => 'ト', + 13028 => 'ナ', + 13029 => 'ニ', + 13030 => 'ヌ', + 13031 => 'ネ', + 13032 => 'ノ', + 13033 => 'ハ', + 13034 => 'ヒ', + 13035 => 'フ', + 13036 => 'ヘ', + 13037 => 'ホ', + 13038 => 'マ', + 13039 => 'ミ', + 13040 => 'ム', + 13041 => 'メ', + 13042 => 'モ', + 13043 => 'ヤ', + 13044 => 'ユ', + 13045 => 'ヨ', + 13046 => 'ラ', + 13047 => 'リ', + 13048 => 'ル', + 13049 => 'レ', + 13050 => 'ロ', + 13051 => 'ワ', + 13052 => 'ヰ', + 13053 => 'ヱ', + 13054 => 'ヲ', + 13055 => '令和', + 13056 => 'アパート', + 13057 => 'アルファ', + 13058 => 'アンペア', + 13059 => 'アール', + 13060 => 'イニング', + 13061 => 'インチ', + 13062 => 'ウォン', + 13063 => 'エスクード', + 13064 => 'エーカー', + 13065 => 'オンス', + 13066 => 'オーム', + 13067 => 'カイリ', + 13068 => 'カラット', + 13069 => 'カロリー', + 13070 => 'ガロン', + 13071 => 'ガンマ', + 13072 => 'ギガ', + 13073 => 'ギニー', + 13074 => 'キュリー', + 13075 => 'ギルダー', + 13076 => 'キロ', + 13077 => 'キログラム', + 13078 => 'キロメートル', + 13079 => 'キロワット', + 13080 => 'グラム', + 13081 => 'グラムトン', + 13082 => 'クルゼイロ', + 13083 => 'クローネ', + 13084 => 'ケース', + 13085 => 'コルナ', + 13086 => 'コーポ', + 13087 => 'サイクル', + 13088 => 'サンチーム', + 13089 => 'シリング', + 13090 => 'センチ', + 13091 => 'セント', + 13092 => 'ダース', + 13093 => 'デシ', + 13094 => 'ドル', + 13095 => 'トン', + 13096 => 'ナノ', + 13097 => 'ノット', + 13098 => 'ハイツ', + 13099 => 'パーセント', + 13100 => 'パーツ', + 13101 => 'バーレル', + 13102 => 'ピアストル', + 13103 => 'ピクル', + 13104 => 'ピコ', + 13105 => 'ビル', + 13106 => 'ファラッド', + 13107 => 'フィート', + 13108 => 'ブッシェル', + 13109 => 'フラン', + 13110 => 'ヘクタール', + 13111 => 'ペソ', + 13112 => 'ペニヒ', + 13113 => 'ヘルツ', + 13114 => 'ペンス', + 13115 => 'ページ', + 13116 => 'ベータ', + 13117 => 'ポイント', + 13118 => 'ボルト', + 13119 => 'ホン', + 13120 => 'ポンド', + 13121 => 'ホール', + 13122 => 'ホーン', + 13123 => 'マイクロ', + 13124 => 'マイル', + 13125 => 'マッハ', + 13126 => 'マルク', + 13127 => 'マンション', + 13128 => 'ミクロン', + 13129 => 'ミリ', + 13130 => 'ミリバール', + 13131 => 'メガ', + 13132 => 'メガトン', + 13133 => 'メートル', + 13134 => 'ヤード', + 13135 => 'ヤール', + 13136 => 'ユアン', + 13137 => 'リットル', + 13138 => 'リラ', + 13139 => 'ルピー', + 13140 => 'ルーブル', + 13141 => 'レム', + 13142 => 'レントゲン', + 13143 => 'ワット', + 13144 => '0点', + 13145 => '1点', + 13146 => '2点', + 13147 => '3点', + 13148 => '4点', + 13149 => '5点', + 13150 => '6点', + 13151 => '7点', + 13152 => '8点', + 13153 => '9点', + 13154 => '10点', + 13155 => '11点', + 13156 => '12点', + 13157 => '13点', + 13158 => '14点', + 13159 => '15点', + 13160 => '16点', + 13161 => '17点', + 13162 => '18点', + 13163 => '19点', + 13164 => '20点', + 13165 => '21点', + 13166 => '22点', + 13167 => '23点', + 13168 => '24点', + 13169 => 'hpa', + 13170 => 'da', + 13171 => 'au', + 13172 => 'bar', + 13173 => 'ov', + 13174 => 'pc', + 13175 => 'dm', + 13176 => 'dm2', + 13177 => 'dm3', + 13178 => 'iu', + 13179 => '平成', + 13180 => '昭和', + 13181 => '大正', + 13182 => '明治', + 13183 => '株式会社', + 13184 => 'pa', + 13185 => 'na', + 13186 => 'μa', + 13187 => 'ma', + 13188 => 'ka', + 13189 => 'kb', + 13190 => 'mb', + 13191 => 'gb', + 13192 => 'cal', + 13193 => 'kcal', + 13194 => 'pf', + 13195 => 'nf', + 13196 => 'μf', + 13197 => 'μg', + 13198 => 'mg', + 13199 => 'kg', + 13200 => 'hz', + 13201 => 'khz', + 13202 => 'mhz', + 13203 => 'ghz', + 13204 => 'thz', + 13205 => 'μl', + 13206 => 'ml', + 13207 => 'dl', + 13208 => 'kl', + 13209 => 'fm', + 13210 => 'nm', + 13211 => 'μm', + 13212 => 'mm', + 13213 => 'cm', + 13214 => 'km', + 13215 => 'mm2', + 13216 => 'cm2', + 13217 => 'm2', + 13218 => 'km2', + 13219 => 'mm3', + 13220 => 'cm3', + 13221 => 'm3', + 13222 => 'km3', + 13223 => 'm∕s', + 13224 => 'm∕s2', + 13225 => 'pa', + 13226 => 'kpa', + 13227 => 'mpa', + 13228 => 'gpa', + 13229 => 'rad', + 13230 => 'rad∕s', + 13231 => 'rad∕s2', + 13232 => 'ps', + 13233 => 'ns', + 13234 => 'μs', + 13235 => 'ms', + 13236 => 'pv', + 13237 => 'nv', + 13238 => 'μv', + 13239 => 'mv', + 13240 => 'kv', + 13241 => 'mv', + 13242 => 'pw', + 13243 => 'nw', + 13244 => 'μw', + 13245 => 'mw', + 13246 => 'kw', + 13247 => 'mw', + 13248 => 'kω', + 13249 => 'mω', + 13251 => 'bq', + 13252 => 'cc', + 13253 => 'cd', + 13254 => 'c∕kg', + 13256 => 'db', + 13257 => 'gy', + 13258 => 'ha', + 13259 => 'hp', + 13260 => 'in', + 13261 => 'kk', + 13262 => 'km', + 13263 => 'kt', + 13264 => 'lm', + 13265 => 'ln', + 13266 => 'log', + 13267 => 'lx', + 13268 => 'mb', + 13269 => 'mil', + 13270 => 'mol', + 13271 => 'ph', + 13273 => 'ppm', + 13274 => 'pr', + 13275 => 'sr', + 13276 => 'sv', + 13277 => 'wb', + 13278 => 'v∕m', + 13279 => 'a∕m', + 13280 => '1日', + 13281 => '2日', + 13282 => '3日', + 13283 => '4日', + 13284 => '5日', + 13285 => '6日', + 13286 => '7日', + 13287 => '8日', + 13288 => '9日', + 13289 => '10日', + 13290 => '11日', + 13291 => '12日', + 13292 => '13日', + 13293 => '14日', + 13294 => '15日', + 13295 => '16日', + 13296 => '17日', + 13297 => '18日', + 13298 => '19日', + 13299 => '20日', + 13300 => '21日', + 13301 => '22日', + 13302 => '23日', + 13303 => '24日', + 13304 => '25日', + 13305 => '26日', + 13306 => '27日', + 13307 => '28日', + 13308 => '29日', + 13309 => '30日', + 13310 => '31日', + 13311 => 'gal', + 42560 => 'ꙁ', + 42562 => 'ꙃ', + 42564 => 'ꙅ', + 42566 => 'ꙇ', + 42568 => 'ꙉ', + 42570 => 'ꙋ', + 42572 => 'ꙍ', + 42574 => 'ꙏ', + 42576 => 'ꙑ', + 42578 => 'ꙓ', + 42580 => 'ꙕ', + 42582 => 'ꙗ', + 42584 => 'ꙙ', + 42586 => 'ꙛ', + 42588 => 'ꙝ', + 42590 => 'ꙟ', + 42592 => 'ꙡ', + 42594 => 'ꙣ', + 42596 => 'ꙥ', + 42598 => 'ꙧ', + 42600 => 'ꙩ', + 42602 => 'ꙫ', + 42604 => 'ꙭ', + 42624 => 'ꚁ', + 42626 => 'ꚃ', + 42628 => 'ꚅ', + 42630 => 'ꚇ', + 42632 => 'ꚉ', + 42634 => 'ꚋ', + 42636 => 'ꚍ', + 42638 => 'ꚏ', + 42640 => 'ꚑ', + 42642 => 'ꚓ', + 42644 => 'ꚕ', + 42646 => 'ꚗ', + 42648 => 'ꚙ', + 42650 => 'ꚛ', + 42652 => 'ъ', + 42653 => 'ь', + 42786 => 'ꜣ', + 42788 => 'ꜥ', + 42790 => 'ꜧ', + 42792 => 'ꜩ', + 42794 => 'ꜫ', + 42796 => 'ꜭ', + 42798 => 'ꜯ', + 42802 => 'ꜳ', + 42804 => 'ꜵ', + 42806 => 'ꜷ', + 42808 => 'ꜹ', + 42810 => 'ꜻ', + 42812 => 'ꜽ', + 42814 => 'ꜿ', + 42816 => 'ꝁ', + 42818 => 'ꝃ', + 42820 => 'ꝅ', + 42822 => 'ꝇ', + 42824 => 'ꝉ', + 42826 => 'ꝋ', + 42828 => 'ꝍ', + 42830 => 'ꝏ', + 42832 => 'ꝑ', + 42834 => 'ꝓ', + 42836 => 'ꝕ', + 42838 => 'ꝗ', + 42840 => 'ꝙ', + 42842 => 'ꝛ', + 42844 => 'ꝝ', + 42846 => 'ꝟ', + 42848 => 'ꝡ', + 42850 => 'ꝣ', + 42852 => 'ꝥ', + 42854 => 'ꝧ', + 42856 => 'ꝩ', + 42858 => 'ꝫ', + 42860 => 'ꝭ', + 42862 => 'ꝯ', + 42864 => 'ꝯ', + 42873 => 'ꝺ', + 42875 => 'ꝼ', + 42877 => 'ᵹ', + 42878 => 'ꝿ', + 42880 => 'ꞁ', + 42882 => 'ꞃ', + 42884 => 'ꞅ', + 42886 => 'ꞇ', + 42891 => 'ꞌ', + 42893 => 'ɥ', + 42896 => 'ꞑ', + 42898 => 'ꞓ', + 42902 => 'ꞗ', + 42904 => 'ꞙ', + 42906 => 'ꞛ', + 42908 => 'ꞝ', + 42910 => 'ꞟ', + 42912 => 'ꞡ', + 42914 => 'ꞣ', + 42916 => 'ꞥ', + 42918 => 'ꞧ', + 42920 => 'ꞩ', + 42922 => 'ɦ', + 42923 => 'ɜ', + 42924 => 'ɡ', + 42925 => 'ɬ', + 42926 => 'ɪ', + 42928 => 'ʞ', + 42929 => 'ʇ', + 42930 => 'ʝ', + 42931 => 'ꭓ', + 42932 => 'ꞵ', + 42934 => 'ꞷ', + 42936 => 'ꞹ', + 42938 => 'ꞻ', + 42940 => 'ꞽ', + 42942 => 'ꞿ', + 42946 => 'ꟃ', + 42948 => 'ꞔ', + 42949 => 'ʂ', + 42950 => 'ᶎ', + 42951 => 'ꟈ', + 42953 => 'ꟊ', + 42997 => 'ꟶ', + 43000 => 'ħ', + 43001 => 'œ', + 43868 => 'ꜧ', + 43869 => 'ꬷ', + 43870 => 'ɫ', + 43871 => 'ꭒ', + 43881 => 'ʍ', + 43888 => 'Ꭰ', + 43889 => 'Ꭱ', + 43890 => 'Ꭲ', + 43891 => 'Ꭳ', + 43892 => 'Ꭴ', + 43893 => 'Ꭵ', + 43894 => 'Ꭶ', + 43895 => 'Ꭷ', + 43896 => 'Ꭸ', + 43897 => 'Ꭹ', + 43898 => 'Ꭺ', + 43899 => 'Ꭻ', + 43900 => 'Ꭼ', + 43901 => 'Ꭽ', + 43902 => 'Ꭾ', + 43903 => 'Ꭿ', + 43904 => 'Ꮀ', + 43905 => 'Ꮁ', + 43906 => 'Ꮂ', + 43907 => 'Ꮃ', + 43908 => 'Ꮄ', + 43909 => 'Ꮅ', + 43910 => 'Ꮆ', + 43911 => 'Ꮇ', + 43912 => 'Ꮈ', + 43913 => 'Ꮉ', + 43914 => 'Ꮊ', + 43915 => 'Ꮋ', + 43916 => 'Ꮌ', + 43917 => 'Ꮍ', + 43918 => 'Ꮎ', + 43919 => 'Ꮏ', + 43920 => 'Ꮐ', + 43921 => 'Ꮑ', + 43922 => 'Ꮒ', + 43923 => 'Ꮓ', + 43924 => 'Ꮔ', + 43925 => 'Ꮕ', + 43926 => 'Ꮖ', + 43927 => 'Ꮗ', + 43928 => 'Ꮘ', + 43929 => 'Ꮙ', + 43930 => 'Ꮚ', + 43931 => 'Ꮛ', + 43932 => 'Ꮜ', + 43933 => 'Ꮝ', + 43934 => 'Ꮞ', + 43935 => 'Ꮟ', + 43936 => 'Ꮠ', + 43937 => 'Ꮡ', + 43938 => 'Ꮢ', + 43939 => 'Ꮣ', + 43940 => 'Ꮤ', + 43941 => 'Ꮥ', + 43942 => 'Ꮦ', + 43943 => 'Ꮧ', + 43944 => 'Ꮨ', + 43945 => 'Ꮩ', + 43946 => 'Ꮪ', + 43947 => 'Ꮫ', + 43948 => 'Ꮬ', + 43949 => 'Ꮭ', + 43950 => 'Ꮮ', + 43951 => 'Ꮯ', + 43952 => 'Ꮰ', + 43953 => 'Ꮱ', + 43954 => 'Ꮲ', + 43955 => 'Ꮳ', + 43956 => 'Ꮴ', + 43957 => 'Ꮵ', + 43958 => 'Ꮶ', + 43959 => 'Ꮷ', + 43960 => 'Ꮸ', + 43961 => 'Ꮹ', + 43962 => 'Ꮺ', + 43963 => 'Ꮻ', + 43964 => 'Ꮼ', + 43965 => 'Ꮽ', + 43966 => 'Ꮾ', + 43967 => 'Ꮿ', + 63744 => '豈', + 63745 => '更', + 63746 => '車', + 63747 => '賈', + 63748 => '滑', + 63749 => '串', + 63750 => '句', + 63751 => '龜', + 63752 => '龜', + 63753 => '契', + 63754 => '金', + 63755 => '喇', + 63756 => '奈', + 63757 => '懶', + 63758 => '癩', + 63759 => '羅', + 63760 => '蘿', + 63761 => '螺', + 63762 => '裸', + 63763 => '邏', + 63764 => '樂', + 63765 => '洛', + 63766 => '烙', + 63767 => '珞', + 63768 => '落', + 63769 => '酪', + 63770 => '駱', + 63771 => '亂', + 63772 => '卵', + 63773 => '欄', + 63774 => '爛', + 63775 => '蘭', + 63776 => '鸞', + 63777 => '嵐', + 63778 => '濫', + 63779 => '藍', + 63780 => '襤', + 63781 => '拉', + 63782 => '臘', + 63783 => '蠟', + 63784 => '廊', + 63785 => '朗', + 63786 => '浪', + 63787 => '狼', + 63788 => '郎', + 63789 => '來', + 63790 => '冷', + 63791 => '勞', + 63792 => '擄', + 63793 => '櫓', + 63794 => '爐', + 63795 => '盧', + 63796 => '老', + 63797 => '蘆', + 63798 => '虜', + 63799 => '路', + 63800 => '露', + 63801 => '魯', + 63802 => '鷺', + 63803 => '碌', + 63804 => '祿', + 63805 => '綠', + 63806 => '菉', + 63807 => '錄', + 63808 => '鹿', + 63809 => '論', + 63810 => '壟', + 63811 => '弄', + 63812 => '籠', + 63813 => '聾', + 63814 => '牢', + 63815 => '磊', + 63816 => '賂', + 63817 => '雷', + 63818 => '壘', + 63819 => '屢', + 63820 => '樓', + 63821 => '淚', + 63822 => '漏', + 63823 => '累', + 63824 => '縷', + 63825 => '陋', + 63826 => '勒', + 63827 => '肋', + 63828 => '凜', + 63829 => '凌', + 63830 => '稜', + 63831 => '綾', + 63832 => '菱', + 63833 => '陵', + 63834 => '讀', + 63835 => '拏', + 63836 => '樂', + 63837 => '諾', + 63838 => '丹', + 63839 => '寧', + 63840 => '怒', + 63841 => '率', + 63842 => '異', + 63843 => '北', + 63844 => '磻', + 63845 => '便', + 63846 => '復', + 63847 => '不', + 63848 => '泌', + 63849 => '數', + 63850 => '索', + 63851 => '參', + 63852 => '塞', + 63853 => '省', + 63854 => '葉', + 63855 => '說', + 63856 => '殺', + 63857 => '辰', + 63858 => '沈', + 63859 => '拾', + 63860 => '若', + 63861 => '掠', + 63862 => '略', + 63863 => '亮', + 63864 => '兩', + 63865 => '凉', + 63866 => '梁', + 63867 => '糧', + 63868 => '良', + 63869 => '諒', + 63870 => '量', + 63871 => '勵', + 63872 => '呂', + 63873 => '女', + 63874 => '廬', + 63875 => '旅', + 63876 => '濾', + 63877 => '礪', + 63878 => '閭', + 63879 => '驪', + 63880 => '麗', + 63881 => '黎', + 63882 => '力', + 63883 => '曆', + 63884 => '歷', + 63885 => '轢', + 63886 => '年', + 63887 => '憐', + 63888 => '戀', + 63889 => '撚', + 63890 => '漣', + 63891 => '煉', + 63892 => '璉', + 63893 => '秊', + 63894 => '練', + 63895 => '聯', + 63896 => '輦', + 63897 => '蓮', + 63898 => '連', + 63899 => '鍊', + 63900 => '列', + 63901 => '劣', + 63902 => '咽', + 63903 => '烈', + 63904 => '裂', + 63905 => '說', + 63906 => '廉', + 63907 => '念', + 63908 => '捻', + 63909 => '殮', + 63910 => '簾', + 63911 => '獵', + 63912 => '令', + 63913 => '囹', + 63914 => '寧', + 63915 => '嶺', + 63916 => '怜', + 63917 => '玲', + 63918 => '瑩', + 63919 => '羚', + 63920 => '聆', + 63921 => '鈴', + 63922 => '零', + 63923 => '靈', + 63924 => '領', + 63925 => '例', + 63926 => '禮', + 63927 => '醴', + 63928 => '隸', + 63929 => '惡', + 63930 => '了', + 63931 => '僚', + 63932 => '寮', + 63933 => '尿', + 63934 => '料', + 63935 => '樂', + 63936 => '燎', + 63937 => '療', + 63938 => '蓼', + 63939 => '遼', + 63940 => '龍', + 63941 => '暈', + 63942 => '阮', + 63943 => '劉', + 63944 => '杻', + 63945 => '柳', + 63946 => '流', + 63947 => '溜', + 63948 => '琉', + 63949 => '留', + 63950 => '硫', + 63951 => '紐', + 63952 => '類', + 63953 => '六', + 63954 => '戮', + 63955 => '陸', + 63956 => '倫', + 63957 => '崙', + 63958 => '淪', + 63959 => '輪', + 63960 => '律', + 63961 => '慄', + 63962 => '栗', + 63963 => '率', + 63964 => '隆', + 63965 => '利', + 63966 => '吏', + 63967 => '履', + 63968 => '易', + 63969 => '李', + 63970 => '梨', + 63971 => '泥', + 63972 => '理', + 63973 => '痢', + 63974 => '罹', + 63975 => '裏', + 63976 => '裡', + 63977 => '里', + 63978 => '離', + 63979 => '匿', + 63980 => '溺', + 63981 => '吝', + 63982 => '燐', + 63983 => '璘', + 63984 => '藺', + 63985 => '隣', + 63986 => '鱗', + 63987 => '麟', + 63988 => '林', + 63989 => '淋', + 63990 => '臨', + 63991 => '立', + 63992 => '笠', + 63993 => '粒', + 63994 => '狀', + 63995 => '炙', + 63996 => '識', + 63997 => '什', + 63998 => '茶', + 63999 => '刺', + 64000 => '切', + 64001 => '度', + 64002 => '拓', + 64003 => '糖', + 64004 => '宅', + 64005 => '洞', + 64006 => '暴', + 64007 => '輻', + 64008 => '行', + 64009 => '降', + 64010 => '見', + 64011 => '廓', + 64012 => '兀', + 64013 => '嗀', + 64016 => '塚', + 64018 => '晴', + 64021 => '凞', + 64022 => '猪', + 64023 => '益', + 64024 => '礼', + 64025 => '神', + 64026 => '祥', + 64027 => '福', + 64028 => '靖', + 64029 => '精', + 64030 => '羽', + 64032 => '蘒', + 64034 => '諸', + 64037 => '逸', + 64038 => '都', + 64042 => '飯', + 64043 => '飼', + 64044 => '館', + 64045 => '鶴', + 64046 => '郞', + 64047 => '隷', + 64048 => '侮', + 64049 => '僧', + 64050 => '免', + 64051 => '勉', + 64052 => '勤', + 64053 => '卑', + 64054 => '喝', + 64055 => '嘆', + 64056 => '器', + 64057 => '塀', + 64058 => '墨', + 64059 => '層', + 64060 => '屮', + 64061 => '悔', + 64062 => '慨', + 64063 => '憎', + 64064 => '懲', + 64065 => '敏', + 64066 => '既', + 64067 => '暑', + 64068 => '梅', + 64069 => '海', + 64070 => '渚', + 64071 => '漢', + 64072 => '煮', + 64073 => '爫', + 64074 => '琢', + 64075 => '碑', + 64076 => '社', + 64077 => '祉', + 64078 => '祈', + 64079 => '祐', + 64080 => '祖', + 64081 => '祝', + 64082 => '禍', + 64083 => '禎', + 64084 => '穀', + 64085 => '突', + 64086 => '節', + 64087 => '練', + 64088 => '縉', + 64089 => '繁', + 64090 => '署', + 64091 => '者', + 64092 => '臭', + 64093 => '艹', + 64094 => '艹', + 64095 => '著', + 64096 => '褐', + 64097 => '視', + 64098 => '謁', + 64099 => '謹', + 64100 => '賓', + 64101 => '贈', + 64102 => '辶', + 64103 => '逸', + 64104 => '難', + 64105 => '響', + 64106 => '頻', + 64107 => '恵', + 64108 => '𤋮', + 64109 => '舘', + 64112 => '並', + 64113 => '况', + 64114 => '全', + 64115 => '侀', + 64116 => '充', + 64117 => '冀', + 64118 => '勇', + 64119 => '勺', + 64120 => '喝', + 64121 => '啕', + 64122 => '喙', + 64123 => '嗢', + 64124 => '塚', + 64125 => '墳', + 64126 => '奄', + 64127 => '奔', + 64128 => '婢', + 64129 => '嬨', + 64130 => '廒', + 64131 => '廙', + 64132 => '彩', + 64133 => '徭', + 64134 => '惘', + 64135 => '慎', + 64136 => '愈', + 64137 => '憎', + 64138 => '慠', + 64139 => '懲', + 64140 => '戴', + 64141 => '揄', + 64142 => '搜', + 64143 => '摒', + 64144 => '敖', + 64145 => '晴', + 64146 => '朗', + 64147 => '望', + 64148 => '杖', + 64149 => '歹', + 64150 => '殺', + 64151 => '流', + 64152 => '滛', + 64153 => '滋', + 64154 => '漢', + 64155 => '瀞', + 64156 => '煮', + 64157 => '瞧', + 64158 => '爵', + 64159 => '犯', + 64160 => '猪', + 64161 => '瑱', + 64162 => '甆', + 64163 => '画', + 64164 => '瘝', + 64165 => '瘟', + 64166 => '益', + 64167 => '盛', + 64168 => '直', + 64169 => '睊', + 64170 => '着', + 64171 => '磌', + 64172 => '窱', + 64173 => '節', + 64174 => '类', + 64175 => '絛', + 64176 => '練', + 64177 => '缾', + 64178 => '者', + 64179 => '荒', + 64180 => '華', + 64181 => '蝹', + 64182 => '襁', + 64183 => '覆', + 64184 => '視', + 64185 => '調', + 64186 => '諸', + 64187 => '請', + 64188 => '謁', + 64189 => '諾', + 64190 => '諭', + 64191 => '謹', + 64192 => '變', + 64193 => '贈', + 64194 => '輸', + 64195 => '遲', + 64196 => '醙', + 64197 => '鉶', + 64198 => '陼', + 64199 => '難', + 64200 => '靖', + 64201 => '韛', + 64202 => '響', + 64203 => '頋', + 64204 => '頻', + 64205 => '鬒', + 64206 => '龜', + 64207 => '𢡊', + 64208 => '𢡄', + 64209 => '𣏕', + 64210 => '㮝', + 64211 => '䀘', + 64212 => '䀹', + 64213 => '𥉉', + 64214 => '𥳐', + 64215 => '𧻓', + 64216 => '齃', + 64217 => '龎', + 64256 => 'ff', + 64257 => 'fi', + 64258 => 'fl', + 64259 => 'ffi', + 64260 => 'ffl', + 64261 => 'st', + 64262 => 'st', + 64275 => 'մն', + 64276 => 'մե', + 64277 => 'մի', + 64278 => 'վն', + 64279 => 'մխ', + 64285 => 'יִ', + 64287 => 'ײַ', + 64288 => 'ע', + 64289 => 'א', + 64290 => 'ד', + 64291 => 'ה', + 64292 => 'כ', + 64293 => 'ל', + 64294 => 'ם', + 64295 => 'ר', + 64296 => 'ת', + 64298 => 'שׁ', + 64299 => 'שׂ', + 64300 => 'שּׁ', + 64301 => 'שּׂ', + 64302 => 'אַ', + 64303 => 'אָ', + 64304 => 'אּ', + 64305 => 'בּ', + 64306 => 'גּ', + 64307 => 'דּ', + 64308 => 'הּ', + 64309 => 'וּ', + 64310 => 'זּ', + 64312 => 'טּ', + 64313 => 'יּ', + 64314 => 'ךּ', + 64315 => 'כּ', + 64316 => 'לּ', + 64318 => 'מּ', + 64320 => 'נּ', + 64321 => 'סּ', + 64323 => 'ףּ', + 64324 => 'פּ', + 64326 => 'צּ', + 64327 => 'קּ', + 64328 => 'רּ', + 64329 => 'שּ', + 64330 => 'תּ', + 64331 => 'וֹ', + 64332 => 'בֿ', + 64333 => 'כֿ', + 64334 => 'פֿ', + 64335 => 'אל', + 64336 => 'ٱ', + 64337 => 'ٱ', + 64338 => 'ٻ', + 64339 => 'ٻ', + 64340 => 'ٻ', + 64341 => 'ٻ', + 64342 => 'پ', + 64343 => 'پ', + 64344 => 'پ', + 64345 => 'پ', + 64346 => 'ڀ', + 64347 => 'ڀ', + 64348 => 'ڀ', + 64349 => 'ڀ', + 64350 => 'ٺ', + 64351 => 'ٺ', + 64352 => 'ٺ', + 64353 => 'ٺ', + 64354 => 'ٿ', + 64355 => 'ٿ', + 64356 => 'ٿ', + 64357 => 'ٿ', + 64358 => 'ٹ', + 64359 => 'ٹ', + 64360 => 'ٹ', + 64361 => 'ٹ', + 64362 => 'ڤ', + 64363 => 'ڤ', + 64364 => 'ڤ', + 64365 => 'ڤ', + 64366 => 'ڦ', + 64367 => 'ڦ', + 64368 => 'ڦ', + 64369 => 'ڦ', + 64370 => 'ڄ', + 64371 => 'ڄ', + 64372 => 'ڄ', + 64373 => 'ڄ', + 64374 => 'ڃ', + 64375 => 'ڃ', + 64376 => 'ڃ', + 64377 => 'ڃ', + 64378 => 'چ', + 64379 => 'چ', + 64380 => 'چ', + 64381 => 'چ', + 64382 => 'ڇ', + 64383 => 'ڇ', + 64384 => 'ڇ', + 64385 => 'ڇ', + 64386 => 'ڍ', + 64387 => 'ڍ', + 64388 => 'ڌ', + 64389 => 'ڌ', + 64390 => 'ڎ', + 64391 => 'ڎ', + 64392 => 'ڈ', + 64393 => 'ڈ', + 64394 => 'ژ', + 64395 => 'ژ', + 64396 => 'ڑ', + 64397 => 'ڑ', + 64398 => 'ک', + 64399 => 'ک', + 64400 => 'ک', + 64401 => 'ک', + 64402 => 'گ', + 64403 => 'گ', + 64404 => 'گ', + 64405 => 'گ', + 64406 => 'ڳ', + 64407 => 'ڳ', + 64408 => 'ڳ', + 64409 => 'ڳ', + 64410 => 'ڱ', + 64411 => 'ڱ', + 64412 => 'ڱ', + 64413 => 'ڱ', + 64414 => 'ں', + 64415 => 'ں', + 64416 => 'ڻ', + 64417 => 'ڻ', + 64418 => 'ڻ', + 64419 => 'ڻ', + 64420 => 'ۀ', + 64421 => 'ۀ', + 64422 => 'ہ', + 64423 => 'ہ', + 64424 => 'ہ', + 64425 => 'ہ', + 64426 => 'ھ', + 64427 => 'ھ', + 64428 => 'ھ', + 64429 => 'ھ', + 64430 => 'ے', + 64431 => 'ے', + 64432 => 'ۓ', + 64433 => 'ۓ', + 64467 => 'ڭ', + 64468 => 'ڭ', + 64469 => 'ڭ', + 64470 => 'ڭ', + 64471 => 'ۇ', + 64472 => 'ۇ', + 64473 => 'ۆ', + 64474 => 'ۆ', + 64475 => 'ۈ', + 64476 => 'ۈ', + 64477 => 'ۇٴ', + 64478 => 'ۋ', + 64479 => 'ۋ', + 64480 => 'ۅ', + 64481 => 'ۅ', + 64482 => 'ۉ', + 64483 => 'ۉ', + 64484 => 'ې', + 64485 => 'ې', + 64486 => 'ې', + 64487 => 'ې', + 64488 => 'ى', + 64489 => 'ى', + 64490 => 'ئا', + 64491 => 'ئا', + 64492 => 'ئە', + 64493 => 'ئە', + 64494 => 'ئو', + 64495 => 'ئو', + 64496 => 'ئۇ', + 64497 => 'ئۇ', + 64498 => 'ئۆ', + 64499 => 'ئۆ', + 64500 => 'ئۈ', + 64501 => 'ئۈ', + 64502 => 'ئې', + 64503 => 'ئې', + 64504 => 'ئې', + 64505 => 'ئى', + 64506 => 'ئى', + 64507 => 'ئى', + 64508 => 'ی', + 64509 => 'ی', + 64510 => 'ی', + 64511 => 'ی', + 64512 => 'ئج', + 64513 => 'ئح', + 64514 => 'ئم', + 64515 => 'ئى', + 64516 => 'ئي', + 64517 => 'بج', + 64518 => 'بح', + 64519 => 'بخ', + 64520 => 'بم', + 64521 => 'بى', + 64522 => 'بي', + 64523 => 'تج', + 64524 => 'تح', + 64525 => 'تخ', + 64526 => 'تم', + 64527 => 'تى', + 64528 => 'تي', + 64529 => 'ثج', + 64530 => 'ثم', + 64531 => 'ثى', + 64532 => 'ثي', + 64533 => 'جح', + 64534 => 'جم', + 64535 => 'حج', + 64536 => 'حم', + 64537 => 'خج', + 64538 => 'خح', + 64539 => 'خم', + 64540 => 'سج', + 64541 => 'سح', + 64542 => 'سخ', + 64543 => 'سم', + 64544 => 'صح', + 64545 => 'صم', + 64546 => 'ضج', + 64547 => 'ضح', + 64548 => 'ضخ', + 64549 => 'ضم', + 64550 => 'طح', + 64551 => 'طم', + 64552 => 'ظم', + 64553 => 'عج', + 64554 => 'عم', + 64555 => 'غج', + 64556 => 'غم', + 64557 => 'فج', + 64558 => 'فح', + 64559 => 'فخ', + 64560 => 'فم', + 64561 => 'فى', + 64562 => 'في', + 64563 => 'قح', + 64564 => 'قم', + 64565 => 'قى', + 64566 => 'قي', + 64567 => 'كا', + 64568 => 'كج', + 64569 => 'كح', + 64570 => 'كخ', + 64571 => 'كل', + 64572 => 'كم', + 64573 => 'كى', + 64574 => 'كي', + 64575 => 'لج', + 64576 => 'لح', + 64577 => 'لخ', + 64578 => 'لم', + 64579 => 'لى', + 64580 => 'لي', + 64581 => 'مج', + 64582 => 'مح', + 64583 => 'مخ', + 64584 => 'مم', + 64585 => 'مى', + 64586 => 'مي', + 64587 => 'نج', + 64588 => 'نح', + 64589 => 'نخ', + 64590 => 'نم', + 64591 => 'نى', + 64592 => 'ني', + 64593 => 'هج', + 64594 => 'هم', + 64595 => 'هى', + 64596 => 'هي', + 64597 => 'يج', + 64598 => 'يح', + 64599 => 'يخ', + 64600 => 'يم', + 64601 => 'يى', + 64602 => 'يي', + 64603 => 'ذٰ', + 64604 => 'رٰ', + 64605 => 'ىٰ', + 64612 => 'ئر', + 64613 => 'ئز', + 64614 => 'ئم', + 64615 => 'ئن', + 64616 => 'ئى', + 64617 => 'ئي', + 64618 => 'بر', + 64619 => 'بز', + 64620 => 'بم', + 64621 => 'بن', + 64622 => 'بى', + 64623 => 'بي', + 64624 => 'تر', + 64625 => 'تز', + 64626 => 'تم', + 64627 => 'تن', + 64628 => 'تى', + 64629 => 'تي', + 64630 => 'ثر', + 64631 => 'ثز', + 64632 => 'ثم', + 64633 => 'ثن', + 64634 => 'ثى', + 64635 => 'ثي', + 64636 => 'فى', + 64637 => 'في', + 64638 => 'قى', + 64639 => 'قي', + 64640 => 'كا', + 64641 => 'كل', + 64642 => 'كم', + 64643 => 'كى', + 64644 => 'كي', + 64645 => 'لم', + 64646 => 'لى', + 64647 => 'لي', + 64648 => 'ما', + 64649 => 'مم', + 64650 => 'نر', + 64651 => 'نز', + 64652 => 'نم', + 64653 => 'نن', + 64654 => 'نى', + 64655 => 'ني', + 64656 => 'ىٰ', + 64657 => 'ير', + 64658 => 'يز', + 64659 => 'يم', + 64660 => 'ين', + 64661 => 'يى', + 64662 => 'يي', + 64663 => 'ئج', + 64664 => 'ئح', + 64665 => 'ئخ', + 64666 => 'ئم', + 64667 => 'ئه', + 64668 => 'بج', + 64669 => 'بح', + 64670 => 'بخ', + 64671 => 'بم', + 64672 => 'به', + 64673 => 'تج', + 64674 => 'تح', + 64675 => 'تخ', + 64676 => 'تم', + 64677 => 'ته', + 64678 => 'ثم', + 64679 => 'جح', + 64680 => 'جم', + 64681 => 'حج', + 64682 => 'حم', + 64683 => 'خج', + 64684 => 'خم', + 64685 => 'سج', + 64686 => 'سح', + 64687 => 'سخ', + 64688 => 'سم', + 64689 => 'صح', + 64690 => 'صخ', + 64691 => 'صم', + 64692 => 'ضج', + 64693 => 'ضح', + 64694 => 'ضخ', + 64695 => 'ضم', + 64696 => 'طح', + 64697 => 'ظم', + 64698 => 'عج', + 64699 => 'عم', + 64700 => 'غج', + 64701 => 'غم', + 64702 => 'فج', + 64703 => 'فح', + 64704 => 'فخ', + 64705 => 'فم', + 64706 => 'قح', + 64707 => 'قم', + 64708 => 'كج', + 64709 => 'كح', + 64710 => 'كخ', + 64711 => 'كل', + 64712 => 'كم', + 64713 => 'لج', + 64714 => 'لح', + 64715 => 'لخ', + 64716 => 'لم', + 64717 => 'له', + 64718 => 'مج', + 64719 => 'مح', + 64720 => 'مخ', + 64721 => 'مم', + 64722 => 'نج', + 64723 => 'نح', + 64724 => 'نخ', + 64725 => 'نم', + 64726 => 'نه', + 64727 => 'هج', + 64728 => 'هم', + 64729 => 'هٰ', + 64730 => 'يج', + 64731 => 'يح', + 64732 => 'يخ', + 64733 => 'يم', + 64734 => 'يه', + 64735 => 'ئم', + 64736 => 'ئه', + 64737 => 'بم', + 64738 => 'به', + 64739 => 'تم', + 64740 => 'ته', + 64741 => 'ثم', + 64742 => 'ثه', + 64743 => 'سم', + 64744 => 'سه', + 64745 => 'شم', + 64746 => 'شه', + 64747 => 'كل', + 64748 => 'كم', + 64749 => 'لم', + 64750 => 'نم', + 64751 => 'نه', + 64752 => 'يم', + 64753 => 'يه', + 64754 => 'ـَّ', + 64755 => 'ـُّ', + 64756 => 'ـِّ', + 64757 => 'طى', + 64758 => 'طي', + 64759 => 'عى', + 64760 => 'عي', + 64761 => 'غى', + 64762 => 'غي', + 64763 => 'سى', + 64764 => 'سي', + 64765 => 'شى', + 64766 => 'شي', + 64767 => 'حى', + 64768 => 'حي', + 64769 => 'جى', + 64770 => 'جي', + 64771 => 'خى', + 64772 => 'خي', + 64773 => 'صى', + 64774 => 'صي', + 64775 => 'ضى', + 64776 => 'ضي', + 64777 => 'شج', + 64778 => 'شح', + 64779 => 'شخ', + 64780 => 'شم', + 64781 => 'شر', + 64782 => 'سر', + 64783 => 'صر', + 64784 => 'ضر', + 64785 => 'طى', + 64786 => 'طي', + 64787 => 'عى', + 64788 => 'عي', + 64789 => 'غى', + 64790 => 'غي', + 64791 => 'سى', + 64792 => 'سي', + 64793 => 'شى', + 64794 => 'شي', + 64795 => 'حى', + 64796 => 'حي', + 64797 => 'جى', + 64798 => 'جي', + 64799 => 'خى', + 64800 => 'خي', + 64801 => 'صى', + 64802 => 'صي', + 64803 => 'ضى', + 64804 => 'ضي', + 64805 => 'شج', + 64806 => 'شح', + 64807 => 'شخ', + 64808 => 'شم', + 64809 => 'شر', + 64810 => 'سر', + 64811 => 'صر', + 64812 => 'ضر', + 64813 => 'شج', + 64814 => 'شح', + 64815 => 'شخ', + 64816 => 'شم', + 64817 => 'سه', + 64818 => 'شه', + 64819 => 'طم', + 64820 => 'سج', + 64821 => 'سح', + 64822 => 'سخ', + 64823 => 'شج', + 64824 => 'شح', + 64825 => 'شخ', + 64826 => 'طم', + 64827 => 'ظم', + 64828 => 'اً', + 64829 => 'اً', + 64848 => 'تجم', + 64849 => 'تحج', + 64850 => 'تحج', + 64851 => 'تحم', + 64852 => 'تخم', + 64853 => 'تمج', + 64854 => 'تمح', + 64855 => 'تمخ', + 64856 => 'جمح', + 64857 => 'جمح', + 64858 => 'حمي', + 64859 => 'حمى', + 64860 => 'سحج', + 64861 => 'سجح', + 64862 => 'سجى', + 64863 => 'سمح', + 64864 => 'سمح', + 64865 => 'سمج', + 64866 => 'سمم', + 64867 => 'سمم', + 64868 => 'صحح', + 64869 => 'صحح', + 64870 => 'صمم', + 64871 => 'شحم', + 64872 => 'شحم', + 64873 => 'شجي', + 64874 => 'شمخ', + 64875 => 'شمخ', + 64876 => 'شمم', + 64877 => 'شمم', + 64878 => 'ضحى', + 64879 => 'ضخم', + 64880 => 'ضخم', + 64881 => 'طمح', + 64882 => 'طمح', + 64883 => 'طمم', + 64884 => 'طمي', + 64885 => 'عجم', + 64886 => 'عمم', + 64887 => 'عمم', + 64888 => 'عمى', + 64889 => 'غمم', + 64890 => 'غمي', + 64891 => 'غمى', + 64892 => 'فخم', + 64893 => 'فخم', + 64894 => 'قمح', + 64895 => 'قمم', + 64896 => 'لحم', + 64897 => 'لحي', + 64898 => 'لحى', + 64899 => 'لجج', + 64900 => 'لجج', + 64901 => 'لخم', + 64902 => 'لخم', + 64903 => 'لمح', + 64904 => 'لمح', + 64905 => 'محج', + 64906 => 'محم', + 64907 => 'محي', + 64908 => 'مجح', + 64909 => 'مجم', + 64910 => 'مخج', + 64911 => 'مخم', + 64914 => 'مجخ', + 64915 => 'همج', + 64916 => 'همم', + 64917 => 'نحم', + 64918 => 'نحى', + 64919 => 'نجم', + 64920 => 'نجم', + 64921 => 'نجى', + 64922 => 'نمي', + 64923 => 'نمى', + 64924 => 'يمم', + 64925 => 'يمم', + 64926 => 'بخي', + 64927 => 'تجي', + 64928 => 'تجى', + 64929 => 'تخي', + 64930 => 'تخى', + 64931 => 'تمي', + 64932 => 'تمى', + 64933 => 'جمي', + 64934 => 'جحى', + 64935 => 'جمى', + 64936 => 'سخى', + 64937 => 'صحي', + 64938 => 'شحي', + 64939 => 'ضحي', + 64940 => 'لجي', + 64941 => 'لمي', + 64942 => 'يحي', + 64943 => 'يجي', + 64944 => 'يمي', + 64945 => 'ممي', + 64946 => 'قمي', + 64947 => 'نحي', + 64948 => 'قمح', + 64949 => 'لحم', + 64950 => 'عمي', + 64951 => 'كمي', + 64952 => 'نجح', + 64953 => 'مخي', + 64954 => 'لجم', + 64955 => 'كمم', + 64956 => 'لجم', + 64957 => 'نجح', + 64958 => 'جحي', + 64959 => 'حجي', + 64960 => 'مجي', + 64961 => 'فمي', + 64962 => 'بحي', + 64963 => 'كمم', + 64964 => 'عجم', + 64965 => 'صمم', + 64966 => 'سخي', + 64967 => 'نجي', + 65008 => 'صلے', + 65009 => 'قلے', + 65010 => 'الله', + 65011 => 'اكبر', + 65012 => 'محمد', + 65013 => 'صلعم', + 65014 => 'رسول', + 65015 => 'عليه', + 65016 => 'وسلم', + 65017 => 'صلى', + 65020 => 'ریال', + 65041 => '、', + 65047 => '〖', + 65048 => '〗', + 65073 => '—', + 65074 => '–', + 65081 => '〔', + 65082 => '〕', + 65083 => '【', + 65084 => '】', + 65085 => '《', + 65086 => '》', + 65087 => '〈', + 65088 => '〉', + 65089 => '「', + 65090 => '」', + 65091 => '『', + 65092 => '』', + 65105 => '、', + 65112 => '—', + 65117 => '〔', + 65118 => '〕', + 65123 => '-', + 65137 => 'ـً', + 65143 => 'ـَ', + 65145 => 'ـُ', + 65147 => 'ـِ', + 65149 => 'ـّ', + 65151 => 'ـْ', + 65152 => 'ء', + 65153 => 'آ', + 65154 => 'آ', + 65155 => 'أ', + 65156 => 'أ', + 65157 => 'ؤ', + 65158 => 'ؤ', + 65159 => 'إ', + 65160 => 'إ', + 65161 => 'ئ', + 65162 => 'ئ', + 65163 => 'ئ', + 65164 => 'ئ', + 65165 => 'ا', + 65166 => 'ا', + 65167 => 'ب', + 65168 => 'ب', + 65169 => 'ب', + 65170 => 'ب', + 65171 => 'ة', + 65172 => 'ة', + 65173 => 'ت', + 65174 => 'ت', + 65175 => 'ت', + 65176 => 'ت', + 65177 => 'ث', + 65178 => 'ث', + 65179 => 'ث', + 65180 => 'ث', + 65181 => 'ج', + 65182 => 'ج', + 65183 => 'ج', + 65184 => 'ج', + 65185 => 'ح', + 65186 => 'ح', + 65187 => 'ح', + 65188 => 'ح', + 65189 => 'خ', + 65190 => 'خ', + 65191 => 'خ', + 65192 => 'خ', + 65193 => 'د', + 65194 => 'د', + 65195 => 'ذ', + 65196 => 'ذ', + 65197 => 'ر', + 65198 => 'ر', + 65199 => 'ز', + 65200 => 'ز', + 65201 => 'س', + 65202 => 'س', + 65203 => 'س', + 65204 => 'س', + 65205 => 'ش', + 65206 => 'ش', + 65207 => 'ش', + 65208 => 'ش', + 65209 => 'ص', + 65210 => 'ص', + 65211 => 'ص', + 65212 => 'ص', + 65213 => 'ض', + 65214 => 'ض', + 65215 => 'ض', + 65216 => 'ض', + 65217 => 'ط', + 65218 => 'ط', + 65219 => 'ط', + 65220 => 'ط', + 65221 => 'ظ', + 65222 => 'ظ', + 65223 => 'ظ', + 65224 => 'ظ', + 65225 => 'ع', + 65226 => 'ع', + 65227 => 'ع', + 65228 => 'ع', + 65229 => 'غ', + 65230 => 'غ', + 65231 => 'غ', + 65232 => 'غ', + 65233 => 'ف', + 65234 => 'ف', + 65235 => 'ف', + 65236 => 'ف', + 65237 => 'ق', + 65238 => 'ق', + 65239 => 'ق', + 65240 => 'ق', + 65241 => 'ك', + 65242 => 'ك', + 65243 => 'ك', + 65244 => 'ك', + 65245 => 'ل', + 65246 => 'ل', + 65247 => 'ل', + 65248 => 'ل', + 65249 => 'م', + 65250 => 'م', + 65251 => 'م', + 65252 => 'م', + 65253 => 'ن', + 65254 => 'ن', + 65255 => 'ن', + 65256 => 'ن', + 65257 => 'ه', + 65258 => 'ه', + 65259 => 'ه', + 65260 => 'ه', + 65261 => 'و', + 65262 => 'و', + 65263 => 'ى', + 65264 => 'ى', + 65265 => 'ي', + 65266 => 'ي', + 65267 => 'ي', + 65268 => 'ي', + 65269 => 'لآ', + 65270 => 'لآ', + 65271 => 'لأ', + 65272 => 'لأ', + 65273 => 'لإ', + 65274 => 'لإ', + 65275 => 'لا', + 65276 => 'لا', + 65293 => '-', + 65294 => '.', + 65296 => '0', + 65297 => '1', + 65298 => '2', + 65299 => '3', + 65300 => '4', + 65301 => '5', + 65302 => '6', + 65303 => '7', + 65304 => '8', + 65305 => '9', + 65313 => 'a', + 65314 => 'b', + 65315 => 'c', + 65316 => 'd', + 65317 => 'e', + 65318 => 'f', + 65319 => 'g', + 65320 => 'h', + 65321 => 'i', + 65322 => 'j', + 65323 => 'k', + 65324 => 'l', + 65325 => 'm', + 65326 => 'n', + 65327 => 'o', + 65328 => 'p', + 65329 => 'q', + 65330 => 'r', + 65331 => 's', + 65332 => 't', + 65333 => 'u', + 65334 => 'v', + 65335 => 'w', + 65336 => 'x', + 65337 => 'y', + 65338 => 'z', + 65345 => 'a', + 65346 => 'b', + 65347 => 'c', + 65348 => 'd', + 65349 => 'e', + 65350 => 'f', + 65351 => 'g', + 65352 => 'h', + 65353 => 'i', + 65354 => 'j', + 65355 => 'k', + 65356 => 'l', + 65357 => 'm', + 65358 => 'n', + 65359 => 'o', + 65360 => 'p', + 65361 => 'q', + 65362 => 'r', + 65363 => 's', + 65364 => 't', + 65365 => 'u', + 65366 => 'v', + 65367 => 'w', + 65368 => 'x', + 65369 => 'y', + 65370 => 'z', + 65375 => '⦅', + 65376 => '⦆', + 65377 => '.', + 65378 => '「', + 65379 => '」', + 65380 => '、', + 65381 => '・', + 65382 => 'ヲ', + 65383 => 'ァ', + 65384 => 'ィ', + 65385 => 'ゥ', + 65386 => 'ェ', + 65387 => 'ォ', + 65388 => 'ャ', + 65389 => 'ュ', + 65390 => 'ョ', + 65391 => 'ッ', + 65392 => 'ー', + 65393 => 'ア', + 65394 => 'イ', + 65395 => 'ウ', + 65396 => 'エ', + 65397 => 'オ', + 65398 => 'カ', + 65399 => 'キ', + 65400 => 'ク', + 65401 => 'ケ', + 65402 => 'コ', + 65403 => 'サ', + 65404 => 'シ', + 65405 => 'ス', + 65406 => 'セ', + 65407 => 'ソ', + 65408 => 'タ', + 65409 => 'チ', + 65410 => 'ツ', + 65411 => 'テ', + 65412 => 'ト', + 65413 => 'ナ', + 65414 => 'ニ', + 65415 => 'ヌ', + 65416 => 'ネ', + 65417 => 'ノ', + 65418 => 'ハ', + 65419 => 'ヒ', + 65420 => 'フ', + 65421 => 'ヘ', + 65422 => 'ホ', + 65423 => 'マ', + 65424 => 'ミ', + 65425 => 'ム', + 65426 => 'メ', + 65427 => 'モ', + 65428 => 'ヤ', + 65429 => 'ユ', + 65430 => 'ヨ', + 65431 => 'ラ', + 65432 => 'リ', + 65433 => 'ル', + 65434 => 'レ', + 65435 => 'ロ', + 65436 => 'ワ', + 65437 => 'ン', + 65438 => '゙', + 65439 => '゚', + 65441 => 'ᄀ', + 65442 => 'ᄁ', + 65443 => 'ᆪ', + 65444 => 'ᄂ', + 65445 => 'ᆬ', + 65446 => 'ᆭ', + 65447 => 'ᄃ', + 65448 => 'ᄄ', + 65449 => 'ᄅ', + 65450 => 'ᆰ', + 65451 => 'ᆱ', + 65452 => 'ᆲ', + 65453 => 'ᆳ', + 65454 => 'ᆴ', + 65455 => 'ᆵ', + 65456 => 'ᄚ', + 65457 => 'ᄆ', + 65458 => 'ᄇ', + 65459 => 'ᄈ', + 65460 => 'ᄡ', + 65461 => 'ᄉ', + 65462 => 'ᄊ', + 65463 => 'ᄋ', + 65464 => 'ᄌ', + 65465 => 'ᄍ', + 65466 => 'ᄎ', + 65467 => 'ᄏ', + 65468 => 'ᄐ', + 65469 => 'ᄑ', + 65470 => 'ᄒ', + 65474 => 'ᅡ', + 65475 => 'ᅢ', + 65476 => 'ᅣ', + 65477 => 'ᅤ', + 65478 => 'ᅥ', + 65479 => 'ᅦ', + 65482 => 'ᅧ', + 65483 => 'ᅨ', + 65484 => 'ᅩ', + 65485 => 'ᅪ', + 65486 => 'ᅫ', + 65487 => 'ᅬ', + 65490 => 'ᅭ', + 65491 => 'ᅮ', + 65492 => 'ᅯ', + 65493 => 'ᅰ', + 65494 => 'ᅱ', + 65495 => 'ᅲ', + 65498 => 'ᅳ', + 65499 => 'ᅴ', + 65500 => 'ᅵ', + 65504 => '¢', + 65505 => '£', + 65506 => '¬', + 65508 => '¦', + 65509 => '¥', + 65510 => '₩', + 65512 => '│', + 65513 => '←', + 65514 => '↑', + 65515 => '→', + 65516 => '↓', + 65517 => '■', + 65518 => '○', + 66560 => '𐐨', + 66561 => '𐐩', + 66562 => '𐐪', + 66563 => '𐐫', + 66564 => '𐐬', + 66565 => '𐐭', + 66566 => '𐐮', + 66567 => '𐐯', + 66568 => '𐐰', + 66569 => '𐐱', + 66570 => '𐐲', + 66571 => '𐐳', + 66572 => '𐐴', + 66573 => '𐐵', + 66574 => '𐐶', + 66575 => '𐐷', + 66576 => '𐐸', + 66577 => '𐐹', + 66578 => '𐐺', + 66579 => '𐐻', + 66580 => '𐐼', + 66581 => '𐐽', + 66582 => '𐐾', + 66583 => '𐐿', + 66584 => '𐑀', + 66585 => '𐑁', + 66586 => '𐑂', + 66587 => '𐑃', + 66588 => '𐑄', + 66589 => '𐑅', + 66590 => '𐑆', + 66591 => '𐑇', + 66592 => '𐑈', + 66593 => '𐑉', + 66594 => '𐑊', + 66595 => '𐑋', + 66596 => '𐑌', + 66597 => '𐑍', + 66598 => '𐑎', + 66599 => '𐑏', + 66736 => '𐓘', + 66737 => '𐓙', + 66738 => '𐓚', + 66739 => '𐓛', + 66740 => '𐓜', + 66741 => '𐓝', + 66742 => '𐓞', + 66743 => '𐓟', + 66744 => '𐓠', + 66745 => '𐓡', + 66746 => '𐓢', + 66747 => '𐓣', + 66748 => '𐓤', + 66749 => '𐓥', + 66750 => '𐓦', + 66751 => '𐓧', + 66752 => '𐓨', + 66753 => '𐓩', + 66754 => '𐓪', + 66755 => '𐓫', + 66756 => '𐓬', + 66757 => '𐓭', + 66758 => '𐓮', + 66759 => '𐓯', + 66760 => '𐓰', + 66761 => '𐓱', + 66762 => '𐓲', + 66763 => '𐓳', + 66764 => '𐓴', + 66765 => '𐓵', + 66766 => '𐓶', + 66767 => '𐓷', + 66768 => '𐓸', + 66769 => '𐓹', + 66770 => '𐓺', + 66771 => '𐓻', + 68736 => '𐳀', + 68737 => '𐳁', + 68738 => '𐳂', + 68739 => '𐳃', + 68740 => '𐳄', + 68741 => '𐳅', + 68742 => '𐳆', + 68743 => '𐳇', + 68744 => '𐳈', + 68745 => '𐳉', + 68746 => '𐳊', + 68747 => '𐳋', + 68748 => '𐳌', + 68749 => '𐳍', + 68750 => '𐳎', + 68751 => '𐳏', + 68752 => '𐳐', + 68753 => '𐳑', + 68754 => '𐳒', + 68755 => '𐳓', + 68756 => '𐳔', + 68757 => '𐳕', + 68758 => '𐳖', + 68759 => '𐳗', + 68760 => '𐳘', + 68761 => '𐳙', + 68762 => '𐳚', + 68763 => '𐳛', + 68764 => '𐳜', + 68765 => '𐳝', + 68766 => '𐳞', + 68767 => '𐳟', + 68768 => '𐳠', + 68769 => '𐳡', + 68770 => '𐳢', + 68771 => '𐳣', + 68772 => '𐳤', + 68773 => '𐳥', + 68774 => '𐳦', + 68775 => '𐳧', + 68776 => '𐳨', + 68777 => '𐳩', + 68778 => '𐳪', + 68779 => '𐳫', + 68780 => '𐳬', + 68781 => '𐳭', + 68782 => '𐳮', + 68783 => '𐳯', + 68784 => '𐳰', + 68785 => '𐳱', + 68786 => '𐳲', + 71840 => '𑣀', + 71841 => '𑣁', + 71842 => '𑣂', + 71843 => '𑣃', + 71844 => '𑣄', + 71845 => '𑣅', + 71846 => '𑣆', + 71847 => '𑣇', + 71848 => '𑣈', + 71849 => '𑣉', + 71850 => '𑣊', + 71851 => '𑣋', + 71852 => '𑣌', + 71853 => '𑣍', + 71854 => '𑣎', + 71855 => '𑣏', + 71856 => '𑣐', + 71857 => '𑣑', + 71858 => '𑣒', + 71859 => '𑣓', + 71860 => '𑣔', + 71861 => '𑣕', + 71862 => '𑣖', + 71863 => '𑣗', + 71864 => '𑣘', + 71865 => '𑣙', + 71866 => '𑣚', + 71867 => '𑣛', + 71868 => '𑣜', + 71869 => '𑣝', + 71870 => '𑣞', + 71871 => '𑣟', + 93760 => '𖹠', + 93761 => '𖹡', + 93762 => '𖹢', + 93763 => '𖹣', + 93764 => '𖹤', + 93765 => '𖹥', + 93766 => '𖹦', + 93767 => '𖹧', + 93768 => '𖹨', + 93769 => '𖹩', + 93770 => '𖹪', + 93771 => '𖹫', + 93772 => '𖹬', + 93773 => '𖹭', + 93774 => '𖹮', + 93775 => '𖹯', + 93776 => '𖹰', + 93777 => '𖹱', + 93778 => '𖹲', + 93779 => '𖹳', + 93780 => '𖹴', + 93781 => '𖹵', + 93782 => '𖹶', + 93783 => '𖹷', + 93784 => '𖹸', + 93785 => '𖹹', + 93786 => '𖹺', + 93787 => '𖹻', + 93788 => '𖹼', + 93789 => '𖹽', + 93790 => '𖹾', + 93791 => '𖹿', + 119134 => '𝅗𝅥', + 119135 => '𝅘𝅥', + 119136 => '𝅘𝅥𝅮', + 119137 => '𝅘𝅥𝅯', + 119138 => '𝅘𝅥𝅰', + 119139 => '𝅘𝅥𝅱', + 119140 => '𝅘𝅥𝅲', + 119227 => '𝆹𝅥', + 119228 => '𝆺𝅥', + 119229 => '𝆹𝅥𝅮', + 119230 => '𝆺𝅥𝅮', + 119231 => '𝆹𝅥𝅯', + 119232 => '𝆺𝅥𝅯', + 119808 => 'a', + 119809 => 'b', + 119810 => 'c', + 119811 => 'd', + 119812 => 'e', + 119813 => 'f', + 119814 => 'g', + 119815 => 'h', + 119816 => 'i', + 119817 => 'j', + 119818 => 'k', + 119819 => 'l', + 119820 => 'm', + 119821 => 'n', + 119822 => 'o', + 119823 => 'p', + 119824 => 'q', + 119825 => 'r', + 119826 => 's', + 119827 => 't', + 119828 => 'u', + 119829 => 'v', + 119830 => 'w', + 119831 => 'x', + 119832 => 'y', + 119833 => 'z', + 119834 => 'a', + 119835 => 'b', + 119836 => 'c', + 119837 => 'd', + 119838 => 'e', + 119839 => 'f', + 119840 => 'g', + 119841 => 'h', + 119842 => 'i', + 119843 => 'j', + 119844 => 'k', + 119845 => 'l', + 119846 => 'm', + 119847 => 'n', + 119848 => 'o', + 119849 => 'p', + 119850 => 'q', + 119851 => 'r', + 119852 => 's', + 119853 => 't', + 119854 => 'u', + 119855 => 'v', + 119856 => 'w', + 119857 => 'x', + 119858 => 'y', + 119859 => 'z', + 119860 => 'a', + 119861 => 'b', + 119862 => 'c', + 119863 => 'd', + 119864 => 'e', + 119865 => 'f', + 119866 => 'g', + 119867 => 'h', + 119868 => 'i', + 119869 => 'j', + 119870 => 'k', + 119871 => 'l', + 119872 => 'm', + 119873 => 'n', + 119874 => 'o', + 119875 => 'p', + 119876 => 'q', + 119877 => 'r', + 119878 => 's', + 119879 => 't', + 119880 => 'u', + 119881 => 'v', + 119882 => 'w', + 119883 => 'x', + 119884 => 'y', + 119885 => 'z', + 119886 => 'a', + 119887 => 'b', + 119888 => 'c', + 119889 => 'd', + 119890 => 'e', + 119891 => 'f', + 119892 => 'g', + 119894 => 'i', + 119895 => 'j', + 119896 => 'k', + 119897 => 'l', + 119898 => 'm', + 119899 => 'n', + 119900 => 'o', + 119901 => 'p', + 119902 => 'q', + 119903 => 'r', + 119904 => 's', + 119905 => 't', + 119906 => 'u', + 119907 => 'v', + 119908 => 'w', + 119909 => 'x', + 119910 => 'y', + 119911 => 'z', + 119912 => 'a', + 119913 => 'b', + 119914 => 'c', + 119915 => 'd', + 119916 => 'e', + 119917 => 'f', + 119918 => 'g', + 119919 => 'h', + 119920 => 'i', + 119921 => 'j', + 119922 => 'k', + 119923 => 'l', + 119924 => 'm', + 119925 => 'n', + 119926 => 'o', + 119927 => 'p', + 119928 => 'q', + 119929 => 'r', + 119930 => 's', + 119931 => 't', + 119932 => 'u', + 119933 => 'v', + 119934 => 'w', + 119935 => 'x', + 119936 => 'y', + 119937 => 'z', + 119938 => 'a', + 119939 => 'b', + 119940 => 'c', + 119941 => 'd', + 119942 => 'e', + 119943 => 'f', + 119944 => 'g', + 119945 => 'h', + 119946 => 'i', + 119947 => 'j', + 119948 => 'k', + 119949 => 'l', + 119950 => 'm', + 119951 => 'n', + 119952 => 'o', + 119953 => 'p', + 119954 => 'q', + 119955 => 'r', + 119956 => 's', + 119957 => 't', + 119958 => 'u', + 119959 => 'v', + 119960 => 'w', + 119961 => 'x', + 119962 => 'y', + 119963 => 'z', + 119964 => 'a', + 119966 => 'c', + 119967 => 'd', + 119970 => 'g', + 119973 => 'j', + 119974 => 'k', + 119977 => 'n', + 119978 => 'o', + 119979 => 'p', + 119980 => 'q', + 119982 => 's', + 119983 => 't', + 119984 => 'u', + 119985 => 'v', + 119986 => 'w', + 119987 => 'x', + 119988 => 'y', + 119989 => 'z', + 119990 => 'a', + 119991 => 'b', + 119992 => 'c', + 119993 => 'd', + 119995 => 'f', + 119997 => 'h', + 119998 => 'i', + 119999 => 'j', + 120000 => 'k', + 120001 => 'l', + 120002 => 'm', + 120003 => 'n', + 120005 => 'p', + 120006 => 'q', + 120007 => 'r', + 120008 => 's', + 120009 => 't', + 120010 => 'u', + 120011 => 'v', + 120012 => 'w', + 120013 => 'x', + 120014 => 'y', + 120015 => 'z', + 120016 => 'a', + 120017 => 'b', + 120018 => 'c', + 120019 => 'd', + 120020 => 'e', + 120021 => 'f', + 120022 => 'g', + 120023 => 'h', + 120024 => 'i', + 120025 => 'j', + 120026 => 'k', + 120027 => 'l', + 120028 => 'm', + 120029 => 'n', + 120030 => 'o', + 120031 => 'p', + 120032 => 'q', + 120033 => 'r', + 120034 => 's', + 120035 => 't', + 120036 => 'u', + 120037 => 'v', + 120038 => 'w', + 120039 => 'x', + 120040 => 'y', + 120041 => 'z', + 120042 => 'a', + 120043 => 'b', + 120044 => 'c', + 120045 => 'd', + 120046 => 'e', + 120047 => 'f', + 120048 => 'g', + 120049 => 'h', + 120050 => 'i', + 120051 => 'j', + 120052 => 'k', + 120053 => 'l', + 120054 => 'm', + 120055 => 'n', + 120056 => 'o', + 120057 => 'p', + 120058 => 'q', + 120059 => 'r', + 120060 => 's', + 120061 => 't', + 120062 => 'u', + 120063 => 'v', + 120064 => 'w', + 120065 => 'x', + 120066 => 'y', + 120067 => 'z', + 120068 => 'a', + 120069 => 'b', + 120071 => 'd', + 120072 => 'e', + 120073 => 'f', + 120074 => 'g', + 120077 => 'j', + 120078 => 'k', + 120079 => 'l', + 120080 => 'm', + 120081 => 'n', + 120082 => 'o', + 120083 => 'p', + 120084 => 'q', + 120086 => 's', + 120087 => 't', + 120088 => 'u', + 120089 => 'v', + 120090 => 'w', + 120091 => 'x', + 120092 => 'y', + 120094 => 'a', + 120095 => 'b', + 120096 => 'c', + 120097 => 'd', + 120098 => 'e', + 120099 => 'f', + 120100 => 'g', + 120101 => 'h', + 120102 => 'i', + 120103 => 'j', + 120104 => 'k', + 120105 => 'l', + 120106 => 'm', + 120107 => 'n', + 120108 => 'o', + 120109 => 'p', + 120110 => 'q', + 120111 => 'r', + 120112 => 's', + 120113 => 't', + 120114 => 'u', + 120115 => 'v', + 120116 => 'w', + 120117 => 'x', + 120118 => 'y', + 120119 => 'z', + 120120 => 'a', + 120121 => 'b', + 120123 => 'd', + 120124 => 'e', + 120125 => 'f', + 120126 => 'g', + 120128 => 'i', + 120129 => 'j', + 120130 => 'k', + 120131 => 'l', + 120132 => 'm', + 120134 => 'o', + 120138 => 's', + 120139 => 't', + 120140 => 'u', + 120141 => 'v', + 120142 => 'w', + 120143 => 'x', + 120144 => 'y', + 120146 => 'a', + 120147 => 'b', + 120148 => 'c', + 120149 => 'd', + 120150 => 'e', + 120151 => 'f', + 120152 => 'g', + 120153 => 'h', + 120154 => 'i', + 120155 => 'j', + 120156 => 'k', + 120157 => 'l', + 120158 => 'm', + 120159 => 'n', + 120160 => 'o', + 120161 => 'p', + 120162 => 'q', + 120163 => 'r', + 120164 => 's', + 120165 => 't', + 120166 => 'u', + 120167 => 'v', + 120168 => 'w', + 120169 => 'x', + 120170 => 'y', + 120171 => 'z', + 120172 => 'a', + 120173 => 'b', + 120174 => 'c', + 120175 => 'd', + 120176 => 'e', + 120177 => 'f', + 120178 => 'g', + 120179 => 'h', + 120180 => 'i', + 120181 => 'j', + 120182 => 'k', + 120183 => 'l', + 120184 => 'm', + 120185 => 'n', + 120186 => 'o', + 120187 => 'p', + 120188 => 'q', + 120189 => 'r', + 120190 => 's', + 120191 => 't', + 120192 => 'u', + 120193 => 'v', + 120194 => 'w', + 120195 => 'x', + 120196 => 'y', + 120197 => 'z', + 120198 => 'a', + 120199 => 'b', + 120200 => 'c', + 120201 => 'd', + 120202 => 'e', + 120203 => 'f', + 120204 => 'g', + 120205 => 'h', + 120206 => 'i', + 120207 => 'j', + 120208 => 'k', + 120209 => 'l', + 120210 => 'm', + 120211 => 'n', + 120212 => 'o', + 120213 => 'p', + 120214 => 'q', + 120215 => 'r', + 120216 => 's', + 120217 => 't', + 120218 => 'u', + 120219 => 'v', + 120220 => 'w', + 120221 => 'x', + 120222 => 'y', + 120223 => 'z', + 120224 => 'a', + 120225 => 'b', + 120226 => 'c', + 120227 => 'd', + 120228 => 'e', + 120229 => 'f', + 120230 => 'g', + 120231 => 'h', + 120232 => 'i', + 120233 => 'j', + 120234 => 'k', + 120235 => 'l', + 120236 => 'm', + 120237 => 'n', + 120238 => 'o', + 120239 => 'p', + 120240 => 'q', + 120241 => 'r', + 120242 => 's', + 120243 => 't', + 120244 => 'u', + 120245 => 'v', + 120246 => 'w', + 120247 => 'x', + 120248 => 'y', + 120249 => 'z', + 120250 => 'a', + 120251 => 'b', + 120252 => 'c', + 120253 => 'd', + 120254 => 'e', + 120255 => 'f', + 120256 => 'g', + 120257 => 'h', + 120258 => 'i', + 120259 => 'j', + 120260 => 'k', + 120261 => 'l', + 120262 => 'm', + 120263 => 'n', + 120264 => 'o', + 120265 => 'p', + 120266 => 'q', + 120267 => 'r', + 120268 => 's', + 120269 => 't', + 120270 => 'u', + 120271 => 'v', + 120272 => 'w', + 120273 => 'x', + 120274 => 'y', + 120275 => 'z', + 120276 => 'a', + 120277 => 'b', + 120278 => 'c', + 120279 => 'd', + 120280 => 'e', + 120281 => 'f', + 120282 => 'g', + 120283 => 'h', + 120284 => 'i', + 120285 => 'j', + 120286 => 'k', + 120287 => 'l', + 120288 => 'm', + 120289 => 'n', + 120290 => 'o', + 120291 => 'p', + 120292 => 'q', + 120293 => 'r', + 120294 => 's', + 120295 => 't', + 120296 => 'u', + 120297 => 'v', + 120298 => 'w', + 120299 => 'x', + 120300 => 'y', + 120301 => 'z', + 120302 => 'a', + 120303 => 'b', + 120304 => 'c', + 120305 => 'd', + 120306 => 'e', + 120307 => 'f', + 120308 => 'g', + 120309 => 'h', + 120310 => 'i', + 120311 => 'j', + 120312 => 'k', + 120313 => 'l', + 120314 => 'm', + 120315 => 'n', + 120316 => 'o', + 120317 => 'p', + 120318 => 'q', + 120319 => 'r', + 120320 => 's', + 120321 => 't', + 120322 => 'u', + 120323 => 'v', + 120324 => 'w', + 120325 => 'x', + 120326 => 'y', + 120327 => 'z', + 120328 => 'a', + 120329 => 'b', + 120330 => 'c', + 120331 => 'd', + 120332 => 'e', + 120333 => 'f', + 120334 => 'g', + 120335 => 'h', + 120336 => 'i', + 120337 => 'j', + 120338 => 'k', + 120339 => 'l', + 120340 => 'm', + 120341 => 'n', + 120342 => 'o', + 120343 => 'p', + 120344 => 'q', + 120345 => 'r', + 120346 => 's', + 120347 => 't', + 120348 => 'u', + 120349 => 'v', + 120350 => 'w', + 120351 => 'x', + 120352 => 'y', + 120353 => 'z', + 120354 => 'a', + 120355 => 'b', + 120356 => 'c', + 120357 => 'd', + 120358 => 'e', + 120359 => 'f', + 120360 => 'g', + 120361 => 'h', + 120362 => 'i', + 120363 => 'j', + 120364 => 'k', + 120365 => 'l', + 120366 => 'm', + 120367 => 'n', + 120368 => 'o', + 120369 => 'p', + 120370 => 'q', + 120371 => 'r', + 120372 => 's', + 120373 => 't', + 120374 => 'u', + 120375 => 'v', + 120376 => 'w', + 120377 => 'x', + 120378 => 'y', + 120379 => 'z', + 120380 => 'a', + 120381 => 'b', + 120382 => 'c', + 120383 => 'd', + 120384 => 'e', + 120385 => 'f', + 120386 => 'g', + 120387 => 'h', + 120388 => 'i', + 120389 => 'j', + 120390 => 'k', + 120391 => 'l', + 120392 => 'm', + 120393 => 'n', + 120394 => 'o', + 120395 => 'p', + 120396 => 'q', + 120397 => 'r', + 120398 => 's', + 120399 => 't', + 120400 => 'u', + 120401 => 'v', + 120402 => 'w', + 120403 => 'x', + 120404 => 'y', + 120405 => 'z', + 120406 => 'a', + 120407 => 'b', + 120408 => 'c', + 120409 => 'd', + 120410 => 'e', + 120411 => 'f', + 120412 => 'g', + 120413 => 'h', + 120414 => 'i', + 120415 => 'j', + 120416 => 'k', + 120417 => 'l', + 120418 => 'm', + 120419 => 'n', + 120420 => 'o', + 120421 => 'p', + 120422 => 'q', + 120423 => 'r', + 120424 => 's', + 120425 => 't', + 120426 => 'u', + 120427 => 'v', + 120428 => 'w', + 120429 => 'x', + 120430 => 'y', + 120431 => 'z', + 120432 => 'a', + 120433 => 'b', + 120434 => 'c', + 120435 => 'd', + 120436 => 'e', + 120437 => 'f', + 120438 => 'g', + 120439 => 'h', + 120440 => 'i', + 120441 => 'j', + 120442 => 'k', + 120443 => 'l', + 120444 => 'm', + 120445 => 'n', + 120446 => 'o', + 120447 => 'p', + 120448 => 'q', + 120449 => 'r', + 120450 => 's', + 120451 => 't', + 120452 => 'u', + 120453 => 'v', + 120454 => 'w', + 120455 => 'x', + 120456 => 'y', + 120457 => 'z', + 120458 => 'a', + 120459 => 'b', + 120460 => 'c', + 120461 => 'd', + 120462 => 'e', + 120463 => 'f', + 120464 => 'g', + 120465 => 'h', + 120466 => 'i', + 120467 => 'j', + 120468 => 'k', + 120469 => 'l', + 120470 => 'm', + 120471 => 'n', + 120472 => 'o', + 120473 => 'p', + 120474 => 'q', + 120475 => 'r', + 120476 => 's', + 120477 => 't', + 120478 => 'u', + 120479 => 'v', + 120480 => 'w', + 120481 => 'x', + 120482 => 'y', + 120483 => 'z', + 120484 => 'ı', + 120485 => 'ȷ', + 120488 => 'α', + 120489 => 'β', + 120490 => 'γ', + 120491 => 'δ', + 120492 => 'ε', + 120493 => 'ζ', + 120494 => 'η', + 120495 => 'θ', + 120496 => 'ι', + 120497 => 'κ', + 120498 => 'λ', + 120499 => 'μ', + 120500 => 'ν', + 120501 => 'ξ', + 120502 => 'ο', + 120503 => 'π', + 120504 => 'ρ', + 120505 => 'θ', + 120506 => 'σ', + 120507 => 'τ', + 120508 => 'υ', + 120509 => 'φ', + 120510 => 'χ', + 120511 => 'ψ', + 120512 => 'ω', + 120513 => '∇', + 120514 => 'α', + 120515 => 'β', + 120516 => 'γ', + 120517 => 'δ', + 120518 => 'ε', + 120519 => 'ζ', + 120520 => 'η', + 120521 => 'θ', + 120522 => 'ι', + 120523 => 'κ', + 120524 => 'λ', + 120525 => 'μ', + 120526 => 'ν', + 120527 => 'ξ', + 120528 => 'ο', + 120529 => 'π', + 120530 => 'ρ', + 120531 => 'σ', + 120532 => 'σ', + 120533 => 'τ', + 120534 => 'υ', + 120535 => 'φ', + 120536 => 'χ', + 120537 => 'ψ', + 120538 => 'ω', + 120539 => '∂', + 120540 => 'ε', + 120541 => 'θ', + 120542 => 'κ', + 120543 => 'φ', + 120544 => 'ρ', + 120545 => 'π', + 120546 => 'α', + 120547 => 'β', + 120548 => 'γ', + 120549 => 'δ', + 120550 => 'ε', + 120551 => 'ζ', + 120552 => 'η', + 120553 => 'θ', + 120554 => 'ι', + 120555 => 'κ', + 120556 => 'λ', + 120557 => 'μ', + 120558 => 'ν', + 120559 => 'ξ', + 120560 => 'ο', + 120561 => 'π', + 120562 => 'ρ', + 120563 => 'θ', + 120564 => 'σ', + 120565 => 'τ', + 120566 => 'υ', + 120567 => 'φ', + 120568 => 'χ', + 120569 => 'ψ', + 120570 => 'ω', + 120571 => '∇', + 120572 => 'α', + 120573 => 'β', + 120574 => 'γ', + 120575 => 'δ', + 120576 => 'ε', + 120577 => 'ζ', + 120578 => 'η', + 120579 => 'θ', + 120580 => 'ι', + 120581 => 'κ', + 120582 => 'λ', + 120583 => 'μ', + 120584 => 'ν', + 120585 => 'ξ', + 120586 => 'ο', + 120587 => 'π', + 120588 => 'ρ', + 120589 => 'σ', + 120590 => 'σ', + 120591 => 'τ', + 120592 => 'υ', + 120593 => 'φ', + 120594 => 'χ', + 120595 => 'ψ', + 120596 => 'ω', + 120597 => '∂', + 120598 => 'ε', + 120599 => 'θ', + 120600 => 'κ', + 120601 => 'φ', + 120602 => 'ρ', + 120603 => 'π', + 120604 => 'α', + 120605 => 'β', + 120606 => 'γ', + 120607 => 'δ', + 120608 => 'ε', + 120609 => 'ζ', + 120610 => 'η', + 120611 => 'θ', + 120612 => 'ι', + 120613 => 'κ', + 120614 => 'λ', + 120615 => 'μ', + 120616 => 'ν', + 120617 => 'ξ', + 120618 => 'ο', + 120619 => 'π', + 120620 => 'ρ', + 120621 => 'θ', + 120622 => 'σ', + 120623 => 'τ', + 120624 => 'υ', + 120625 => 'φ', + 120626 => 'χ', + 120627 => 'ψ', + 120628 => 'ω', + 120629 => '∇', + 120630 => 'α', + 120631 => 'β', + 120632 => 'γ', + 120633 => 'δ', + 120634 => 'ε', + 120635 => 'ζ', + 120636 => 'η', + 120637 => 'θ', + 120638 => 'ι', + 120639 => 'κ', + 120640 => 'λ', + 120641 => 'μ', + 120642 => 'ν', + 120643 => 'ξ', + 120644 => 'ο', + 120645 => 'π', + 120646 => 'ρ', + 120647 => 'σ', + 120648 => 'σ', + 120649 => 'τ', + 120650 => 'υ', + 120651 => 'φ', + 120652 => 'χ', + 120653 => 'ψ', + 120654 => 'ω', + 120655 => '∂', + 120656 => 'ε', + 120657 => 'θ', + 120658 => 'κ', + 120659 => 'φ', + 120660 => 'ρ', + 120661 => 'π', + 120662 => 'α', + 120663 => 'β', + 120664 => 'γ', + 120665 => 'δ', + 120666 => 'ε', + 120667 => 'ζ', + 120668 => 'η', + 120669 => 'θ', + 120670 => 'ι', + 120671 => 'κ', + 120672 => 'λ', + 120673 => 'μ', + 120674 => 'ν', + 120675 => 'ξ', + 120676 => 'ο', + 120677 => 'π', + 120678 => 'ρ', + 120679 => 'θ', + 120680 => 'σ', + 120681 => 'τ', + 120682 => 'υ', + 120683 => 'φ', + 120684 => 'χ', + 120685 => 'ψ', + 120686 => 'ω', + 120687 => '∇', + 120688 => 'α', + 120689 => 'β', + 120690 => 'γ', + 120691 => 'δ', + 120692 => 'ε', + 120693 => 'ζ', + 120694 => 'η', + 120695 => 'θ', + 120696 => 'ι', + 120697 => 'κ', + 120698 => 'λ', + 120699 => 'μ', + 120700 => 'ν', + 120701 => 'ξ', + 120702 => 'ο', + 120703 => 'π', + 120704 => 'ρ', + 120705 => 'σ', + 120706 => 'σ', + 120707 => 'τ', + 120708 => 'υ', + 120709 => 'φ', + 120710 => 'χ', + 120711 => 'ψ', + 120712 => 'ω', + 120713 => '∂', + 120714 => 'ε', + 120715 => 'θ', + 120716 => 'κ', + 120717 => 'φ', + 120718 => 'ρ', + 120719 => 'π', + 120720 => 'α', + 120721 => 'β', + 120722 => 'γ', + 120723 => 'δ', + 120724 => 'ε', + 120725 => 'ζ', + 120726 => 'η', + 120727 => 'θ', + 120728 => 'ι', + 120729 => 'κ', + 120730 => 'λ', + 120731 => 'μ', + 120732 => 'ν', + 120733 => 'ξ', + 120734 => 'ο', + 120735 => 'π', + 120736 => 'ρ', + 120737 => 'θ', + 120738 => 'σ', + 120739 => 'τ', + 120740 => 'υ', + 120741 => 'φ', + 120742 => 'χ', + 120743 => 'ψ', + 120744 => 'ω', + 120745 => '∇', + 120746 => 'α', + 120747 => 'β', + 120748 => 'γ', + 120749 => 'δ', + 120750 => 'ε', + 120751 => 'ζ', + 120752 => 'η', + 120753 => 'θ', + 120754 => 'ι', + 120755 => 'κ', + 120756 => 'λ', + 120757 => 'μ', + 120758 => 'ν', + 120759 => 'ξ', + 120760 => 'ο', + 120761 => 'π', + 120762 => 'ρ', + 120763 => 'σ', + 120764 => 'σ', + 120765 => 'τ', + 120766 => 'υ', + 120767 => 'φ', + 120768 => 'χ', + 120769 => 'ψ', + 120770 => 'ω', + 120771 => '∂', + 120772 => 'ε', + 120773 => 'θ', + 120774 => 'κ', + 120775 => 'φ', + 120776 => 'ρ', + 120777 => 'π', + 120778 => 'ϝ', + 120779 => 'ϝ', + 120782 => '0', + 120783 => '1', + 120784 => '2', + 120785 => '3', + 120786 => '4', + 120787 => '5', + 120788 => '6', + 120789 => '7', + 120790 => '8', + 120791 => '9', + 120792 => '0', + 120793 => '1', + 120794 => '2', + 120795 => '3', + 120796 => '4', + 120797 => '5', + 120798 => '6', + 120799 => '7', + 120800 => '8', + 120801 => '9', + 120802 => '0', + 120803 => '1', + 120804 => '2', + 120805 => '3', + 120806 => '4', + 120807 => '5', + 120808 => '6', + 120809 => '7', + 120810 => '8', + 120811 => '9', + 120812 => '0', + 120813 => '1', + 120814 => '2', + 120815 => '3', + 120816 => '4', + 120817 => '5', + 120818 => '6', + 120819 => '7', + 120820 => '8', + 120821 => '9', + 120822 => '0', + 120823 => '1', + 120824 => '2', + 120825 => '3', + 120826 => '4', + 120827 => '5', + 120828 => '6', + 120829 => '7', + 120830 => '8', + 120831 => '9', + 125184 => '𞤢', + 125185 => '𞤣', + 125186 => '𞤤', + 125187 => '𞤥', + 125188 => '𞤦', + 125189 => '𞤧', + 125190 => '𞤨', + 125191 => '𞤩', + 125192 => '𞤪', + 125193 => '𞤫', + 125194 => '𞤬', + 125195 => '𞤭', + 125196 => '𞤮', + 125197 => '𞤯', + 125198 => '𞤰', + 125199 => '𞤱', + 125200 => '𞤲', + 125201 => '𞤳', + 125202 => '𞤴', + 125203 => '𞤵', + 125204 => '𞤶', + 125205 => '𞤷', + 125206 => '𞤸', + 125207 => '𞤹', + 125208 => '𞤺', + 125209 => '𞤻', + 125210 => '𞤼', + 125211 => '𞤽', + 125212 => '𞤾', + 125213 => '𞤿', + 125214 => '𞥀', + 125215 => '𞥁', + 125216 => '𞥂', + 125217 => '𞥃', + 126464 => 'ا', + 126465 => 'ب', + 126466 => 'ج', + 126467 => 'د', + 126469 => 'و', + 126470 => 'ز', + 126471 => 'ح', + 126472 => 'ط', + 126473 => 'ي', + 126474 => 'ك', + 126475 => 'ل', + 126476 => 'م', + 126477 => 'ن', + 126478 => 'س', + 126479 => 'ع', + 126480 => 'ف', + 126481 => 'ص', + 126482 => 'ق', + 126483 => 'ر', + 126484 => 'ش', + 126485 => 'ت', + 126486 => 'ث', + 126487 => 'خ', + 126488 => 'ذ', + 126489 => 'ض', + 126490 => 'ظ', + 126491 => 'غ', + 126492 => 'ٮ', + 126493 => 'ں', + 126494 => 'ڡ', + 126495 => 'ٯ', + 126497 => 'ب', + 126498 => 'ج', + 126500 => 'ه', + 126503 => 'ح', + 126505 => 'ي', + 126506 => 'ك', + 126507 => 'ل', + 126508 => 'م', + 126509 => 'ن', + 126510 => 'س', + 126511 => 'ع', + 126512 => 'ف', + 126513 => 'ص', + 126514 => 'ق', + 126516 => 'ش', + 126517 => 'ت', + 126518 => 'ث', + 126519 => 'خ', + 126521 => 'ض', + 126523 => 'غ', + 126530 => 'ج', + 126535 => 'ح', + 126537 => 'ي', + 126539 => 'ل', + 126541 => 'ن', + 126542 => 'س', + 126543 => 'ع', + 126545 => 'ص', + 126546 => 'ق', + 126548 => 'ش', + 126551 => 'خ', + 126553 => 'ض', + 126555 => 'غ', + 126557 => 'ں', + 126559 => 'ٯ', + 126561 => 'ب', + 126562 => 'ج', + 126564 => 'ه', + 126567 => 'ح', + 126568 => 'ط', + 126569 => 'ي', + 126570 => 'ك', + 126572 => 'م', + 126573 => 'ن', + 126574 => 'س', + 126575 => 'ع', + 126576 => 'ف', + 126577 => 'ص', + 126578 => 'ق', + 126580 => 'ش', + 126581 => 'ت', + 126582 => 'ث', + 126583 => 'خ', + 126585 => 'ض', + 126586 => 'ظ', + 126587 => 'غ', + 126588 => 'ٮ', + 126590 => 'ڡ', + 126592 => 'ا', + 126593 => 'ب', + 126594 => 'ج', + 126595 => 'د', + 126596 => 'ه', + 126597 => 'و', + 126598 => 'ز', + 126599 => 'ح', + 126600 => 'ط', + 126601 => 'ي', + 126603 => 'ل', + 126604 => 'م', + 126605 => 'ن', + 126606 => 'س', + 126607 => 'ع', + 126608 => 'ف', + 126609 => 'ص', + 126610 => 'ق', + 126611 => 'ر', + 126612 => 'ش', + 126613 => 'ت', + 126614 => 'ث', + 126615 => 'خ', + 126616 => 'ذ', + 126617 => 'ض', + 126618 => 'ظ', + 126619 => 'غ', + 126625 => 'ب', + 126626 => 'ج', + 126627 => 'د', + 126629 => 'و', + 126630 => 'ز', + 126631 => 'ح', + 126632 => 'ط', + 126633 => 'ي', + 126635 => 'ل', + 126636 => 'م', + 126637 => 'ن', + 126638 => 'س', + 126639 => 'ع', + 126640 => 'ف', + 126641 => 'ص', + 126642 => 'ق', + 126643 => 'ر', + 126644 => 'ش', + 126645 => 'ت', + 126646 => 'ث', + 126647 => 'خ', + 126648 => 'ذ', + 126649 => 'ض', + 126650 => 'ظ', + 126651 => 'غ', + 127274 => '〔s〕', + 127275 => 'c', + 127276 => 'r', + 127277 => 'cd', + 127278 => 'wz', + 127280 => 'a', + 127281 => 'b', + 127282 => 'c', + 127283 => 'd', + 127284 => 'e', + 127285 => 'f', + 127286 => 'g', + 127287 => 'h', + 127288 => 'i', + 127289 => 'j', + 127290 => 'k', + 127291 => 'l', + 127292 => 'm', + 127293 => 'n', + 127294 => 'o', + 127295 => 'p', + 127296 => 'q', + 127297 => 'r', + 127298 => 's', + 127299 => 't', + 127300 => 'u', + 127301 => 'v', + 127302 => 'w', + 127303 => 'x', + 127304 => 'y', + 127305 => 'z', + 127306 => 'hv', + 127307 => 'mv', + 127308 => 'sd', + 127309 => 'ss', + 127310 => 'ppv', + 127311 => 'wc', + 127338 => 'mc', + 127339 => 'md', + 127340 => 'mr', + 127376 => 'dj', + 127488 => 'ほか', + 127489 => 'ココ', + 127490 => 'サ', + 127504 => '手', + 127505 => '字', + 127506 => '双', + 127507 => 'デ', + 127508 => '二', + 127509 => '多', + 127510 => '解', + 127511 => '天', + 127512 => '交', + 127513 => '映', + 127514 => '無', + 127515 => '料', + 127516 => '前', + 127517 => '後', + 127518 => '再', + 127519 => '新', + 127520 => '初', + 127521 => '終', + 127522 => '生', + 127523 => '販', + 127524 => '声', + 127525 => '吹', + 127526 => '演', + 127527 => '投', + 127528 => '捕', + 127529 => '一', + 127530 => '三', + 127531 => '遊', + 127532 => '左', + 127533 => '中', + 127534 => '右', + 127535 => '指', + 127536 => '走', + 127537 => '打', + 127538 => '禁', + 127539 => '空', + 127540 => '合', + 127541 => '満', + 127542 => '有', + 127543 => '月', + 127544 => '申', + 127545 => '割', + 127546 => '営', + 127547 => '配', + 127552 => '〔本〕', + 127553 => '〔三〕', + 127554 => '〔二〕', + 127555 => '〔安〕', + 127556 => '〔点〕', + 127557 => '〔打〕', + 127558 => '〔盗〕', + 127559 => '〔勝〕', + 127560 => '〔敗〕', + 127568 => '得', + 127569 => '可', + 130032 => '0', + 130033 => '1', + 130034 => '2', + 130035 => '3', + 130036 => '4', + 130037 => '5', + 130038 => '6', + 130039 => '7', + 130040 => '8', + 130041 => '9', + 194560 => '丽', + 194561 => '丸', + 194562 => '乁', + 194563 => '𠄢', + 194564 => '你', + 194565 => '侮', + 194566 => '侻', + 194567 => '倂', + 194568 => '偺', + 194569 => '備', + 194570 => '僧', + 194571 => '像', + 194572 => '㒞', + 194573 => '𠘺', + 194574 => '免', + 194575 => '兔', + 194576 => '兤', + 194577 => '具', + 194578 => '𠔜', + 194579 => '㒹', + 194580 => '內', + 194581 => '再', + 194582 => '𠕋', + 194583 => '冗', + 194584 => '冤', + 194585 => '仌', + 194586 => '冬', + 194587 => '况', + 194588 => '𩇟', + 194589 => '凵', + 194590 => '刃', + 194591 => '㓟', + 194592 => '刻', + 194593 => '剆', + 194594 => '割', + 194595 => '剷', + 194596 => '㔕', + 194597 => '勇', + 194598 => '勉', + 194599 => '勤', + 194600 => '勺', + 194601 => '包', + 194602 => '匆', + 194603 => '北', + 194604 => '卉', + 194605 => '卑', + 194606 => '博', + 194607 => '即', + 194608 => '卽', + 194609 => '卿', + 194610 => '卿', + 194611 => '卿', + 194612 => '𠨬', + 194613 => '灰', + 194614 => '及', + 194615 => '叟', + 194616 => '𠭣', + 194617 => '叫', + 194618 => '叱', + 194619 => '吆', + 194620 => '咞', + 194621 => '吸', + 194622 => '呈', + 194623 => '周', + 194624 => '咢', + 194625 => '哶', + 194626 => '唐', + 194627 => '啓', + 194628 => '啣', + 194629 => '善', + 194630 => '善', + 194631 => '喙', + 194632 => '喫', + 194633 => '喳', + 194634 => '嗂', + 194635 => '圖', + 194636 => '嘆', + 194637 => '圗', + 194638 => '噑', + 194639 => '噴', + 194640 => '切', + 194641 => '壮', + 194642 => '城', + 194643 => '埴', + 194644 => '堍', + 194645 => '型', + 194646 => '堲', + 194647 => '報', + 194648 => '墬', + 194649 => '𡓤', + 194650 => '売', + 194651 => '壷', + 194652 => '夆', + 194653 => '多', + 194654 => '夢', + 194655 => '奢', + 194656 => '𡚨', + 194657 => '𡛪', + 194658 => '姬', + 194659 => '娛', + 194660 => '娧', + 194661 => '姘', + 194662 => '婦', + 194663 => '㛮', + 194665 => '嬈', + 194666 => '嬾', + 194667 => '嬾', + 194668 => '𡧈', + 194669 => '寃', + 194670 => '寘', + 194671 => '寧', + 194672 => '寳', + 194673 => '𡬘', + 194674 => '寿', + 194675 => '将', + 194677 => '尢', + 194678 => '㞁', + 194679 => '屠', + 194680 => '屮', + 194681 => '峀', + 194682 => '岍', + 194683 => '𡷤', + 194684 => '嵃', + 194685 => '𡷦', + 194686 => '嵮', + 194687 => '嵫', + 194688 => '嵼', + 194689 => '巡', + 194690 => '巢', + 194691 => '㠯', + 194692 => '巽', + 194693 => '帨', + 194694 => '帽', + 194695 => '幩', + 194696 => '㡢', + 194697 => '𢆃', + 194698 => '㡼', + 194699 => '庰', + 194700 => '庳', + 194701 => '庶', + 194702 => '廊', + 194703 => '𪎒', + 194704 => '廾', + 194705 => '𢌱', + 194706 => '𢌱', + 194707 => '舁', + 194708 => '弢', + 194709 => '弢', + 194710 => '㣇', + 194711 => '𣊸', + 194712 => '𦇚', + 194713 => '形', + 194714 => '彫', + 194715 => '㣣', + 194716 => '徚', + 194717 => '忍', + 194718 => '志', + 194719 => '忹', + 194720 => '悁', + 194721 => '㤺', + 194722 => '㤜', + 194723 => '悔', + 194724 => '𢛔', + 194725 => '惇', + 194726 => '慈', + 194727 => '慌', + 194728 => '慎', + 194729 => '慌', + 194730 => '慺', + 194731 => '憎', + 194732 => '憲', + 194733 => '憤', + 194734 => '憯', + 194735 => '懞', + 194736 => '懲', + 194737 => '懶', + 194738 => '成', + 194739 => '戛', + 194740 => '扝', + 194741 => '抱', + 194742 => '拔', + 194743 => '捐', + 194744 => '𢬌', + 194745 => '挽', + 194746 => '拼', + 194747 => '捨', + 194748 => '掃', + 194749 => '揤', + 194750 => '𢯱', + 194751 => '搢', + 194752 => '揅', + 194753 => '掩', + 194754 => '㨮', + 194755 => '摩', + 194756 => '摾', + 194757 => '撝', + 194758 => '摷', + 194759 => '㩬', + 194760 => '敏', + 194761 => '敬', + 194762 => '𣀊', + 194763 => '旣', + 194764 => '書', + 194765 => '晉', + 194766 => '㬙', + 194767 => '暑', + 194768 => '㬈', + 194769 => '㫤', + 194770 => '冒', + 194771 => '冕', + 194772 => '最', + 194773 => '暜', + 194774 => '肭', + 194775 => '䏙', + 194776 => '朗', + 194777 => '望', + 194778 => '朡', + 194779 => '杞', + 194780 => '杓', + 194781 => '𣏃', + 194782 => '㭉', + 194783 => '柺', + 194784 => '枅', + 194785 => '桒', + 194786 => '梅', + 194787 => '𣑭', + 194788 => '梎', + 194789 => '栟', + 194790 => '椔', + 194791 => '㮝', + 194792 => '楂', + 194793 => '榣', + 194794 => '槪', + 194795 => '檨', + 194796 => '𣚣', + 194797 => '櫛', + 194798 => '㰘', + 194799 => '次', + 194800 => '𣢧', + 194801 => '歔', + 194802 => '㱎', + 194803 => '歲', + 194804 => '殟', + 194805 => '殺', + 194806 => '殻', + 194807 => '𣪍', + 194808 => '𡴋', + 194809 => '𣫺', + 194810 => '汎', + 194811 => '𣲼', + 194812 => '沿', + 194813 => '泍', + 194814 => '汧', + 194815 => '洖', + 194816 => '派', + 194817 => '海', + 194818 => '流', + 194819 => '浩', + 194820 => '浸', + 194821 => '涅', + 194822 => '𣴞', + 194823 => '洴', + 194824 => '港', + 194825 => '湮', + 194826 => '㴳', + 194827 => '滋', + 194828 => '滇', + 194829 => '𣻑', + 194830 => '淹', + 194831 => '潮', + 194832 => '𣽞', + 194833 => '𣾎', + 194834 => '濆', + 194835 => '瀹', + 194836 => '瀞', + 194837 => '瀛', + 194838 => '㶖', + 194839 => '灊', + 194840 => '災', + 194841 => '灷', + 194842 => '炭', + 194843 => '𠔥', + 194844 => '煅', + 194845 => '𤉣', + 194846 => '熜', + 194848 => '爨', + 194849 => '爵', + 194850 => '牐', + 194851 => '𤘈', + 194852 => '犀', + 194853 => '犕', + 194854 => '𤜵', + 194855 => '𤠔', + 194856 => '獺', + 194857 => '王', + 194858 => '㺬', + 194859 => '玥', + 194860 => '㺸', + 194861 => '㺸', + 194862 => '瑇', + 194863 => '瑜', + 194864 => '瑱', + 194865 => '璅', + 194866 => '瓊', + 194867 => '㼛', + 194868 => '甤', + 194869 => '𤰶', + 194870 => '甾', + 194871 => '𤲒', + 194872 => '異', + 194873 => '𢆟', + 194874 => '瘐', + 194875 => '𤾡', + 194876 => '𤾸', + 194877 => '𥁄', + 194878 => '㿼', + 194879 => '䀈', + 194880 => '直', + 194881 => '𥃳', + 194882 => '𥃲', + 194883 => '𥄙', + 194884 => '𥄳', + 194885 => '眞', + 194886 => '真', + 194887 => '真', + 194888 => '睊', + 194889 => '䀹', + 194890 => '瞋', + 194891 => '䁆', + 194892 => '䂖', + 194893 => '𥐝', + 194894 => '硎', + 194895 => '碌', + 194896 => '磌', + 194897 => '䃣', + 194898 => '𥘦', + 194899 => '祖', + 194900 => '𥚚', + 194901 => '𥛅', + 194902 => '福', + 194903 => '秫', + 194904 => '䄯', + 194905 => '穀', + 194906 => '穊', + 194907 => '穏', + 194908 => '𥥼', + 194909 => '𥪧', + 194910 => '𥪧', + 194912 => '䈂', + 194913 => '𥮫', + 194914 => '篆', + 194915 => '築', + 194916 => '䈧', + 194917 => '𥲀', + 194918 => '糒', + 194919 => '䊠', + 194920 => '糨', + 194921 => '糣', + 194922 => '紀', + 194923 => '𥾆', + 194924 => '絣', + 194925 => '䌁', + 194926 => '緇', + 194927 => '縂', + 194928 => '繅', + 194929 => '䌴', + 194930 => '𦈨', + 194931 => '𦉇', + 194932 => '䍙', + 194933 => '𦋙', + 194934 => '罺', + 194935 => '𦌾', + 194936 => '羕', + 194937 => '翺', + 194938 => '者', + 194939 => '𦓚', + 194940 => '𦔣', + 194941 => '聠', + 194942 => '𦖨', + 194943 => '聰', + 194944 => '𣍟', + 194945 => '䏕', + 194946 => '育', + 194947 => '脃', + 194948 => '䐋', + 194949 => '脾', + 194950 => '媵', + 194951 => '𦞧', + 194952 => '𦞵', + 194953 => '𣎓', + 194954 => '𣎜', + 194955 => '舁', + 194956 => '舄', + 194957 => '辞', + 194958 => '䑫', + 194959 => '芑', + 194960 => '芋', + 194961 => '芝', + 194962 => '劳', + 194963 => '花', + 194964 => '芳', + 194965 => '芽', + 194966 => '苦', + 194967 => '𦬼', + 194968 => '若', + 194969 => '茝', + 194970 => '荣', + 194971 => '莭', + 194972 => '茣', + 194973 => '莽', + 194974 => '菧', + 194975 => '著', + 194976 => '荓', + 194977 => '菊', + 194978 => '菌', + 194979 => '菜', + 194980 => '𦰶', + 194981 => '𦵫', + 194982 => '𦳕', + 194983 => '䔫', + 194984 => '蓱', + 194985 => '蓳', + 194986 => '蔖', + 194987 => '𧏊', + 194988 => '蕤', + 194989 => '𦼬', + 194990 => '䕝', + 194991 => '䕡', + 194992 => '𦾱', + 194993 => '𧃒', + 194994 => '䕫', + 194995 => '虐', + 194996 => '虜', + 194997 => '虧', + 194998 => '虩', + 194999 => '蚩', + 195000 => '蚈', + 195001 => '蜎', + 195002 => '蛢', + 195003 => '蝹', + 195004 => '蜨', + 195005 => '蝫', + 195006 => '螆', + 195008 => '蟡', + 195009 => '蠁', + 195010 => '䗹', + 195011 => '衠', + 195012 => '衣', + 195013 => '𧙧', + 195014 => '裗', + 195015 => '裞', + 195016 => '䘵', + 195017 => '裺', + 195018 => '㒻', + 195019 => '𧢮', + 195020 => '𧥦', + 195021 => '䚾', + 195022 => '䛇', + 195023 => '誠', + 195024 => '諭', + 195025 => '變', + 195026 => '豕', + 195027 => '𧲨', + 195028 => '貫', + 195029 => '賁', + 195030 => '贛', + 195031 => '起', + 195032 => '𧼯', + 195033 => '𠠄', + 195034 => '跋', + 195035 => '趼', + 195036 => '跰', + 195037 => '𠣞', + 195038 => '軔', + 195039 => '輸', + 195040 => '𨗒', + 195041 => '𨗭', + 195042 => '邔', + 195043 => '郱', + 195044 => '鄑', + 195045 => '𨜮', + 195046 => '鄛', + 195047 => '鈸', + 195048 => '鋗', + 195049 => '鋘', + 195050 => '鉼', + 195051 => '鏹', + 195052 => '鐕', + 195053 => '𨯺', + 195054 => '開', + 195055 => '䦕', + 195056 => '閷', + 195057 => '𨵷', + 195058 => '䧦', + 195059 => '雃', + 195060 => '嶲', + 195061 => '霣', + 195062 => '𩅅', + 195063 => '𩈚', + 195064 => '䩮', + 195065 => '䩶', + 195066 => '韠', + 195067 => '𩐊', + 195068 => '䪲', + 195069 => '𩒖', + 195070 => '頋', + 195071 => '頋', + 195072 => '頩', + 195073 => '𩖶', + 195074 => '飢', + 195075 => '䬳', + 195076 => '餩', + 195077 => '馧', + 195078 => '駂', + 195079 => '駾', + 195080 => '䯎', + 195081 => '𩬰', + 195082 => '鬒', + 195083 => '鱀', + 195084 => '鳽', + 195085 => '䳎', + 195086 => '䳭', + 195087 => '鵧', + 195088 => '𪃎', + 195089 => '䳸', + 195090 => '𪄅', + 195091 => '𪈎', + 195092 => '𪊑', + 195093 => '麻', + 195094 => '䵖', + 195095 => '黹', + 195096 => '黾', + 195097 => '鼅', + 195098 => '鼏', + 195099 => '鼖', + 195100 => '鼻', + 195101 => '𪘀', +); diff --git a/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/virama.php b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/virama.php new file mode 100644 index 000000000..1958e37ed --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/Resources/unidata/virama.php @@ -0,0 +1,65 @@ + 9, + 2509 => 9, + 2637 => 9, + 2765 => 9, + 2893 => 9, + 3021 => 9, + 3149 => 9, + 3277 => 9, + 3387 => 9, + 3388 => 9, + 3405 => 9, + 3530 => 9, + 3642 => 9, + 3770 => 9, + 3972 => 9, + 4153 => 9, + 4154 => 9, + 5908 => 9, + 5940 => 9, + 6098 => 9, + 6752 => 9, + 6980 => 9, + 7082 => 9, + 7083 => 9, + 7154 => 9, + 7155 => 9, + 11647 => 9, + 43014 => 9, + 43052 => 9, + 43204 => 9, + 43347 => 9, + 43456 => 9, + 43766 => 9, + 44013 => 9, + 68159 => 9, + 69702 => 9, + 69759 => 9, + 69817 => 9, + 69939 => 9, + 69940 => 9, + 70080 => 9, + 70197 => 9, + 70378 => 9, + 70477 => 9, + 70722 => 9, + 70850 => 9, + 71103 => 9, + 71231 => 9, + 71350 => 9, + 71467 => 9, + 71737 => 9, + 71997 => 9, + 71998 => 9, + 72160 => 9, + 72244 => 9, + 72263 => 9, + 72345 => 9, + 72767 => 9, + 73028 => 9, + 73029 => 9, + 73111 => 9, +); diff --git a/tools/mailer/symfony/polyfill-intl-idn/bootstrap.php b/tools/mailer/symfony/polyfill-intl-idn/bootstrap.php new file mode 100644 index 000000000..57c78356c --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/bootstrap.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Intl\Idn as p; + +if (extension_loaded('intl')) { + return; +} + +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__.'/bootstrap80.php'; +} + +if (!defined('U_IDNA_PROHIBITED_ERROR')) { + define('U_IDNA_PROHIBITED_ERROR', 66560); +} +if (!defined('U_IDNA_ERROR_START')) { + define('U_IDNA_ERROR_START', 66560); +} +if (!defined('U_IDNA_UNASSIGNED_ERROR')) { + define('U_IDNA_UNASSIGNED_ERROR', 66561); +} +if (!defined('U_IDNA_CHECK_BIDI_ERROR')) { + define('U_IDNA_CHECK_BIDI_ERROR', 66562); +} +if (!defined('U_IDNA_STD3_ASCII_RULES_ERROR')) { + define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563); +} +if (!defined('U_IDNA_ACE_PREFIX_ERROR')) { + define('U_IDNA_ACE_PREFIX_ERROR', 66564); +} +if (!defined('U_IDNA_VERIFICATION_ERROR')) { + define('U_IDNA_VERIFICATION_ERROR', 66565); +} +if (!defined('U_IDNA_LABEL_TOO_LONG_ERROR')) { + define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566); +} +if (!defined('U_IDNA_ZERO_LENGTH_LABEL_ERROR')) { + define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567); +} +if (!defined('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR')) { + define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568); +} +if (!defined('U_IDNA_ERROR_LIMIT')) { + define('U_IDNA_ERROR_LIMIT', 66569); +} +if (!defined('U_STRINGPREP_PROHIBITED_ERROR')) { + define('U_STRINGPREP_PROHIBITED_ERROR', 66560); +} +if (!defined('U_STRINGPREP_UNASSIGNED_ERROR')) { + define('U_STRINGPREP_UNASSIGNED_ERROR', 66561); +} +if (!defined('U_STRINGPREP_CHECK_BIDI_ERROR')) { + define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562); +} +if (!defined('IDNA_DEFAULT')) { + define('IDNA_DEFAULT', 0); +} +if (!defined('IDNA_ALLOW_UNASSIGNED')) { + define('IDNA_ALLOW_UNASSIGNED', 1); +} +if (!defined('IDNA_USE_STD3_RULES')) { + define('IDNA_USE_STD3_RULES', 2); +} +if (!defined('IDNA_CHECK_BIDI')) { + define('IDNA_CHECK_BIDI', 4); +} +if (!defined('IDNA_CHECK_CONTEXTJ')) { + define('IDNA_CHECK_CONTEXTJ', 8); +} +if (!defined('IDNA_NONTRANSITIONAL_TO_ASCII')) { + define('IDNA_NONTRANSITIONAL_TO_ASCII', 16); +} +if (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) { + define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32); +} +if (!defined('INTL_IDNA_VARIANT_2003')) { + define('INTL_IDNA_VARIANT_2003', 0); +} +if (!defined('INTL_IDNA_VARIANT_UTS46')) { + define('INTL_IDNA_VARIANT_UTS46', 1); +} +if (!defined('IDNA_ERROR_EMPTY_LABEL')) { + define('IDNA_ERROR_EMPTY_LABEL', 1); +} +if (!defined('IDNA_ERROR_LABEL_TOO_LONG')) { + define('IDNA_ERROR_LABEL_TOO_LONG', 2); +} +if (!defined('IDNA_ERROR_DOMAIN_NAME_TOO_LONG')) { + define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4); +} +if (!defined('IDNA_ERROR_LEADING_HYPHEN')) { + define('IDNA_ERROR_LEADING_HYPHEN', 8); +} +if (!defined('IDNA_ERROR_TRAILING_HYPHEN')) { + define('IDNA_ERROR_TRAILING_HYPHEN', 16); +} +if (!defined('IDNA_ERROR_HYPHEN_3_4')) { + define('IDNA_ERROR_HYPHEN_3_4', 32); +} +if (!defined('IDNA_ERROR_LEADING_COMBINING_MARK')) { + define('IDNA_ERROR_LEADING_COMBINING_MARK', 64); +} +if (!defined('IDNA_ERROR_DISALLOWED')) { + define('IDNA_ERROR_DISALLOWED', 128); +} +if (!defined('IDNA_ERROR_PUNYCODE')) { + define('IDNA_ERROR_PUNYCODE', 256); +} +if (!defined('IDNA_ERROR_LABEL_HAS_DOT')) { + define('IDNA_ERROR_LABEL_HAS_DOT', 512); +} +if (!defined('IDNA_ERROR_INVALID_ACE_LABEL')) { + define('IDNA_ERROR_INVALID_ACE_LABEL', 1024); +} +if (!defined('IDNA_ERROR_BIDI')) { + define('IDNA_ERROR_BIDI', 2048); +} +if (!defined('IDNA_ERROR_CONTEXTJ')) { + define('IDNA_ERROR_CONTEXTJ', 4096); +} + +if (\PHP_VERSION_ID < 70400) { + if (!function_exists('idn_to_ascii')) { + function idn_to_ascii($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_2003, &$idna_info = null) { return p\Idn::idn_to_ascii($domain, $flags, $variant, $idna_info); } + } + if (!function_exists('idn_to_utf8')) { + function idn_to_utf8($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_2003, &$idna_info = null) { return p\Idn::idn_to_utf8($domain, $flags, $variant, $idna_info); } + } +} else { + if (!function_exists('idn_to_ascii')) { + function idn_to_ascii($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_UTS46, &$idna_info = null) { return p\Idn::idn_to_ascii($domain, $flags, $variant, $idna_info); } + } + if (!function_exists('idn_to_utf8')) { + function idn_to_utf8($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_UTS46, &$idna_info = null) { return p\Idn::idn_to_utf8($domain, $flags, $variant, $idna_info); } + } +} diff --git a/tools/mailer/symfony/polyfill-intl-idn/bootstrap80.php b/tools/mailer/symfony/polyfill-intl-idn/bootstrap80.php new file mode 100644 index 000000000..a62c2d69b --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/bootstrap80.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Intl\Idn as p; + +if (!defined('U_IDNA_PROHIBITED_ERROR')) { + define('U_IDNA_PROHIBITED_ERROR', 66560); +} +if (!defined('U_IDNA_ERROR_START')) { + define('U_IDNA_ERROR_START', 66560); +} +if (!defined('U_IDNA_UNASSIGNED_ERROR')) { + define('U_IDNA_UNASSIGNED_ERROR', 66561); +} +if (!defined('U_IDNA_CHECK_BIDI_ERROR')) { + define('U_IDNA_CHECK_BIDI_ERROR', 66562); +} +if (!defined('U_IDNA_STD3_ASCII_RULES_ERROR')) { + define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563); +} +if (!defined('U_IDNA_ACE_PREFIX_ERROR')) { + define('U_IDNA_ACE_PREFIX_ERROR', 66564); +} +if (!defined('U_IDNA_VERIFICATION_ERROR')) { + define('U_IDNA_VERIFICATION_ERROR', 66565); +} +if (!defined('U_IDNA_LABEL_TOO_LONG_ERROR')) { + define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566); +} +if (!defined('U_IDNA_ZERO_LENGTH_LABEL_ERROR')) { + define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567); +} +if (!defined('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR')) { + define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568); +} +if (!defined('U_IDNA_ERROR_LIMIT')) { + define('U_IDNA_ERROR_LIMIT', 66569); +} +if (!defined('U_STRINGPREP_PROHIBITED_ERROR')) { + define('U_STRINGPREP_PROHIBITED_ERROR', 66560); +} +if (!defined('U_STRINGPREP_UNASSIGNED_ERROR')) { + define('U_STRINGPREP_UNASSIGNED_ERROR', 66561); +} +if (!defined('U_STRINGPREP_CHECK_BIDI_ERROR')) { + define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562); +} +if (!defined('IDNA_DEFAULT')) { + define('IDNA_DEFAULT', 0); +} +if (!defined('IDNA_ALLOW_UNASSIGNED')) { + define('IDNA_ALLOW_UNASSIGNED', 1); +} +if (!defined('IDNA_USE_STD3_RULES')) { + define('IDNA_USE_STD3_RULES', 2); +} +if (!defined('IDNA_CHECK_BIDI')) { + define('IDNA_CHECK_BIDI', 4); +} +if (!defined('IDNA_CHECK_CONTEXTJ')) { + define('IDNA_CHECK_CONTEXTJ', 8); +} +if (!defined('IDNA_NONTRANSITIONAL_TO_ASCII')) { + define('IDNA_NONTRANSITIONAL_TO_ASCII', 16); +} +if (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) { + define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32); +} +if (!defined('INTL_IDNA_VARIANT_UTS46')) { + define('INTL_IDNA_VARIANT_UTS46', 1); +} +if (!defined('IDNA_ERROR_EMPTY_LABEL')) { + define('IDNA_ERROR_EMPTY_LABEL', 1); +} +if (!defined('IDNA_ERROR_LABEL_TOO_LONG')) { + define('IDNA_ERROR_LABEL_TOO_LONG', 2); +} +if (!defined('IDNA_ERROR_DOMAIN_NAME_TOO_LONG')) { + define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4); +} +if (!defined('IDNA_ERROR_LEADING_HYPHEN')) { + define('IDNA_ERROR_LEADING_HYPHEN', 8); +} +if (!defined('IDNA_ERROR_TRAILING_HYPHEN')) { + define('IDNA_ERROR_TRAILING_HYPHEN', 16); +} +if (!defined('IDNA_ERROR_HYPHEN_3_4')) { + define('IDNA_ERROR_HYPHEN_3_4', 32); +} +if (!defined('IDNA_ERROR_LEADING_COMBINING_MARK')) { + define('IDNA_ERROR_LEADING_COMBINING_MARK', 64); +} +if (!defined('IDNA_ERROR_DISALLOWED')) { + define('IDNA_ERROR_DISALLOWED', 128); +} +if (!defined('IDNA_ERROR_PUNYCODE')) { + define('IDNA_ERROR_PUNYCODE', 256); +} +if (!defined('IDNA_ERROR_LABEL_HAS_DOT')) { + define('IDNA_ERROR_LABEL_HAS_DOT', 512); +} +if (!defined('IDNA_ERROR_INVALID_ACE_LABEL')) { + define('IDNA_ERROR_INVALID_ACE_LABEL', 1024); +} +if (!defined('IDNA_ERROR_BIDI')) { + define('IDNA_ERROR_BIDI', 2048); +} +if (!defined('IDNA_ERROR_CONTEXTJ')) { + define('IDNA_ERROR_CONTEXTJ', 4096); +} + +if (!function_exists('idn_to_ascii')) { + function idn_to_ascii(?string $domain, ?int $flags = IDNA_DEFAULT, ?int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\Idn::idn_to_ascii((string) $domain, (int) $flags, (int) $variant, $idna_info); } +} +if (!function_exists('idn_to_utf8')) { + function idn_to_utf8(?string $domain, ?int $flags = IDNA_DEFAULT, ?int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\Idn::idn_to_utf8((string) $domain, (int) $flags, (int) $variant, $idna_info); } +} diff --git a/tools/mailer/symfony/polyfill-intl-idn/composer.json b/tools/mailer/symfony/polyfill-intl-idn/composer.json new file mode 100644 index 000000000..760debcd2 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-idn/composer.json @@ -0,0 +1,40 @@ +{ + "name": "symfony/polyfill-intl-idn", + "type": "library", + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "keywords": ["polyfill", "shim", "compatibility", "portable", "intl", "idn"], + "homepage": "https://symfony.com", + "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" + } + ], + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Intl\\Idn\\": "" }, + "files": [ "bootstrap.php" ] + }, + "suggest": { + "ext-intl": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/tools/mailer/symfony/polyfill-intl-normalizer/LICENSE b/tools/mailer/symfony/polyfill-intl-normalizer/LICENSE new file mode 100644 index 000000000..6e3afce69 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-normalizer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-present Fabien Potencier + +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/tools/mailer/symfony/polyfill-intl-normalizer/Normalizer.php b/tools/mailer/symfony/polyfill-intl-normalizer/Normalizer.php new file mode 100644 index 000000000..81704ab37 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-normalizer/Normalizer.php @@ -0,0 +1,310 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Intl\Normalizer; + +/** + * Normalizer is a PHP fallback implementation of the Normalizer class provided by the intl extension. + * + * It has been validated with Unicode 6.3 Normalization Conformance Test. + * See http://www.unicode.org/reports/tr15/ for detailed info about Unicode normalizations. + * + * @author Nicolas Grekas + * + * @internal + */ +class Normalizer +{ + public const FORM_D = \Normalizer::FORM_D; + public const FORM_KD = \Normalizer::FORM_KD; + public const FORM_C = \Normalizer::FORM_C; + public const FORM_KC = \Normalizer::FORM_KC; + public const NFD = \Normalizer::NFD; + public const NFKD = \Normalizer::NFKD; + public const NFC = \Normalizer::NFC; + public const NFKC = \Normalizer::NFKC; + + private static $C; + private static $D; + private static $KD; + private static $cC; + private static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; + private static $ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; + + public static function isNormalized(string $s, int $form = self::FORM_C) + { + if (!\in_array($form, [self::NFD, self::NFKD, self::NFC, self::NFKC])) { + return false; + } + if (!isset($s[strspn($s, self::$ASCII)])) { + return true; + } + if (self::NFC == $form && preg_match('//u', $s) && !preg_match('/[^\x00-\x{2FF}]/u', $s)) { + return true; + } + + return self::normalize($s, $form) === $s; + } + + public static function normalize(string $s, int $form = self::FORM_C) + { + if (!preg_match('//u', $s)) { + return false; + } + + switch ($form) { + case self::NFC: $C = true; $K = false; break; + case self::NFD: $C = false; $K = false; break; + case self::NFKC: $C = true; $K = true; break; + case self::NFKD: $C = false; $K = true; break; + default: + if (\defined('Normalizer::NONE') && \Normalizer::NONE == $form) { + return $s; + } + + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form'); + } + + if ('' === $s) { + return ''; + } + + if ($K && null === self::$KD) { + self::$KD = self::getData('compatibilityDecomposition'); + } + + if (null === self::$D) { + self::$D = self::getData('canonicalDecomposition'); + self::$cC = self::getData('combiningClass'); + } + + if (null !== $mbEncoding = (2 /* MB_OVERLOAD_STRING */ & (int) \ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) { + mb_internal_encoding('8bit'); + } + + $r = self::decompose($s, $K); + + if ($C) { + if (null === self::$C) { + self::$C = self::getData('canonicalComposition'); + } + + $r = self::recompose($r); + } + if (null !== $mbEncoding) { + mb_internal_encoding($mbEncoding); + } + + return $r; + } + + private static function recompose($s) + { + $ASCII = self::$ASCII; + $compMap = self::$C; + $combClass = self::$cC; + $ulenMask = self::$ulenMask; + + $result = $tail = ''; + + $i = $s[0] < "\x80" ? 1 : $ulenMask[$s[0] & "\xF0"]; + $len = \strlen($s); + + $lastUchr = substr($s, 0, $i); + $lastUcls = isset($combClass[$lastUchr]) ? 256 : 0; + + while ($i < $len) { + if ($s[$i] < "\x80") { + // ASCII chars + + if ($tail) { + $lastUchr .= $tail; + $tail = ''; + } + + if ($j = strspn($s, $ASCII, $i + 1)) { + $lastUchr .= substr($s, $i, $j); + $i += $j; + } + + $result .= $lastUchr; + $lastUchr = $s[$i]; + $lastUcls = 0; + ++$i; + continue; + } + + $ulen = $ulenMask[$s[$i] & "\xF0"]; + $uchr = substr($s, $i, $ulen); + + if ($lastUchr < "\xE1\x84\x80" || "\xE1\x84\x92" < $lastUchr + || $uchr < "\xE1\x85\xA1" || "\xE1\x85\xB5" < $uchr + || $lastUcls) { + // Table lookup and combining chars composition + + $ucls = $combClass[$uchr] ?? 0; + + if (isset($compMap[$lastUchr.$uchr]) && (!$lastUcls || $lastUcls < $ucls)) { + $lastUchr = $compMap[$lastUchr.$uchr]; + } elseif ($lastUcls = $ucls) { + $tail .= $uchr; + } else { + if ($tail) { + $lastUchr .= $tail; + $tail = ''; + } + + $result .= $lastUchr; + $lastUchr = $uchr; + } + } else { + // Hangul chars + + $L = \ord($lastUchr[2]) - 0x80; + $V = \ord($uchr[2]) - 0xA1; + $T = 0; + + $uchr = substr($s, $i + $ulen, 3); + + if ("\xE1\x86\xA7" <= $uchr && $uchr <= "\xE1\x87\x82") { + $T = \ord($uchr[2]) - 0xA7; + 0 > $T && $T += 0x40; + $ulen += 3; + } + + $L = 0xAC00 + ($L * 21 + $V) * 28 + $T; + $lastUchr = \chr(0xE0 | $L >> 12).\chr(0x80 | $L >> 6 & 0x3F).\chr(0x80 | $L & 0x3F); + } + + $i += $ulen; + } + + return $result.$lastUchr.$tail; + } + + private static function decompose($s, $c) + { + $result = ''; + + $ASCII = self::$ASCII; + $decompMap = self::$D; + $combClass = self::$cC; + $ulenMask = self::$ulenMask; + if ($c) { + $compatMap = self::$KD; + } + + $c = []; + $i = 0; + $len = \strlen($s); + + while ($i < $len) { + if ($s[$i] < "\x80") { + // ASCII chars + + if ($c) { + ksort($c); + $result .= implode('', $c); + $c = []; + } + + $j = 1 + strspn($s, $ASCII, $i + 1); + $result .= substr($s, $i, $j); + $i += $j; + continue; + } + + $ulen = $ulenMask[$s[$i] & "\xF0"]; + $uchr = substr($s, $i, $ulen); + $i += $ulen; + + if ($uchr < "\xEA\xB0\x80" || "\xED\x9E\xA3" < $uchr) { + // Table lookup + + if ($uchr !== $j = $compatMap[$uchr] ?? ($decompMap[$uchr] ?? $uchr)) { + $uchr = $j; + + $j = \strlen($uchr); + $ulen = $uchr[0] < "\x80" ? 1 : $ulenMask[$uchr[0] & "\xF0"]; + + if ($ulen != $j) { + // Put trailing chars in $s + + $j -= $ulen; + $i -= $j; + + if (0 > $i) { + $s = str_repeat(' ', -$i).$s; + $len -= $i; + $i = 0; + } + + while ($j--) { + $s[$i + $j] = $uchr[$ulen + $j]; + } + + $uchr = substr($uchr, 0, $ulen); + } + } + if (isset($combClass[$uchr])) { + // Combining chars, for sorting + + if (!isset($c[$combClass[$uchr]])) { + $c[$combClass[$uchr]] = ''; + } + $c[$combClass[$uchr]] .= $uchr; + continue; + } + } else { + // Hangul chars + + $uchr = unpack('C*', $uchr); + $j = (($uchr[1] - 224) << 12) + (($uchr[2] - 128) << 6) + $uchr[3] - 0xAC80; + + $uchr = "\xE1\x84".\chr(0x80 + (int) ($j / 588)) + ."\xE1\x85".\chr(0xA1 + (int) (($j % 588) / 28)); + + if ($j %= 28) { + $uchr .= $j < 25 + ? ("\xE1\x86".\chr(0xA7 + $j)) + : ("\xE1\x87".\chr(0x67 + $j)); + } + } + if ($c) { + ksort($c); + $result .= implode('', $c); + $c = []; + } + + $result .= $uchr; + } + + if ($c) { + ksort($c); + $result .= implode('', $c); + } + + return $result; + } + + private static function getData($file) + { + if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) { + return require $file; + } + + return false; + } +} diff --git a/tools/mailer/symfony/polyfill-intl-normalizer/README.md b/tools/mailer/symfony/polyfill-intl-normalizer/README.md new file mode 100644 index 000000000..b9b762e85 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-normalizer/README.md @@ -0,0 +1,14 @@ +Symfony Polyfill / Intl: Normalizer +=================================== + +This component provides a fallback implementation for the +[`Normalizer`](https://php.net/Normalizer) class provided +by the [Intl](https://php.net/intl) extension. + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/tools/mailer/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php b/tools/mailer/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php new file mode 100644 index 000000000..0fdfc890a --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php @@ -0,0 +1,17 @@ + 'À', + 'Á' => 'Á', + 'Â' => 'Â', + 'Ã' => 'Ã', + 'Ä' => 'Ä', + 'Å' => 'Å', + 'Ç' => 'Ç', + 'È' => 'È', + 'É' => 'É', + 'Ê' => 'Ê', + 'Ë' => 'Ë', + 'Ì' => 'Ì', + 'Í' => 'Í', + 'Î' => 'Î', + 'Ï' => 'Ï', + 'Ñ' => 'Ñ', + 'Ò' => 'Ò', + 'Ó' => 'Ó', + 'Ô' => 'Ô', + 'Õ' => 'Õ', + 'Ö' => 'Ö', + 'Ù' => 'Ù', + 'Ú' => 'Ú', + 'Û' => 'Û', + 'Ü' => 'Ü', + 'Ý' => 'Ý', + 'à' => 'à', + 'á' => 'á', + 'â' => 'â', + 'ã' => 'ã', + 'ä' => 'ä', + 'å' => 'å', + 'ç' => 'ç', + 'è' => 'è', + 'é' => 'é', + 'ê' => 'ê', + 'ë' => 'ë', + 'ì' => 'ì', + 'í' => 'í', + 'î' => 'î', + 'ï' => 'ï', + 'ñ' => 'ñ', + 'ò' => 'ò', + 'ó' => 'ó', + 'ô' => 'ô', + 'õ' => 'õ', + 'ö' => 'ö', + 'ù' => 'ù', + 'ú' => 'ú', + 'û' => 'û', + 'ü' => 'ü', + 'ý' => 'ý', + 'ÿ' => 'ÿ', + 'Ā' => 'Ā', + 'ā' => 'ā', + 'Ă' => 'Ă', + 'ă' => 'ă', + 'Ą' => 'Ą', + 'ą' => 'ą', + 'Ć' => 'Ć', + 'ć' => 'ć', + 'Ĉ' => 'Ĉ', + 'ĉ' => 'ĉ', + 'Ċ' => 'Ċ', + 'ċ' => 'ċ', + 'Č' => 'Č', + 'č' => 'č', + 'Ď' => 'Ď', + 'ď' => 'ď', + 'Ē' => 'Ē', + 'ē' => 'ē', + 'Ĕ' => 'Ĕ', + 'ĕ' => 'ĕ', + 'Ė' => 'Ė', + 'ė' => 'ė', + 'Ę' => 'Ę', + 'ę' => 'ę', + 'Ě' => 'Ě', + 'ě' => 'ě', + 'Ĝ' => 'Ĝ', + 'ĝ' => 'ĝ', + 'Ğ' => 'Ğ', + 'ğ' => 'ğ', + 'Ġ' => 'Ġ', + 'ġ' => 'ġ', + 'Ģ' => 'Ģ', + 'ģ' => 'ģ', + 'Ĥ' => 'Ĥ', + 'ĥ' => 'ĥ', + 'Ĩ' => 'Ĩ', + 'ĩ' => 'ĩ', + 'Ī' => 'Ī', + 'ī' => 'ī', + 'Ĭ' => 'Ĭ', + 'ĭ' => 'ĭ', + 'Į' => 'Į', + 'į' => 'į', + 'İ' => 'İ', + 'Ĵ' => 'Ĵ', + 'ĵ' => 'ĵ', + 'Ķ' => 'Ķ', + 'ķ' => 'ķ', + 'Ĺ' => 'Ĺ', + 'ĺ' => 'ĺ', + 'Ļ' => 'Ļ', + 'ļ' => 'ļ', + 'Ľ' => 'Ľ', + 'ľ' => 'ľ', + 'Ń' => 'Ń', + 'ń' => 'ń', + 'Ņ' => 'Ņ', + 'ņ' => 'ņ', + 'Ň' => 'Ň', + 'ň' => 'ň', + 'Ō' => 'Ō', + 'ō' => 'ō', + 'Ŏ' => 'Ŏ', + 'ŏ' => 'ŏ', + 'Ő' => 'Ő', + 'ő' => 'ő', + 'Ŕ' => 'Ŕ', + 'ŕ' => 'ŕ', + 'Ŗ' => 'Ŗ', + 'ŗ' => 'ŗ', + 'Ř' => 'Ř', + 'ř' => 'ř', + 'Ś' => 'Ś', + 'ś' => 'ś', + 'Ŝ' => 'Ŝ', + 'ŝ' => 'ŝ', + 'Ş' => 'Ş', + 'ş' => 'ş', + 'Š' => 'Š', + 'š' => 'š', + 'Ţ' => 'Ţ', + 'ţ' => 'ţ', + 'Ť' => 'Ť', + 'ť' => 'ť', + 'Ũ' => 'Ũ', + 'ũ' => 'ũ', + 'Ū' => 'Ū', + 'ū' => 'ū', + 'Ŭ' => 'Ŭ', + 'ŭ' => 'ŭ', + 'Ů' => 'Ů', + 'ů' => 'ů', + 'Ű' => 'Ű', + 'ű' => 'ű', + 'Ų' => 'Ų', + 'ų' => 'ų', + 'Ŵ' => 'Ŵ', + 'ŵ' => 'ŵ', + 'Ŷ' => 'Ŷ', + 'ŷ' => 'ŷ', + 'Ÿ' => 'Ÿ', + 'Ź' => 'Ź', + 'ź' => 'ź', + 'Ż' => 'Ż', + 'ż' => 'ż', + 'Ž' => 'Ž', + 'ž' => 'ž', + 'Ơ' => 'Ơ', + 'ơ' => 'ơ', + 'Ư' => 'Ư', + 'ư' => 'ư', + 'Ǎ' => 'Ǎ', + 'ǎ' => 'ǎ', + 'Ǐ' => 'Ǐ', + 'ǐ' => 'ǐ', + 'Ǒ' => 'Ǒ', + 'ǒ' => 'ǒ', + 'Ǔ' => 'Ǔ', + 'ǔ' => 'ǔ', + 'Ǖ' => 'Ǖ', + 'ǖ' => 'ǖ', + 'Ǘ' => 'Ǘ', + 'ǘ' => 'ǘ', + 'Ǚ' => 'Ǚ', + 'ǚ' => 'ǚ', + 'Ǜ' => 'Ǜ', + 'ǜ' => 'ǜ', + 'Ǟ' => 'Ǟ', + 'ǟ' => 'ǟ', + 'Ǡ' => 'Ǡ', + 'ǡ' => 'ǡ', + 'Ǣ' => 'Ǣ', + 'ǣ' => 'ǣ', + 'Ǧ' => 'Ǧ', + 'ǧ' => 'ǧ', + 'Ǩ' => 'Ǩ', + 'ǩ' => 'ǩ', + 'Ǫ' => 'Ǫ', + 'ǫ' => 'ǫ', + 'Ǭ' => 'Ǭ', + 'ǭ' => 'ǭ', + 'Ǯ' => 'Ǯ', + 'ǯ' => 'ǯ', + 'ǰ' => 'ǰ', + 'Ǵ' => 'Ǵ', + 'ǵ' => 'ǵ', + 'Ǹ' => 'Ǹ', + 'ǹ' => 'ǹ', + 'Ǻ' => 'Ǻ', + 'ǻ' => 'ǻ', + 'Ǽ' => 'Ǽ', + 'ǽ' => 'ǽ', + 'Ǿ' => 'Ǿ', + 'ǿ' => 'ǿ', + 'Ȁ' => 'Ȁ', + 'ȁ' => 'ȁ', + 'Ȃ' => 'Ȃ', + 'ȃ' => 'ȃ', + 'Ȅ' => 'Ȅ', + 'ȅ' => 'ȅ', + 'Ȇ' => 'Ȇ', + 'ȇ' => 'ȇ', + 'Ȉ' => 'Ȉ', + 'ȉ' => 'ȉ', + 'Ȋ' => 'Ȋ', + 'ȋ' => 'ȋ', + 'Ȍ' => 'Ȍ', + 'ȍ' => 'ȍ', + 'Ȏ' => 'Ȏ', + 'ȏ' => 'ȏ', + 'Ȑ' => 'Ȑ', + 'ȑ' => 'ȑ', + 'Ȓ' => 'Ȓ', + 'ȓ' => 'ȓ', + 'Ȕ' => 'Ȕ', + 'ȕ' => 'ȕ', + 'Ȗ' => 'Ȗ', + 'ȗ' => 'ȗ', + 'Ș' => 'Ș', + 'ș' => 'ș', + 'Ț' => 'Ț', + 'ț' => 'ț', + 'Ȟ' => 'Ȟ', + 'ȟ' => 'ȟ', + 'Ȧ' => 'Ȧ', + 'ȧ' => 'ȧ', + 'Ȩ' => 'Ȩ', + 'ȩ' => 'ȩ', + 'Ȫ' => 'Ȫ', + 'ȫ' => 'ȫ', + 'Ȭ' => 'Ȭ', + 'ȭ' => 'ȭ', + 'Ȯ' => 'Ȯ', + 'ȯ' => 'ȯ', + 'Ȱ' => 'Ȱ', + 'ȱ' => 'ȱ', + 'Ȳ' => 'Ȳ', + 'ȳ' => 'ȳ', + '΅' => '΅', + 'Ά' => 'Ά', + 'Έ' => 'Έ', + 'Ή' => 'Ή', + 'Ί' => 'Ί', + 'Ό' => 'Ό', + 'Ύ' => 'Ύ', + 'Ώ' => 'Ώ', + 'ΐ' => 'ΐ', + 'Ϊ' => 'Ϊ', + 'Ϋ' => 'Ϋ', + 'ά' => 'ά', + 'έ' => 'έ', + 'ή' => 'ή', + 'ί' => 'ί', + 'ΰ' => 'ΰ', + 'ϊ' => 'ϊ', + 'ϋ' => 'ϋ', + 'ό' => 'ό', + 'ύ' => 'ύ', + 'ώ' => 'ώ', + 'ϓ' => 'ϓ', + 'ϔ' => 'ϔ', + 'Ѐ' => 'Ѐ', + 'Ё' => 'Ё', + 'Ѓ' => 'Ѓ', + 'Ї' => 'Ї', + 'Ќ' => 'Ќ', + 'Ѝ' => 'Ѝ', + 'Ў' => 'Ў', + 'Й' => 'Й', + 'й' => 'й', + 'ѐ' => 'ѐ', + 'ё' => 'ё', + 'ѓ' => 'ѓ', + 'ї' => 'ї', + 'ќ' => 'ќ', + 'ѝ' => 'ѝ', + 'ў' => 'ў', + 'Ѷ' => 'Ѷ', + 'ѷ' => 'ѷ', + 'Ӂ' => 'Ӂ', + 'ӂ' => 'ӂ', + 'Ӑ' => 'Ӑ', + 'ӑ' => 'ӑ', + 'Ӓ' => 'Ӓ', + 'ӓ' => 'ӓ', + 'Ӗ' => 'Ӗ', + 'ӗ' => 'ӗ', + 'Ӛ' => 'Ӛ', + 'ӛ' => 'ӛ', + 'Ӝ' => 'Ӝ', + 'ӝ' => 'ӝ', + 'Ӟ' => 'Ӟ', + 'ӟ' => 'ӟ', + 'Ӣ' => 'Ӣ', + 'ӣ' => 'ӣ', + 'Ӥ' => 'Ӥ', + 'ӥ' => 'ӥ', + 'Ӧ' => 'Ӧ', + 'ӧ' => 'ӧ', + 'Ӫ' => 'Ӫ', + 'ӫ' => 'ӫ', + 'Ӭ' => 'Ӭ', + 'ӭ' => 'ӭ', + 'Ӯ' => 'Ӯ', + 'ӯ' => 'ӯ', + 'Ӱ' => 'Ӱ', + 'ӱ' => 'ӱ', + 'Ӳ' => 'Ӳ', + 'ӳ' => 'ӳ', + 'Ӵ' => 'Ӵ', + 'ӵ' => 'ӵ', + 'Ӹ' => 'Ӹ', + 'ӹ' => 'ӹ', + 'آ' => 'آ', + 'أ' => 'أ', + 'ؤ' => 'ؤ', + 'إ' => 'إ', + 'ئ' => 'ئ', + 'ۀ' => 'ۀ', + 'ۂ' => 'ۂ', + 'ۓ' => 'ۓ', + 'ऩ' => 'ऩ', + 'ऱ' => 'ऱ', + 'ऴ' => 'ऴ', + 'ো' => 'ো', + 'ৌ' => 'ৌ', + 'ୈ' => 'ୈ', + 'ୋ' => 'ୋ', + 'ୌ' => 'ୌ', + 'ஔ' => 'ஔ', + 'ொ' => 'ொ', + 'ோ' => 'ோ', + 'ௌ' => 'ௌ', + 'ై' => 'ై', + 'ೀ' => 'ೀ', + 'ೇ' => 'ೇ', + 'ೈ' => 'ೈ', + 'ೊ' => 'ೊ', + 'ೋ' => 'ೋ', + 'ൊ' => 'ൊ', + 'ോ' => 'ോ', + 'ൌ' => 'ൌ', + 'ේ' => 'ේ', + 'ො' => 'ො', + 'ෝ' => 'ෝ', + 'ෞ' => 'ෞ', + 'ဦ' => 'ဦ', + 'ᬆ' => 'ᬆ', + 'ᬈ' => 'ᬈ', + 'ᬊ' => 'ᬊ', + 'ᬌ' => 'ᬌ', + 'ᬎ' => 'ᬎ', + 'ᬒ' => 'ᬒ', + 'ᬻ' => 'ᬻ', + 'ᬽ' => 'ᬽ', + 'ᭀ' => 'ᭀ', + 'ᭁ' => 'ᭁ', + 'ᭃ' => 'ᭃ', + 'Ḁ' => 'Ḁ', + 'ḁ' => 'ḁ', + 'Ḃ' => 'Ḃ', + 'ḃ' => 'ḃ', + 'Ḅ' => 'Ḅ', + 'ḅ' => 'ḅ', + 'Ḇ' => 'Ḇ', + 'ḇ' => 'ḇ', + 'Ḉ' => 'Ḉ', + 'ḉ' => 'ḉ', + 'Ḋ' => 'Ḋ', + 'ḋ' => 'ḋ', + 'Ḍ' => 'Ḍ', + 'ḍ' => 'ḍ', + 'Ḏ' => 'Ḏ', + 'ḏ' => 'ḏ', + 'Ḑ' => 'Ḑ', + 'ḑ' => 'ḑ', + 'Ḓ' => 'Ḓ', + 'ḓ' => 'ḓ', + 'Ḕ' => 'Ḕ', + 'ḕ' => 'ḕ', + 'Ḗ' => 'Ḗ', + 'ḗ' => 'ḗ', + 'Ḙ' => 'Ḙ', + 'ḙ' => 'ḙ', + 'Ḛ' => 'Ḛ', + 'ḛ' => 'ḛ', + 'Ḝ' => 'Ḝ', + 'ḝ' => 'ḝ', + 'Ḟ' => 'Ḟ', + 'ḟ' => 'ḟ', + 'Ḡ' => 'Ḡ', + 'ḡ' => 'ḡ', + 'Ḣ' => 'Ḣ', + 'ḣ' => 'ḣ', + 'Ḥ' => 'Ḥ', + 'ḥ' => 'ḥ', + 'Ḧ' => 'Ḧ', + 'ḧ' => 'ḧ', + 'Ḩ' => 'Ḩ', + 'ḩ' => 'ḩ', + 'Ḫ' => 'Ḫ', + 'ḫ' => 'ḫ', + 'Ḭ' => 'Ḭ', + 'ḭ' => 'ḭ', + 'Ḯ' => 'Ḯ', + 'ḯ' => 'ḯ', + 'Ḱ' => 'Ḱ', + 'ḱ' => 'ḱ', + 'Ḳ' => 'Ḳ', + 'ḳ' => 'ḳ', + 'Ḵ' => 'Ḵ', + 'ḵ' => 'ḵ', + 'Ḷ' => 'Ḷ', + 'ḷ' => 'ḷ', + 'Ḹ' => 'Ḹ', + 'ḹ' => 'ḹ', + 'Ḻ' => 'Ḻ', + 'ḻ' => 'ḻ', + 'Ḽ' => 'Ḽ', + 'ḽ' => 'ḽ', + 'Ḿ' => 'Ḿ', + 'ḿ' => 'ḿ', + 'Ṁ' => 'Ṁ', + 'ṁ' => 'ṁ', + 'Ṃ' => 'Ṃ', + 'ṃ' => 'ṃ', + 'Ṅ' => 'Ṅ', + 'ṅ' => 'ṅ', + 'Ṇ' => 'Ṇ', + 'ṇ' => 'ṇ', + 'Ṉ' => 'Ṉ', + 'ṉ' => 'ṉ', + 'Ṋ' => 'Ṋ', + 'ṋ' => 'ṋ', + 'Ṍ' => 'Ṍ', + 'ṍ' => 'ṍ', + 'Ṏ' => 'Ṏ', + 'ṏ' => 'ṏ', + 'Ṑ' => 'Ṑ', + 'ṑ' => 'ṑ', + 'Ṓ' => 'Ṓ', + 'ṓ' => 'ṓ', + 'Ṕ' => 'Ṕ', + 'ṕ' => 'ṕ', + 'Ṗ' => 'Ṗ', + 'ṗ' => 'ṗ', + 'Ṙ' => 'Ṙ', + 'ṙ' => 'ṙ', + 'Ṛ' => 'Ṛ', + 'ṛ' => 'ṛ', + 'Ṝ' => 'Ṝ', + 'ṝ' => 'ṝ', + 'Ṟ' => 'Ṟ', + 'ṟ' => 'ṟ', + 'Ṡ' => 'Ṡ', + 'ṡ' => 'ṡ', + 'Ṣ' => 'Ṣ', + 'ṣ' => 'ṣ', + 'Ṥ' => 'Ṥ', + 'ṥ' => 'ṥ', + 'Ṧ' => 'Ṧ', + 'ṧ' => 'ṧ', + 'Ṩ' => 'Ṩ', + 'ṩ' => 'ṩ', + 'Ṫ' => 'Ṫ', + 'ṫ' => 'ṫ', + 'Ṭ' => 'Ṭ', + 'ṭ' => 'ṭ', + 'Ṯ' => 'Ṯ', + 'ṯ' => 'ṯ', + 'Ṱ' => 'Ṱ', + 'ṱ' => 'ṱ', + 'Ṳ' => 'Ṳ', + 'ṳ' => 'ṳ', + 'Ṵ' => 'Ṵ', + 'ṵ' => 'ṵ', + 'Ṷ' => 'Ṷ', + 'ṷ' => 'ṷ', + 'Ṹ' => 'Ṹ', + 'ṹ' => 'ṹ', + 'Ṻ' => 'Ṻ', + 'ṻ' => 'ṻ', + 'Ṽ' => 'Ṽ', + 'ṽ' => 'ṽ', + 'Ṿ' => 'Ṿ', + 'ṿ' => 'ṿ', + 'Ẁ' => 'Ẁ', + 'ẁ' => 'ẁ', + 'Ẃ' => 'Ẃ', + 'ẃ' => 'ẃ', + 'Ẅ' => 'Ẅ', + 'ẅ' => 'ẅ', + 'Ẇ' => 'Ẇ', + 'ẇ' => 'ẇ', + 'Ẉ' => 'Ẉ', + 'ẉ' => 'ẉ', + 'Ẋ' => 'Ẋ', + 'ẋ' => 'ẋ', + 'Ẍ' => 'Ẍ', + 'ẍ' => 'ẍ', + 'Ẏ' => 'Ẏ', + 'ẏ' => 'ẏ', + 'Ẑ' => 'Ẑ', + 'ẑ' => 'ẑ', + 'Ẓ' => 'Ẓ', + 'ẓ' => 'ẓ', + 'Ẕ' => 'Ẕ', + 'ẕ' => 'ẕ', + 'ẖ' => 'ẖ', + 'ẗ' => 'ẗ', + 'ẘ' => 'ẘ', + 'ẙ' => 'ẙ', + 'ẛ' => 'ẛ', + 'Ạ' => 'Ạ', + 'ạ' => 'ạ', + 'Ả' => 'Ả', + 'ả' => 'ả', + 'Ấ' => 'Ấ', + 'ấ' => 'ấ', + 'Ầ' => 'Ầ', + 'ầ' => 'ầ', + 'Ẩ' => 'Ẩ', + 'ẩ' => 'ẩ', + 'Ẫ' => 'Ẫ', + 'ẫ' => 'ẫ', + 'Ậ' => 'Ậ', + 'ậ' => 'ậ', + 'Ắ' => 'Ắ', + 'ắ' => 'ắ', + 'Ằ' => 'Ằ', + 'ằ' => 'ằ', + 'Ẳ' => 'Ẳ', + 'ẳ' => 'ẳ', + 'Ẵ' => 'Ẵ', + 'ẵ' => 'ẵ', + 'Ặ' => 'Ặ', + 'ặ' => 'ặ', + 'Ẹ' => 'Ẹ', + 'ẹ' => 'ẹ', + 'Ẻ' => 'Ẻ', + 'ẻ' => 'ẻ', + 'Ẽ' => 'Ẽ', + 'ẽ' => 'ẽ', + 'Ế' => 'Ế', + 'ế' => 'ế', + 'Ề' => 'Ề', + 'ề' => 'ề', + 'Ể' => 'Ể', + 'ể' => 'ể', + 'Ễ' => 'Ễ', + 'ễ' => 'ễ', + 'Ệ' => 'Ệ', + 'ệ' => 'ệ', + 'Ỉ' => 'Ỉ', + 'ỉ' => 'ỉ', + 'Ị' => 'Ị', + 'ị' => 'ị', + 'Ọ' => 'Ọ', + 'ọ' => 'ọ', + 'Ỏ' => 'Ỏ', + 'ỏ' => 'ỏ', + 'Ố' => 'Ố', + 'ố' => 'ố', + 'Ồ' => 'Ồ', + 'ồ' => 'ồ', + 'Ổ' => 'Ổ', + 'ổ' => 'ổ', + 'Ỗ' => 'Ỗ', + 'ỗ' => 'ỗ', + 'Ộ' => 'Ộ', + 'ộ' => 'ộ', + 'Ớ' => 'Ớ', + 'ớ' => 'ớ', + 'Ờ' => 'Ờ', + 'ờ' => 'ờ', + 'Ở' => 'Ở', + 'ở' => 'ở', + 'Ỡ' => 'Ỡ', + 'ỡ' => 'ỡ', + 'Ợ' => 'Ợ', + 'ợ' => 'ợ', + 'Ụ' => 'Ụ', + 'ụ' => 'ụ', + 'Ủ' => 'Ủ', + 'ủ' => 'ủ', + 'Ứ' => 'Ứ', + 'ứ' => 'ứ', + 'Ừ' => 'Ừ', + 'ừ' => 'ừ', + 'Ử' => 'Ử', + 'ử' => 'ử', + 'Ữ' => 'Ữ', + 'ữ' => 'ữ', + 'Ự' => 'Ự', + 'ự' => 'ự', + 'Ỳ' => 'Ỳ', + 'ỳ' => 'ỳ', + 'Ỵ' => 'Ỵ', + 'ỵ' => 'ỵ', + 'Ỷ' => 'Ỷ', + 'ỷ' => 'ỷ', + 'Ỹ' => 'Ỹ', + 'ỹ' => 'ỹ', + 'ἀ' => 'ἀ', + 'ἁ' => 'ἁ', + 'ἂ' => 'ἂ', + 'ἃ' => 'ἃ', + 'ἄ' => 'ἄ', + 'ἅ' => 'ἅ', + 'ἆ' => 'ἆ', + 'ἇ' => 'ἇ', + 'Ἀ' => 'Ἀ', + 'Ἁ' => 'Ἁ', + 'Ἂ' => 'Ἂ', + 'Ἃ' => 'Ἃ', + 'Ἄ' => 'Ἄ', + 'Ἅ' => 'Ἅ', + 'Ἆ' => 'Ἆ', + 'Ἇ' => 'Ἇ', + 'ἐ' => 'ἐ', + 'ἑ' => 'ἑ', + 'ἒ' => 'ἒ', + 'ἓ' => 'ἓ', + 'ἔ' => 'ἔ', + 'ἕ' => 'ἕ', + 'Ἐ' => 'Ἐ', + 'Ἑ' => 'Ἑ', + 'Ἒ' => 'Ἒ', + 'Ἓ' => 'Ἓ', + 'Ἔ' => 'Ἔ', + 'Ἕ' => 'Ἕ', + 'ἠ' => 'ἠ', + 'ἡ' => 'ἡ', + 'ἢ' => 'ἢ', + 'ἣ' => 'ἣ', + 'ἤ' => 'ἤ', + 'ἥ' => 'ἥ', + 'ἦ' => 'ἦ', + 'ἧ' => 'ἧ', + 'Ἠ' => 'Ἠ', + 'Ἡ' => 'Ἡ', + 'Ἢ' => 'Ἢ', + 'Ἣ' => 'Ἣ', + 'Ἤ' => 'Ἤ', + 'Ἥ' => 'Ἥ', + 'Ἦ' => 'Ἦ', + 'Ἧ' => 'Ἧ', + 'ἰ' => 'ἰ', + 'ἱ' => 'ἱ', + 'ἲ' => 'ἲ', + 'ἳ' => 'ἳ', + 'ἴ' => 'ἴ', + 'ἵ' => 'ἵ', + 'ἶ' => 'ἶ', + 'ἷ' => 'ἷ', + 'Ἰ' => 'Ἰ', + 'Ἱ' => 'Ἱ', + 'Ἲ' => 'Ἲ', + 'Ἳ' => 'Ἳ', + 'Ἴ' => 'Ἴ', + 'Ἵ' => 'Ἵ', + 'Ἶ' => 'Ἶ', + 'Ἷ' => 'Ἷ', + 'ὀ' => 'ὀ', + 'ὁ' => 'ὁ', + 'ὂ' => 'ὂ', + 'ὃ' => 'ὃ', + 'ὄ' => 'ὄ', + 'ὅ' => 'ὅ', + 'Ὀ' => 'Ὀ', + 'Ὁ' => 'Ὁ', + 'Ὂ' => 'Ὂ', + 'Ὃ' => 'Ὃ', + 'Ὄ' => 'Ὄ', + 'Ὅ' => 'Ὅ', + 'ὐ' => 'ὐ', + 'ὑ' => 'ὑ', + 'ὒ' => 'ὒ', + 'ὓ' => 'ὓ', + 'ὔ' => 'ὔ', + 'ὕ' => 'ὕ', + 'ὖ' => 'ὖ', + 'ὗ' => 'ὗ', + 'Ὑ' => 'Ὑ', + 'Ὓ' => 'Ὓ', + 'Ὕ' => 'Ὕ', + 'Ὗ' => 'Ὗ', + 'ὠ' => 'ὠ', + 'ὡ' => 'ὡ', + 'ὢ' => 'ὢ', + 'ὣ' => 'ὣ', + 'ὤ' => 'ὤ', + 'ὥ' => 'ὥ', + 'ὦ' => 'ὦ', + 'ὧ' => 'ὧ', + 'Ὠ' => 'Ὠ', + 'Ὡ' => 'Ὡ', + 'Ὢ' => 'Ὢ', + 'Ὣ' => 'Ὣ', + 'Ὤ' => 'Ὤ', + 'Ὥ' => 'Ὥ', + 'Ὦ' => 'Ὦ', + 'Ὧ' => 'Ὧ', + 'ὰ' => 'ὰ', + 'ὲ' => 'ὲ', + 'ὴ' => 'ὴ', + 'ὶ' => 'ὶ', + 'ὸ' => 'ὸ', + 'ὺ' => 'ὺ', + 'ὼ' => 'ὼ', + 'ᾀ' => 'ᾀ', + 'ᾁ' => 'ᾁ', + 'ᾂ' => 'ᾂ', + 'ᾃ' => 'ᾃ', + 'ᾄ' => 'ᾄ', + 'ᾅ' => 'ᾅ', + 'ᾆ' => 'ᾆ', + 'ᾇ' => 'ᾇ', + 'ᾈ' => 'ᾈ', + 'ᾉ' => 'ᾉ', + 'ᾊ' => 'ᾊ', + 'ᾋ' => 'ᾋ', + 'ᾌ' => 'ᾌ', + 'ᾍ' => 'ᾍ', + 'ᾎ' => 'ᾎ', + 'ᾏ' => 'ᾏ', + 'ᾐ' => 'ᾐ', + 'ᾑ' => 'ᾑ', + 'ᾒ' => 'ᾒ', + 'ᾓ' => 'ᾓ', + 'ᾔ' => 'ᾔ', + 'ᾕ' => 'ᾕ', + 'ᾖ' => 'ᾖ', + 'ᾗ' => 'ᾗ', + 'ᾘ' => 'ᾘ', + 'ᾙ' => 'ᾙ', + 'ᾚ' => 'ᾚ', + 'ᾛ' => 'ᾛ', + 'ᾜ' => 'ᾜ', + 'ᾝ' => 'ᾝ', + 'ᾞ' => 'ᾞ', + 'ᾟ' => 'ᾟ', + 'ᾠ' => 'ᾠ', + 'ᾡ' => 'ᾡ', + 'ᾢ' => 'ᾢ', + 'ᾣ' => 'ᾣ', + 'ᾤ' => 'ᾤ', + 'ᾥ' => 'ᾥ', + 'ᾦ' => 'ᾦ', + 'ᾧ' => 'ᾧ', + 'ᾨ' => 'ᾨ', + 'ᾩ' => 'ᾩ', + 'ᾪ' => 'ᾪ', + 'ᾫ' => 'ᾫ', + 'ᾬ' => 'ᾬ', + 'ᾭ' => 'ᾭ', + 'ᾮ' => 'ᾮ', + 'ᾯ' => 'ᾯ', + 'ᾰ' => 'ᾰ', + 'ᾱ' => 'ᾱ', + 'ᾲ' => 'ᾲ', + 'ᾳ' => 'ᾳ', + 'ᾴ' => 'ᾴ', + 'ᾶ' => 'ᾶ', + 'ᾷ' => 'ᾷ', + 'Ᾰ' => 'Ᾰ', + 'Ᾱ' => 'Ᾱ', + 'Ὰ' => 'Ὰ', + 'ᾼ' => 'ᾼ', + '῁' => '῁', + 'ῂ' => 'ῂ', + 'ῃ' => 'ῃ', + 'ῄ' => 'ῄ', + 'ῆ' => 'ῆ', + 'ῇ' => 'ῇ', + 'Ὲ' => 'Ὲ', + 'Ὴ' => 'Ὴ', + 'ῌ' => 'ῌ', + '῍' => '῍', + '῎' => '῎', + '῏' => '῏', + 'ῐ' => 'ῐ', + 'ῑ' => 'ῑ', + 'ῒ' => 'ῒ', + 'ῖ' => 'ῖ', + 'ῗ' => 'ῗ', + 'Ῐ' => 'Ῐ', + 'Ῑ' => 'Ῑ', + 'Ὶ' => 'Ὶ', + '῝' => '῝', + '῞' => '῞', + '῟' => '῟', + 'ῠ' => 'ῠ', + 'ῡ' => 'ῡ', + 'ῢ' => 'ῢ', + 'ῤ' => 'ῤ', + 'ῥ' => 'ῥ', + 'ῦ' => 'ῦ', + 'ῧ' => 'ῧ', + 'Ῠ' => 'Ῠ', + 'Ῡ' => 'Ῡ', + 'Ὺ' => 'Ὺ', + 'Ῥ' => 'Ῥ', + '῭' => '῭', + 'ῲ' => 'ῲ', + 'ῳ' => 'ῳ', + 'ῴ' => 'ῴ', + 'ῶ' => 'ῶ', + 'ῷ' => 'ῷ', + 'Ὸ' => 'Ὸ', + 'Ὼ' => 'Ὼ', + 'ῼ' => 'ῼ', + '↚' => '↚', + '↛' => '↛', + '↮' => '↮', + '⇍' => '⇍', + '⇎' => '⇎', + '⇏' => '⇏', + '∄' => '∄', + '∉' => '∉', + '∌' => '∌', + '∤' => '∤', + '∦' => '∦', + '≁' => '≁', + '≄' => '≄', + '≇' => '≇', + '≉' => '≉', + '≠' => '≠', + '≢' => '≢', + '≭' => '≭', + '≮' => '≮', + '≯' => '≯', + '≰' => '≰', + '≱' => '≱', + '≴' => '≴', + '≵' => '≵', + '≸' => '≸', + '≹' => '≹', + '⊀' => '⊀', + '⊁' => '⊁', + '⊄' => '⊄', + '⊅' => '⊅', + '⊈' => '⊈', + '⊉' => '⊉', + '⊬' => '⊬', + '⊭' => '⊭', + '⊮' => '⊮', + '⊯' => '⊯', + '⋠' => '⋠', + '⋡' => '⋡', + '⋢' => '⋢', + '⋣' => '⋣', + '⋪' => '⋪', + '⋫' => '⋫', + '⋬' => '⋬', + '⋭' => '⋭', + 'が' => 'が', + 'ぎ' => 'ぎ', + 'ぐ' => 'ぐ', + 'げ' => 'げ', + 'ご' => 'ご', + 'ざ' => 'ざ', + 'じ' => 'じ', + 'ず' => 'ず', + 'ぜ' => 'ぜ', + 'ぞ' => 'ぞ', + 'だ' => 'だ', + 'ぢ' => 'ぢ', + 'づ' => 'づ', + 'で' => 'で', + 'ど' => 'ど', + 'ば' => 'ば', + 'ぱ' => 'ぱ', + 'び' => 'び', + 'ぴ' => 'ぴ', + 'ぶ' => 'ぶ', + 'ぷ' => 'ぷ', + 'べ' => 'べ', + 'ぺ' => 'ぺ', + 'ぼ' => 'ぼ', + 'ぽ' => 'ぽ', + 'ゔ' => 'ゔ', + 'ゞ' => 'ゞ', + 'ガ' => 'ガ', + 'ギ' => 'ギ', + 'グ' => 'グ', + 'ゲ' => 'ゲ', + 'ゴ' => 'ゴ', + 'ザ' => 'ザ', + 'ジ' => 'ジ', + 'ズ' => 'ズ', + 'ゼ' => 'ゼ', + 'ゾ' => 'ゾ', + 'ダ' => 'ダ', + 'ヂ' => 'ヂ', + 'ヅ' => 'ヅ', + 'デ' => 'デ', + 'ド' => 'ド', + 'バ' => 'バ', + 'パ' => 'パ', + 'ビ' => 'ビ', + 'ピ' => 'ピ', + 'ブ' => 'ブ', + 'プ' => 'プ', + 'ベ' => 'ベ', + 'ペ' => 'ペ', + 'ボ' => 'ボ', + 'ポ' => 'ポ', + 'ヴ' => 'ヴ', + 'ヷ' => 'ヷ', + 'ヸ' => 'ヸ', + 'ヹ' => 'ヹ', + 'ヺ' => 'ヺ', + 'ヾ' => 'ヾ', + '𑂚' => '𑂚', + '𑂜' => '𑂜', + '𑂫' => '𑂫', + '𑄮' => '𑄮', + '𑄯' => '𑄯', + '𑍋' => '𑍋', + '𑍌' => '𑍌', + '𑒻' => '𑒻', + '𑒼' => '𑒼', + '𑒾' => '𑒾', + '𑖺' => '𑖺', + '𑖻' => '𑖻', + '𑤸' => '𑤸', +); diff --git a/tools/mailer/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php b/tools/mailer/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php new file mode 100644 index 000000000..5a3e8e096 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php @@ -0,0 +1,2065 @@ + 'À', + 'Á' => 'Á', + 'Â' => 'Â', + 'Ã' => 'Ã', + 'Ä' => 'Ä', + 'Å' => 'Å', + 'Ç' => 'Ç', + 'È' => 'È', + 'É' => 'É', + 'Ê' => 'Ê', + 'Ë' => 'Ë', + 'Ì' => 'Ì', + 'Í' => 'Í', + 'Î' => 'Î', + 'Ï' => 'Ï', + 'Ñ' => 'Ñ', + 'Ò' => 'Ò', + 'Ó' => 'Ó', + 'Ô' => 'Ô', + 'Õ' => 'Õ', + 'Ö' => 'Ö', + 'Ù' => 'Ù', + 'Ú' => 'Ú', + 'Û' => 'Û', + 'Ü' => 'Ü', + 'Ý' => 'Ý', + 'à' => 'à', + 'á' => 'á', + 'â' => 'â', + 'ã' => 'ã', + 'ä' => 'ä', + 'å' => 'å', + 'ç' => 'ç', + 'è' => 'è', + 'é' => 'é', + 'ê' => 'ê', + 'ë' => 'ë', + 'ì' => 'ì', + 'í' => 'í', + 'î' => 'î', + 'ï' => 'ï', + 'ñ' => 'ñ', + 'ò' => 'ò', + 'ó' => 'ó', + 'ô' => 'ô', + 'õ' => 'õ', + 'ö' => 'ö', + 'ù' => 'ù', + 'ú' => 'ú', + 'û' => 'û', + 'ü' => 'ü', + 'ý' => 'ý', + 'ÿ' => 'ÿ', + 'Ā' => 'Ā', + 'ā' => 'ā', + 'Ă' => 'Ă', + 'ă' => 'ă', + 'Ą' => 'Ą', + 'ą' => 'ą', + 'Ć' => 'Ć', + 'ć' => 'ć', + 'Ĉ' => 'Ĉ', + 'ĉ' => 'ĉ', + 'Ċ' => 'Ċ', + 'ċ' => 'ċ', + 'Č' => 'Č', + 'č' => 'č', + 'Ď' => 'Ď', + 'ď' => 'ď', + 'Ē' => 'Ē', + 'ē' => 'ē', + 'Ĕ' => 'Ĕ', + 'ĕ' => 'ĕ', + 'Ė' => 'Ė', + 'ė' => 'ė', + 'Ę' => 'Ę', + 'ę' => 'ę', + 'Ě' => 'Ě', + 'ě' => 'ě', + 'Ĝ' => 'Ĝ', + 'ĝ' => 'ĝ', + 'Ğ' => 'Ğ', + 'ğ' => 'ğ', + 'Ġ' => 'Ġ', + 'ġ' => 'ġ', + 'Ģ' => 'Ģ', + 'ģ' => 'ģ', + 'Ĥ' => 'Ĥ', + 'ĥ' => 'ĥ', + 'Ĩ' => 'Ĩ', + 'ĩ' => 'ĩ', + 'Ī' => 'Ī', + 'ī' => 'ī', + 'Ĭ' => 'Ĭ', + 'ĭ' => 'ĭ', + 'Į' => 'Į', + 'į' => 'į', + 'İ' => 'İ', + 'Ĵ' => 'Ĵ', + 'ĵ' => 'ĵ', + 'Ķ' => 'Ķ', + 'ķ' => 'ķ', + 'Ĺ' => 'Ĺ', + 'ĺ' => 'ĺ', + 'Ļ' => 'Ļ', + 'ļ' => 'ļ', + 'Ľ' => 'Ľ', + 'ľ' => 'ľ', + 'Ń' => 'Ń', + 'ń' => 'ń', + 'Ņ' => 'Ņ', + 'ņ' => 'ņ', + 'Ň' => 'Ň', + 'ň' => 'ň', + 'Ō' => 'Ō', + 'ō' => 'ō', + 'Ŏ' => 'Ŏ', + 'ŏ' => 'ŏ', + 'Ő' => 'Ő', + 'ő' => 'ő', + 'Ŕ' => 'Ŕ', + 'ŕ' => 'ŕ', + 'Ŗ' => 'Ŗ', + 'ŗ' => 'ŗ', + 'Ř' => 'Ř', + 'ř' => 'ř', + 'Ś' => 'Ś', + 'ś' => 'ś', + 'Ŝ' => 'Ŝ', + 'ŝ' => 'ŝ', + 'Ş' => 'Ş', + 'ş' => 'ş', + 'Š' => 'Š', + 'š' => 'š', + 'Ţ' => 'Ţ', + 'ţ' => 'ţ', + 'Ť' => 'Ť', + 'ť' => 'ť', + 'Ũ' => 'Ũ', + 'ũ' => 'ũ', + 'Ū' => 'Ū', + 'ū' => 'ū', + 'Ŭ' => 'Ŭ', + 'ŭ' => 'ŭ', + 'Ů' => 'Ů', + 'ů' => 'ů', + 'Ű' => 'Ű', + 'ű' => 'ű', + 'Ų' => 'Ų', + 'ų' => 'ų', + 'Ŵ' => 'Ŵ', + 'ŵ' => 'ŵ', + 'Ŷ' => 'Ŷ', + 'ŷ' => 'ŷ', + 'Ÿ' => 'Ÿ', + 'Ź' => 'Ź', + 'ź' => 'ź', + 'Ż' => 'Ż', + 'ż' => 'ż', + 'Ž' => 'Ž', + 'ž' => 'ž', + 'Ơ' => 'Ơ', + 'ơ' => 'ơ', + 'Ư' => 'Ư', + 'ư' => 'ư', + 'Ǎ' => 'Ǎ', + 'ǎ' => 'ǎ', + 'Ǐ' => 'Ǐ', + 'ǐ' => 'ǐ', + 'Ǒ' => 'Ǒ', + 'ǒ' => 'ǒ', + 'Ǔ' => 'Ǔ', + 'ǔ' => 'ǔ', + 'Ǖ' => 'Ǖ', + 'ǖ' => 'ǖ', + 'Ǘ' => 'Ǘ', + 'ǘ' => 'ǘ', + 'Ǚ' => 'Ǚ', + 'ǚ' => 'ǚ', + 'Ǜ' => 'Ǜ', + 'ǜ' => 'ǜ', + 'Ǟ' => 'Ǟ', + 'ǟ' => 'ǟ', + 'Ǡ' => 'Ǡ', + 'ǡ' => 'ǡ', + 'Ǣ' => 'Ǣ', + 'ǣ' => 'ǣ', + 'Ǧ' => 'Ǧ', + 'ǧ' => 'ǧ', + 'Ǩ' => 'Ǩ', + 'ǩ' => 'ǩ', + 'Ǫ' => 'Ǫ', + 'ǫ' => 'ǫ', + 'Ǭ' => 'Ǭ', + 'ǭ' => 'ǭ', + 'Ǯ' => 'Ǯ', + 'ǯ' => 'ǯ', + 'ǰ' => 'ǰ', + 'Ǵ' => 'Ǵ', + 'ǵ' => 'ǵ', + 'Ǹ' => 'Ǹ', + 'ǹ' => 'ǹ', + 'Ǻ' => 'Ǻ', + 'ǻ' => 'ǻ', + 'Ǽ' => 'Ǽ', + 'ǽ' => 'ǽ', + 'Ǿ' => 'Ǿ', + 'ǿ' => 'ǿ', + 'Ȁ' => 'Ȁ', + 'ȁ' => 'ȁ', + 'Ȃ' => 'Ȃ', + 'ȃ' => 'ȃ', + 'Ȅ' => 'Ȅ', + 'ȅ' => 'ȅ', + 'Ȇ' => 'Ȇ', + 'ȇ' => 'ȇ', + 'Ȉ' => 'Ȉ', + 'ȉ' => 'ȉ', + 'Ȋ' => 'Ȋ', + 'ȋ' => 'ȋ', + 'Ȍ' => 'Ȍ', + 'ȍ' => 'ȍ', + 'Ȏ' => 'Ȏ', + 'ȏ' => 'ȏ', + 'Ȑ' => 'Ȑ', + 'ȑ' => 'ȑ', + 'Ȓ' => 'Ȓ', + 'ȓ' => 'ȓ', + 'Ȕ' => 'Ȕ', + 'ȕ' => 'ȕ', + 'Ȗ' => 'Ȗ', + 'ȗ' => 'ȗ', + 'Ș' => 'Ș', + 'ș' => 'ș', + 'Ț' => 'Ț', + 'ț' => 'ț', + 'Ȟ' => 'Ȟ', + 'ȟ' => 'ȟ', + 'Ȧ' => 'Ȧ', + 'ȧ' => 'ȧ', + 'Ȩ' => 'Ȩ', + 'ȩ' => 'ȩ', + 'Ȫ' => 'Ȫ', + 'ȫ' => 'ȫ', + 'Ȭ' => 'Ȭ', + 'ȭ' => 'ȭ', + 'Ȯ' => 'Ȯ', + 'ȯ' => 'ȯ', + 'Ȱ' => 'Ȱ', + 'ȱ' => 'ȱ', + 'Ȳ' => 'Ȳ', + 'ȳ' => 'ȳ', + '̀' => '̀', + '́' => '́', + '̓' => '̓', + '̈́' => '̈́', + 'ʹ' => 'ʹ', + ';' => ';', + '΅' => '΅', + 'Ά' => 'Ά', + '·' => '·', + 'Έ' => 'Έ', + 'Ή' => 'Ή', + 'Ί' => 'Ί', + 'Ό' => 'Ό', + 'Ύ' => 'Ύ', + 'Ώ' => 'Ώ', + 'ΐ' => 'ΐ', + 'Ϊ' => 'Ϊ', + 'Ϋ' => 'Ϋ', + 'ά' => 'ά', + 'έ' => 'έ', + 'ή' => 'ή', + 'ί' => 'ί', + 'ΰ' => 'ΰ', + 'ϊ' => 'ϊ', + 'ϋ' => 'ϋ', + 'ό' => 'ό', + 'ύ' => 'ύ', + 'ώ' => 'ώ', + 'ϓ' => 'ϓ', + 'ϔ' => 'ϔ', + 'Ѐ' => 'Ѐ', + 'Ё' => 'Ё', + 'Ѓ' => 'Ѓ', + 'Ї' => 'Ї', + 'Ќ' => 'Ќ', + 'Ѝ' => 'Ѝ', + 'Ў' => 'Ў', + 'Й' => 'Й', + 'й' => 'й', + 'ѐ' => 'ѐ', + 'ё' => 'ё', + 'ѓ' => 'ѓ', + 'ї' => 'ї', + 'ќ' => 'ќ', + 'ѝ' => 'ѝ', + 'ў' => 'ў', + 'Ѷ' => 'Ѷ', + 'ѷ' => 'ѷ', + 'Ӂ' => 'Ӂ', + 'ӂ' => 'ӂ', + 'Ӑ' => 'Ӑ', + 'ӑ' => 'ӑ', + 'Ӓ' => 'Ӓ', + 'ӓ' => 'ӓ', + 'Ӗ' => 'Ӗ', + 'ӗ' => 'ӗ', + 'Ӛ' => 'Ӛ', + 'ӛ' => 'ӛ', + 'Ӝ' => 'Ӝ', + 'ӝ' => 'ӝ', + 'Ӟ' => 'Ӟ', + 'ӟ' => 'ӟ', + 'Ӣ' => 'Ӣ', + 'ӣ' => 'ӣ', + 'Ӥ' => 'Ӥ', + 'ӥ' => 'ӥ', + 'Ӧ' => 'Ӧ', + 'ӧ' => 'ӧ', + 'Ӫ' => 'Ӫ', + 'ӫ' => 'ӫ', + 'Ӭ' => 'Ӭ', + 'ӭ' => 'ӭ', + 'Ӯ' => 'Ӯ', + 'ӯ' => 'ӯ', + 'Ӱ' => 'Ӱ', + 'ӱ' => 'ӱ', + 'Ӳ' => 'Ӳ', + 'ӳ' => 'ӳ', + 'Ӵ' => 'Ӵ', + 'ӵ' => 'ӵ', + 'Ӹ' => 'Ӹ', + 'ӹ' => 'ӹ', + 'آ' => 'آ', + 'أ' => 'أ', + 'ؤ' => 'ؤ', + 'إ' => 'إ', + 'ئ' => 'ئ', + 'ۀ' => 'ۀ', + 'ۂ' => 'ۂ', + 'ۓ' => 'ۓ', + 'ऩ' => 'ऩ', + 'ऱ' => 'ऱ', + 'ऴ' => 'ऴ', + 'क़' => 'क़', + 'ख़' => 'ख़', + 'ग़' => 'ग़', + 'ज़' => 'ज़', + 'ड़' => 'ड़', + 'ढ़' => 'ढ़', + 'फ़' => 'फ़', + 'य़' => 'य़', + 'ো' => 'ো', + 'ৌ' => 'ৌ', + 'ড়' => 'ড়', + 'ঢ়' => 'ঢ়', + 'য়' => 'য়', + 'ਲ਼' => 'ਲ਼', + 'ਸ਼' => 'ਸ਼', + 'ਖ਼' => 'ਖ਼', + 'ਗ਼' => 'ਗ਼', + 'ਜ਼' => 'ਜ਼', + 'ਫ਼' => 'ਫ਼', + 'ୈ' => 'ୈ', + 'ୋ' => 'ୋ', + 'ୌ' => 'ୌ', + 'ଡ଼' => 'ଡ଼', + 'ଢ଼' => 'ଢ଼', + 'ஔ' => 'ஔ', + 'ொ' => 'ொ', + 'ோ' => 'ோ', + 'ௌ' => 'ௌ', + 'ై' => 'ై', + 'ೀ' => 'ೀ', + 'ೇ' => 'ೇ', + 'ೈ' => 'ೈ', + 'ೊ' => 'ೊ', + 'ೋ' => 'ೋ', + 'ൊ' => 'ൊ', + 'ോ' => 'ോ', + 'ൌ' => 'ൌ', + 'ේ' => 'ේ', + 'ො' => 'ො', + 'ෝ' => 'ෝ', + 'ෞ' => 'ෞ', + 'གྷ' => 'གྷ', + 'ཌྷ' => 'ཌྷ', + 'དྷ' => 'དྷ', + 'བྷ' => 'བྷ', + 'ཛྷ' => 'ཛྷ', + 'ཀྵ' => 'ཀྵ', + 'ཱི' => 'ཱི', + 'ཱུ' => 'ཱུ', + 'ྲྀ' => 'ྲྀ', + 'ླྀ' => 'ླྀ', + 'ཱྀ' => 'ཱྀ', + 'ྒྷ' => 'ྒྷ', + 'ྜྷ' => 'ྜྷ', + 'ྡྷ' => 'ྡྷ', + 'ྦྷ' => 'ྦྷ', + 'ྫྷ' => 'ྫྷ', + 'ྐྵ' => 'ྐྵ', + 'ဦ' => 'ဦ', + 'ᬆ' => 'ᬆ', + 'ᬈ' => 'ᬈ', + 'ᬊ' => 'ᬊ', + 'ᬌ' => 'ᬌ', + 'ᬎ' => 'ᬎ', + 'ᬒ' => 'ᬒ', + 'ᬻ' => 'ᬻ', + 'ᬽ' => 'ᬽ', + 'ᭀ' => 'ᭀ', + 'ᭁ' => 'ᭁ', + 'ᭃ' => 'ᭃ', + 'Ḁ' => 'Ḁ', + 'ḁ' => 'ḁ', + 'Ḃ' => 'Ḃ', + 'ḃ' => 'ḃ', + 'Ḅ' => 'Ḅ', + 'ḅ' => 'ḅ', + 'Ḇ' => 'Ḇ', + 'ḇ' => 'ḇ', + 'Ḉ' => 'Ḉ', + 'ḉ' => 'ḉ', + 'Ḋ' => 'Ḋ', + 'ḋ' => 'ḋ', + 'Ḍ' => 'Ḍ', + 'ḍ' => 'ḍ', + 'Ḏ' => 'Ḏ', + 'ḏ' => 'ḏ', + 'Ḑ' => 'Ḑ', + 'ḑ' => 'ḑ', + 'Ḓ' => 'Ḓ', + 'ḓ' => 'ḓ', + 'Ḕ' => 'Ḕ', + 'ḕ' => 'ḕ', + 'Ḗ' => 'Ḗ', + 'ḗ' => 'ḗ', + 'Ḙ' => 'Ḙ', + 'ḙ' => 'ḙ', + 'Ḛ' => 'Ḛ', + 'ḛ' => 'ḛ', + 'Ḝ' => 'Ḝ', + 'ḝ' => 'ḝ', + 'Ḟ' => 'Ḟ', + 'ḟ' => 'ḟ', + 'Ḡ' => 'Ḡ', + 'ḡ' => 'ḡ', + 'Ḣ' => 'Ḣ', + 'ḣ' => 'ḣ', + 'Ḥ' => 'Ḥ', + 'ḥ' => 'ḥ', + 'Ḧ' => 'Ḧ', + 'ḧ' => 'ḧ', + 'Ḩ' => 'Ḩ', + 'ḩ' => 'ḩ', + 'Ḫ' => 'Ḫ', + 'ḫ' => 'ḫ', + 'Ḭ' => 'Ḭ', + 'ḭ' => 'ḭ', + 'Ḯ' => 'Ḯ', + 'ḯ' => 'ḯ', + 'Ḱ' => 'Ḱ', + 'ḱ' => 'ḱ', + 'Ḳ' => 'Ḳ', + 'ḳ' => 'ḳ', + 'Ḵ' => 'Ḵ', + 'ḵ' => 'ḵ', + 'Ḷ' => 'Ḷ', + 'ḷ' => 'ḷ', + 'Ḹ' => 'Ḹ', + 'ḹ' => 'ḹ', + 'Ḻ' => 'Ḻ', + 'ḻ' => 'ḻ', + 'Ḽ' => 'Ḽ', + 'ḽ' => 'ḽ', + 'Ḿ' => 'Ḿ', + 'ḿ' => 'ḿ', + 'Ṁ' => 'Ṁ', + 'ṁ' => 'ṁ', + 'Ṃ' => 'Ṃ', + 'ṃ' => 'ṃ', + 'Ṅ' => 'Ṅ', + 'ṅ' => 'ṅ', + 'Ṇ' => 'Ṇ', + 'ṇ' => 'ṇ', + 'Ṉ' => 'Ṉ', + 'ṉ' => 'ṉ', + 'Ṋ' => 'Ṋ', + 'ṋ' => 'ṋ', + 'Ṍ' => 'Ṍ', + 'ṍ' => 'ṍ', + 'Ṏ' => 'Ṏ', + 'ṏ' => 'ṏ', + 'Ṑ' => 'Ṑ', + 'ṑ' => 'ṑ', + 'Ṓ' => 'Ṓ', + 'ṓ' => 'ṓ', + 'Ṕ' => 'Ṕ', + 'ṕ' => 'ṕ', + 'Ṗ' => 'Ṗ', + 'ṗ' => 'ṗ', + 'Ṙ' => 'Ṙ', + 'ṙ' => 'ṙ', + 'Ṛ' => 'Ṛ', + 'ṛ' => 'ṛ', + 'Ṝ' => 'Ṝ', + 'ṝ' => 'ṝ', + 'Ṟ' => 'Ṟ', + 'ṟ' => 'ṟ', + 'Ṡ' => 'Ṡ', + 'ṡ' => 'ṡ', + 'Ṣ' => 'Ṣ', + 'ṣ' => 'ṣ', + 'Ṥ' => 'Ṥ', + 'ṥ' => 'ṥ', + 'Ṧ' => 'Ṧ', + 'ṧ' => 'ṧ', + 'Ṩ' => 'Ṩ', + 'ṩ' => 'ṩ', + 'Ṫ' => 'Ṫ', + 'ṫ' => 'ṫ', + 'Ṭ' => 'Ṭ', + 'ṭ' => 'ṭ', + 'Ṯ' => 'Ṯ', + 'ṯ' => 'ṯ', + 'Ṱ' => 'Ṱ', + 'ṱ' => 'ṱ', + 'Ṳ' => 'Ṳ', + 'ṳ' => 'ṳ', + 'Ṵ' => 'Ṵ', + 'ṵ' => 'ṵ', + 'Ṷ' => 'Ṷ', + 'ṷ' => 'ṷ', + 'Ṹ' => 'Ṹ', + 'ṹ' => 'ṹ', + 'Ṻ' => 'Ṻ', + 'ṻ' => 'ṻ', + 'Ṽ' => 'Ṽ', + 'ṽ' => 'ṽ', + 'Ṿ' => 'Ṿ', + 'ṿ' => 'ṿ', + 'Ẁ' => 'Ẁ', + 'ẁ' => 'ẁ', + 'Ẃ' => 'Ẃ', + 'ẃ' => 'ẃ', + 'Ẅ' => 'Ẅ', + 'ẅ' => 'ẅ', + 'Ẇ' => 'Ẇ', + 'ẇ' => 'ẇ', + 'Ẉ' => 'Ẉ', + 'ẉ' => 'ẉ', + 'Ẋ' => 'Ẋ', + 'ẋ' => 'ẋ', + 'Ẍ' => 'Ẍ', + 'ẍ' => 'ẍ', + 'Ẏ' => 'Ẏ', + 'ẏ' => 'ẏ', + 'Ẑ' => 'Ẑ', + 'ẑ' => 'ẑ', + 'Ẓ' => 'Ẓ', + 'ẓ' => 'ẓ', + 'Ẕ' => 'Ẕ', + 'ẕ' => 'ẕ', + 'ẖ' => 'ẖ', + 'ẗ' => 'ẗ', + 'ẘ' => 'ẘ', + 'ẙ' => 'ẙ', + 'ẛ' => 'ẛ', + 'Ạ' => 'Ạ', + 'ạ' => 'ạ', + 'Ả' => 'Ả', + 'ả' => 'ả', + 'Ấ' => 'Ấ', + 'ấ' => 'ấ', + 'Ầ' => 'Ầ', + 'ầ' => 'ầ', + 'Ẩ' => 'Ẩ', + 'ẩ' => 'ẩ', + 'Ẫ' => 'Ẫ', + 'ẫ' => 'ẫ', + 'Ậ' => 'Ậ', + 'ậ' => 'ậ', + 'Ắ' => 'Ắ', + 'ắ' => 'ắ', + 'Ằ' => 'Ằ', + 'ằ' => 'ằ', + 'Ẳ' => 'Ẳ', + 'ẳ' => 'ẳ', + 'Ẵ' => 'Ẵ', + 'ẵ' => 'ẵ', + 'Ặ' => 'Ặ', + 'ặ' => 'ặ', + 'Ẹ' => 'Ẹ', + 'ẹ' => 'ẹ', + 'Ẻ' => 'Ẻ', + 'ẻ' => 'ẻ', + 'Ẽ' => 'Ẽ', + 'ẽ' => 'ẽ', + 'Ế' => 'Ế', + 'ế' => 'ế', + 'Ề' => 'Ề', + 'ề' => 'ề', + 'Ể' => 'Ể', + 'ể' => 'ể', + 'Ễ' => 'Ễ', + 'ễ' => 'ễ', + 'Ệ' => 'Ệ', + 'ệ' => 'ệ', + 'Ỉ' => 'Ỉ', + 'ỉ' => 'ỉ', + 'Ị' => 'Ị', + 'ị' => 'ị', + 'Ọ' => 'Ọ', + 'ọ' => 'ọ', + 'Ỏ' => 'Ỏ', + 'ỏ' => 'ỏ', + 'Ố' => 'Ố', + 'ố' => 'ố', + 'Ồ' => 'Ồ', + 'ồ' => 'ồ', + 'Ổ' => 'Ổ', + 'ổ' => 'ổ', + 'Ỗ' => 'Ỗ', + 'ỗ' => 'ỗ', + 'Ộ' => 'Ộ', + 'ộ' => 'ộ', + 'Ớ' => 'Ớ', + 'ớ' => 'ớ', + 'Ờ' => 'Ờ', + 'ờ' => 'ờ', + 'Ở' => 'Ở', + 'ở' => 'ở', + 'Ỡ' => 'Ỡ', + 'ỡ' => 'ỡ', + 'Ợ' => 'Ợ', + 'ợ' => 'ợ', + 'Ụ' => 'Ụ', + 'ụ' => 'ụ', + 'Ủ' => 'Ủ', + 'ủ' => 'ủ', + 'Ứ' => 'Ứ', + 'ứ' => 'ứ', + 'Ừ' => 'Ừ', + 'ừ' => 'ừ', + 'Ử' => 'Ử', + 'ử' => 'ử', + 'Ữ' => 'Ữ', + 'ữ' => 'ữ', + 'Ự' => 'Ự', + 'ự' => 'ự', + 'Ỳ' => 'Ỳ', + 'ỳ' => 'ỳ', + 'Ỵ' => 'Ỵ', + 'ỵ' => 'ỵ', + 'Ỷ' => 'Ỷ', + 'ỷ' => 'ỷ', + 'Ỹ' => 'Ỹ', + 'ỹ' => 'ỹ', + 'ἀ' => 'ἀ', + 'ἁ' => 'ἁ', + 'ἂ' => 'ἂ', + 'ἃ' => 'ἃ', + 'ἄ' => 'ἄ', + 'ἅ' => 'ἅ', + 'ἆ' => 'ἆ', + 'ἇ' => 'ἇ', + 'Ἀ' => 'Ἀ', + 'Ἁ' => 'Ἁ', + 'Ἂ' => 'Ἂ', + 'Ἃ' => 'Ἃ', + 'Ἄ' => 'Ἄ', + 'Ἅ' => 'Ἅ', + 'Ἆ' => 'Ἆ', + 'Ἇ' => 'Ἇ', + 'ἐ' => 'ἐ', + 'ἑ' => 'ἑ', + 'ἒ' => 'ἒ', + 'ἓ' => 'ἓ', + 'ἔ' => 'ἔ', + 'ἕ' => 'ἕ', + 'Ἐ' => 'Ἐ', + 'Ἑ' => 'Ἑ', + 'Ἒ' => 'Ἒ', + 'Ἓ' => 'Ἓ', + 'Ἔ' => 'Ἔ', + 'Ἕ' => 'Ἕ', + 'ἠ' => 'ἠ', + 'ἡ' => 'ἡ', + 'ἢ' => 'ἢ', + 'ἣ' => 'ἣ', + 'ἤ' => 'ἤ', + 'ἥ' => 'ἥ', + 'ἦ' => 'ἦ', + 'ἧ' => 'ἧ', + 'Ἠ' => 'Ἠ', + 'Ἡ' => 'Ἡ', + 'Ἢ' => 'Ἢ', + 'Ἣ' => 'Ἣ', + 'Ἤ' => 'Ἤ', + 'Ἥ' => 'Ἥ', + 'Ἦ' => 'Ἦ', + 'Ἧ' => 'Ἧ', + 'ἰ' => 'ἰ', + 'ἱ' => 'ἱ', + 'ἲ' => 'ἲ', + 'ἳ' => 'ἳ', + 'ἴ' => 'ἴ', + 'ἵ' => 'ἵ', + 'ἶ' => 'ἶ', + 'ἷ' => 'ἷ', + 'Ἰ' => 'Ἰ', + 'Ἱ' => 'Ἱ', + 'Ἲ' => 'Ἲ', + 'Ἳ' => 'Ἳ', + 'Ἴ' => 'Ἴ', + 'Ἵ' => 'Ἵ', + 'Ἶ' => 'Ἶ', + 'Ἷ' => 'Ἷ', + 'ὀ' => 'ὀ', + 'ὁ' => 'ὁ', + 'ὂ' => 'ὂ', + 'ὃ' => 'ὃ', + 'ὄ' => 'ὄ', + 'ὅ' => 'ὅ', + 'Ὀ' => 'Ὀ', + 'Ὁ' => 'Ὁ', + 'Ὂ' => 'Ὂ', + 'Ὃ' => 'Ὃ', + 'Ὄ' => 'Ὄ', + 'Ὅ' => 'Ὅ', + 'ὐ' => 'ὐ', + 'ὑ' => 'ὑ', + 'ὒ' => 'ὒ', + 'ὓ' => 'ὓ', + 'ὔ' => 'ὔ', + 'ὕ' => 'ὕ', + 'ὖ' => 'ὖ', + 'ὗ' => 'ὗ', + 'Ὑ' => 'Ὑ', + 'Ὓ' => 'Ὓ', + 'Ὕ' => 'Ὕ', + 'Ὗ' => 'Ὗ', + 'ὠ' => 'ὠ', + 'ὡ' => 'ὡ', + 'ὢ' => 'ὢ', + 'ὣ' => 'ὣ', + 'ὤ' => 'ὤ', + 'ὥ' => 'ὥ', + 'ὦ' => 'ὦ', + 'ὧ' => 'ὧ', + 'Ὠ' => 'Ὠ', + 'Ὡ' => 'Ὡ', + 'Ὢ' => 'Ὢ', + 'Ὣ' => 'Ὣ', + 'Ὤ' => 'Ὤ', + 'Ὥ' => 'Ὥ', + 'Ὦ' => 'Ὦ', + 'Ὧ' => 'Ὧ', + 'ὰ' => 'ὰ', + 'ά' => 'ά', + 'ὲ' => 'ὲ', + 'έ' => 'έ', + 'ὴ' => 'ὴ', + 'ή' => 'ή', + 'ὶ' => 'ὶ', + 'ί' => 'ί', + 'ὸ' => 'ὸ', + 'ό' => 'ό', + 'ὺ' => 'ὺ', + 'ύ' => 'ύ', + 'ὼ' => 'ὼ', + 'ώ' => 'ώ', + 'ᾀ' => 'ᾀ', + 'ᾁ' => 'ᾁ', + 'ᾂ' => 'ᾂ', + 'ᾃ' => 'ᾃ', + 'ᾄ' => 'ᾄ', + 'ᾅ' => 'ᾅ', + 'ᾆ' => 'ᾆ', + 'ᾇ' => 'ᾇ', + 'ᾈ' => 'ᾈ', + 'ᾉ' => 'ᾉ', + 'ᾊ' => 'ᾊ', + 'ᾋ' => 'ᾋ', + 'ᾌ' => 'ᾌ', + 'ᾍ' => 'ᾍ', + 'ᾎ' => 'ᾎ', + 'ᾏ' => 'ᾏ', + 'ᾐ' => 'ᾐ', + 'ᾑ' => 'ᾑ', + 'ᾒ' => 'ᾒ', + 'ᾓ' => 'ᾓ', + 'ᾔ' => 'ᾔ', + 'ᾕ' => 'ᾕ', + 'ᾖ' => 'ᾖ', + 'ᾗ' => 'ᾗ', + 'ᾘ' => 'ᾘ', + 'ᾙ' => 'ᾙ', + 'ᾚ' => 'ᾚ', + 'ᾛ' => 'ᾛ', + 'ᾜ' => 'ᾜ', + 'ᾝ' => 'ᾝ', + 'ᾞ' => 'ᾞ', + 'ᾟ' => 'ᾟ', + 'ᾠ' => 'ᾠ', + 'ᾡ' => 'ᾡ', + 'ᾢ' => 'ᾢ', + 'ᾣ' => 'ᾣ', + 'ᾤ' => 'ᾤ', + 'ᾥ' => 'ᾥ', + 'ᾦ' => 'ᾦ', + 'ᾧ' => 'ᾧ', + 'ᾨ' => 'ᾨ', + 'ᾩ' => 'ᾩ', + 'ᾪ' => 'ᾪ', + 'ᾫ' => 'ᾫ', + 'ᾬ' => 'ᾬ', + 'ᾭ' => 'ᾭ', + 'ᾮ' => 'ᾮ', + 'ᾯ' => 'ᾯ', + 'ᾰ' => 'ᾰ', + 'ᾱ' => 'ᾱ', + 'ᾲ' => 'ᾲ', + 'ᾳ' => 'ᾳ', + 'ᾴ' => 'ᾴ', + 'ᾶ' => 'ᾶ', + 'ᾷ' => 'ᾷ', + 'Ᾰ' => 'Ᾰ', + 'Ᾱ' => 'Ᾱ', + 'Ὰ' => 'Ὰ', + 'Ά' => 'Ά', + 'ᾼ' => 'ᾼ', + 'ι' => 'ι', + '῁' => '῁', + 'ῂ' => 'ῂ', + 'ῃ' => 'ῃ', + 'ῄ' => 'ῄ', + 'ῆ' => 'ῆ', + 'ῇ' => 'ῇ', + 'Ὲ' => 'Ὲ', + 'Έ' => 'Έ', + 'Ὴ' => 'Ὴ', + 'Ή' => 'Ή', + 'ῌ' => 'ῌ', + '῍' => '῍', + '῎' => '῎', + '῏' => '῏', + 'ῐ' => 'ῐ', + 'ῑ' => 'ῑ', + 'ῒ' => 'ῒ', + 'ΐ' => 'ΐ', + 'ῖ' => 'ῖ', + 'ῗ' => 'ῗ', + 'Ῐ' => 'Ῐ', + 'Ῑ' => 'Ῑ', + 'Ὶ' => 'Ὶ', + 'Ί' => 'Ί', + '῝' => '῝', + '῞' => '῞', + '῟' => '῟', + 'ῠ' => 'ῠ', + 'ῡ' => 'ῡ', + 'ῢ' => 'ῢ', + 'ΰ' => 'ΰ', + 'ῤ' => 'ῤ', + 'ῥ' => 'ῥ', + 'ῦ' => 'ῦ', + 'ῧ' => 'ῧ', + 'Ῠ' => 'Ῠ', + 'Ῡ' => 'Ῡ', + 'Ὺ' => 'Ὺ', + 'Ύ' => 'Ύ', + 'Ῥ' => 'Ῥ', + '῭' => '῭', + '΅' => '΅', + '`' => '`', + 'ῲ' => 'ῲ', + 'ῳ' => 'ῳ', + 'ῴ' => 'ῴ', + 'ῶ' => 'ῶ', + 'ῷ' => 'ῷ', + 'Ὸ' => 'Ὸ', + 'Ό' => 'Ό', + 'Ὼ' => 'Ὼ', + 'Ώ' => 'Ώ', + 'ῼ' => 'ῼ', + '´' => '´', + ' ' => ' ', + ' ' => ' ', + 'Ω' => 'Ω', + 'K' => 'K', + 'Å' => 'Å', + '↚' => '↚', + '↛' => '↛', + '↮' => '↮', + '⇍' => '⇍', + '⇎' => '⇎', + '⇏' => '⇏', + '∄' => '∄', + '∉' => '∉', + '∌' => '∌', + '∤' => '∤', + '∦' => '∦', + '≁' => '≁', + '≄' => '≄', + '≇' => '≇', + '≉' => '≉', + '≠' => '≠', + '≢' => '≢', + '≭' => '≭', + '≮' => '≮', + '≯' => '≯', + '≰' => '≰', + '≱' => '≱', + '≴' => '≴', + '≵' => '≵', + '≸' => '≸', + '≹' => '≹', + '⊀' => '⊀', + '⊁' => '⊁', + '⊄' => '⊄', + '⊅' => '⊅', + '⊈' => '⊈', + '⊉' => '⊉', + '⊬' => '⊬', + '⊭' => '⊭', + '⊮' => '⊮', + '⊯' => '⊯', + '⋠' => '⋠', + '⋡' => '⋡', + '⋢' => '⋢', + '⋣' => '⋣', + '⋪' => '⋪', + '⋫' => '⋫', + '⋬' => '⋬', + '⋭' => '⋭', + '〈' => '〈', + '〉' => '〉', + '⫝̸' => '⫝̸', + 'が' => 'が', + 'ぎ' => 'ぎ', + 'ぐ' => 'ぐ', + 'げ' => 'げ', + 'ご' => 'ご', + 'ざ' => 'ざ', + 'じ' => 'じ', + 'ず' => 'ず', + 'ぜ' => 'ぜ', + 'ぞ' => 'ぞ', + 'だ' => 'だ', + 'ぢ' => 'ぢ', + 'づ' => 'づ', + 'で' => 'で', + 'ど' => 'ど', + 'ば' => 'ば', + 'ぱ' => 'ぱ', + 'び' => 'び', + 'ぴ' => 'ぴ', + 'ぶ' => 'ぶ', + 'ぷ' => 'ぷ', + 'べ' => 'べ', + 'ぺ' => 'ぺ', + 'ぼ' => 'ぼ', + 'ぽ' => 'ぽ', + 'ゔ' => 'ゔ', + 'ゞ' => 'ゞ', + 'ガ' => 'ガ', + 'ギ' => 'ギ', + 'グ' => 'グ', + 'ゲ' => 'ゲ', + 'ゴ' => 'ゴ', + 'ザ' => 'ザ', + 'ジ' => 'ジ', + 'ズ' => 'ズ', + 'ゼ' => 'ゼ', + 'ゾ' => 'ゾ', + 'ダ' => 'ダ', + 'ヂ' => 'ヂ', + 'ヅ' => 'ヅ', + 'デ' => 'デ', + 'ド' => 'ド', + 'バ' => 'バ', + 'パ' => 'パ', + 'ビ' => 'ビ', + 'ピ' => 'ピ', + 'ブ' => 'ブ', + 'プ' => 'プ', + 'ベ' => 'ベ', + 'ペ' => 'ペ', + 'ボ' => 'ボ', + 'ポ' => 'ポ', + 'ヴ' => 'ヴ', + 'ヷ' => 'ヷ', + 'ヸ' => 'ヸ', + 'ヹ' => 'ヹ', + 'ヺ' => 'ヺ', + 'ヾ' => 'ヾ', + '豈' => '豈', + '更' => '更', + '車' => '車', + '賈' => '賈', + '滑' => '滑', + '串' => '串', + '句' => '句', + '龜' => '龜', + '龜' => '龜', + '契' => '契', + '金' => '金', + '喇' => '喇', + '奈' => '奈', + '懶' => '懶', + '癩' => '癩', + '羅' => '羅', + '蘿' => '蘿', + '螺' => '螺', + '裸' => '裸', + '邏' => '邏', + '樂' => '樂', + '洛' => '洛', + '烙' => '烙', + '珞' => '珞', + '落' => '落', + '酪' => '酪', + '駱' => '駱', + '亂' => '亂', + '卵' => '卵', + '欄' => '欄', + '爛' => '爛', + '蘭' => '蘭', + '鸞' => '鸞', + '嵐' => '嵐', + '濫' => '濫', + '藍' => '藍', + '襤' => '襤', + '拉' => '拉', + '臘' => '臘', + '蠟' => '蠟', + '廊' => '廊', + '朗' => '朗', + '浪' => '浪', + '狼' => '狼', + '郎' => '郎', + '來' => '來', + '冷' => '冷', + '勞' => '勞', + '擄' => '擄', + '櫓' => '櫓', + '爐' => '爐', + '盧' => '盧', + '老' => '老', + '蘆' => '蘆', + '虜' => '虜', + '路' => '路', + '露' => '露', + '魯' => '魯', + '鷺' => '鷺', + '碌' => '碌', + '祿' => '祿', + '綠' => '綠', + '菉' => '菉', + '錄' => '錄', + '鹿' => '鹿', + '論' => '論', + '壟' => '壟', + '弄' => '弄', + '籠' => '籠', + '聾' => '聾', + '牢' => '牢', + '磊' => '磊', + '賂' => '賂', + '雷' => '雷', + '壘' => '壘', + '屢' => '屢', + '樓' => '樓', + '淚' => '淚', + '漏' => '漏', + '累' => '累', + '縷' => '縷', + '陋' => '陋', + '勒' => '勒', + '肋' => '肋', + '凜' => '凜', + '凌' => '凌', + '稜' => '稜', + '綾' => '綾', + '菱' => '菱', + '陵' => '陵', + '讀' => '讀', + '拏' => '拏', + '樂' => '樂', + '諾' => '諾', + '丹' => '丹', + '寧' => '寧', + '怒' => '怒', + '率' => '率', + '異' => '異', + '北' => '北', + '磻' => '磻', + '便' => '便', + '復' => '復', + '不' => '不', + '泌' => '泌', + '數' => '數', + '索' => '索', + '參' => '參', + '塞' => '塞', + '省' => '省', + '葉' => '葉', + '說' => '說', + '殺' => '殺', + '辰' => '辰', + '沈' => '沈', + '拾' => '拾', + '若' => '若', + '掠' => '掠', + '略' => '略', + '亮' => '亮', + '兩' => '兩', + '凉' => '凉', + '梁' => '梁', + '糧' => '糧', + '良' => '良', + '諒' => '諒', + '量' => '量', + '勵' => '勵', + '呂' => '呂', + '女' => '女', + '廬' => '廬', + '旅' => '旅', + '濾' => '濾', + '礪' => '礪', + '閭' => '閭', + '驪' => '驪', + '麗' => '麗', + '黎' => '黎', + '力' => '力', + '曆' => '曆', + '歷' => '歷', + '轢' => '轢', + '年' => '年', + '憐' => '憐', + '戀' => '戀', + '撚' => '撚', + '漣' => '漣', + '煉' => '煉', + '璉' => '璉', + '秊' => '秊', + '練' => '練', + '聯' => '聯', + '輦' => '輦', + '蓮' => '蓮', + '連' => '連', + '鍊' => '鍊', + '列' => '列', + '劣' => '劣', + '咽' => '咽', + '烈' => '烈', + '裂' => '裂', + '說' => '說', + '廉' => '廉', + '念' => '念', + '捻' => '捻', + '殮' => '殮', + '簾' => '簾', + '獵' => '獵', + '令' => '令', + '囹' => '囹', + '寧' => '寧', + '嶺' => '嶺', + '怜' => '怜', + '玲' => '玲', + '瑩' => '瑩', + '羚' => '羚', + '聆' => '聆', + '鈴' => '鈴', + '零' => '零', + '靈' => '靈', + '領' => '領', + '例' => '例', + '禮' => '禮', + '醴' => '醴', + '隸' => '隸', + '惡' => '惡', + '了' => '了', + '僚' => '僚', + '寮' => '寮', + '尿' => '尿', + '料' => '料', + '樂' => '樂', + '燎' => '燎', + '療' => '療', + '蓼' => '蓼', + '遼' => '遼', + '龍' => '龍', + '暈' => '暈', + '阮' => '阮', + '劉' => '劉', + '杻' => '杻', + '柳' => '柳', + '流' => '流', + '溜' => '溜', + '琉' => '琉', + '留' => '留', + '硫' => '硫', + '紐' => '紐', + '類' => '類', + '六' => '六', + '戮' => '戮', + '陸' => '陸', + '倫' => '倫', + '崙' => '崙', + '淪' => '淪', + '輪' => '輪', + '律' => '律', + '慄' => '慄', + '栗' => '栗', + '率' => '率', + '隆' => '隆', + '利' => '利', + '吏' => '吏', + '履' => '履', + '易' => '易', + '李' => '李', + '梨' => '梨', + '泥' => '泥', + '理' => '理', + '痢' => '痢', + '罹' => '罹', + '裏' => '裏', + '裡' => '裡', + '里' => '里', + '離' => '離', + '匿' => '匿', + '溺' => '溺', + '吝' => '吝', + '燐' => '燐', + '璘' => '璘', + '藺' => '藺', + '隣' => '隣', + '鱗' => '鱗', + '麟' => '麟', + '林' => '林', + '淋' => '淋', + '臨' => '臨', + '立' => '立', + '笠' => '笠', + '粒' => '粒', + '狀' => '狀', + '炙' => '炙', + '識' => '識', + '什' => '什', + '茶' => '茶', + '刺' => '刺', + '切' => '切', + '度' => '度', + '拓' => '拓', + '糖' => '糖', + '宅' => '宅', + '洞' => '洞', + '暴' => '暴', + '輻' => '輻', + '行' => '行', + '降' => '降', + '見' => '見', + '廓' => '廓', + '兀' => '兀', + '嗀' => '嗀', + '塚' => '塚', + '晴' => '晴', + '凞' => '凞', + '猪' => '猪', + '益' => '益', + '礼' => '礼', + '神' => '神', + '祥' => '祥', + '福' => '福', + '靖' => '靖', + '精' => '精', + '羽' => '羽', + '蘒' => '蘒', + '諸' => '諸', + '逸' => '逸', + '都' => '都', + '飯' => '飯', + '飼' => '飼', + '館' => '館', + '鶴' => '鶴', + '郞' => '郞', + '隷' => '隷', + '侮' => '侮', + '僧' => '僧', + '免' => '免', + '勉' => '勉', + '勤' => '勤', + '卑' => '卑', + '喝' => '喝', + '嘆' => '嘆', + '器' => '器', + '塀' => '塀', + '墨' => '墨', + '層' => '層', + '屮' => '屮', + '悔' => '悔', + '慨' => '慨', + '憎' => '憎', + '懲' => '懲', + '敏' => '敏', + '既' => '既', + '暑' => '暑', + '梅' => '梅', + '海' => '海', + '渚' => '渚', + '漢' => '漢', + '煮' => '煮', + '爫' => '爫', + '琢' => '琢', + '碑' => '碑', + '社' => '社', + '祉' => '祉', + '祈' => '祈', + '祐' => '祐', + '祖' => '祖', + '祝' => '祝', + '禍' => '禍', + '禎' => '禎', + '穀' => '穀', + '突' => '突', + '節' => '節', + '練' => '練', + '縉' => '縉', + '繁' => '繁', + '署' => '署', + '者' => '者', + '臭' => '臭', + '艹' => '艹', + '艹' => '艹', + '著' => '著', + '褐' => '褐', + '視' => '視', + '謁' => '謁', + '謹' => '謹', + '賓' => '賓', + '贈' => '贈', + '辶' => '辶', + '逸' => '逸', + '難' => '難', + '響' => '響', + '頻' => '頻', + '恵' => '恵', + '𤋮' => '𤋮', + '舘' => '舘', + '並' => '並', + '况' => '况', + '全' => '全', + '侀' => '侀', + '充' => '充', + '冀' => '冀', + '勇' => '勇', + '勺' => '勺', + '喝' => '喝', + '啕' => '啕', + '喙' => '喙', + '嗢' => '嗢', + '塚' => '塚', + '墳' => '墳', + '奄' => '奄', + '奔' => '奔', + '婢' => '婢', + '嬨' => '嬨', + '廒' => '廒', + '廙' => '廙', + '彩' => '彩', + '徭' => '徭', + '惘' => '惘', + '慎' => '慎', + '愈' => '愈', + '憎' => '憎', + '慠' => '慠', + '懲' => '懲', + '戴' => '戴', + '揄' => '揄', + '搜' => '搜', + '摒' => '摒', + '敖' => '敖', + '晴' => '晴', + '朗' => '朗', + '望' => '望', + '杖' => '杖', + '歹' => '歹', + '殺' => '殺', + '流' => '流', + '滛' => '滛', + '滋' => '滋', + '漢' => '漢', + '瀞' => '瀞', + '煮' => '煮', + '瞧' => '瞧', + '爵' => '爵', + '犯' => '犯', + '猪' => '猪', + '瑱' => '瑱', + '甆' => '甆', + '画' => '画', + '瘝' => '瘝', + '瘟' => '瘟', + '益' => '益', + '盛' => '盛', + '直' => '直', + '睊' => '睊', + '着' => '着', + '磌' => '磌', + '窱' => '窱', + '節' => '節', + '类' => '类', + '絛' => '絛', + '練' => '練', + '缾' => '缾', + '者' => '者', + '荒' => '荒', + '華' => '華', + '蝹' => '蝹', + '襁' => '襁', + '覆' => '覆', + '視' => '視', + '調' => '調', + '諸' => '諸', + '請' => '請', + '謁' => '謁', + '諾' => '諾', + '諭' => '諭', + '謹' => '謹', + '變' => '變', + '贈' => '贈', + '輸' => '輸', + '遲' => '遲', + '醙' => '醙', + '鉶' => '鉶', + '陼' => '陼', + '難' => '難', + '靖' => '靖', + '韛' => '韛', + '響' => '響', + '頋' => '頋', + '頻' => '頻', + '鬒' => '鬒', + '龜' => '龜', + '𢡊' => '𢡊', + '𢡄' => '𢡄', + '𣏕' => '𣏕', + '㮝' => '㮝', + '䀘' => '䀘', + '䀹' => '䀹', + '𥉉' => '𥉉', + '𥳐' => '𥳐', + '𧻓' => '𧻓', + '齃' => '齃', + '龎' => '龎', + 'יִ' => 'יִ', + 'ײַ' => 'ײַ', + 'שׁ' => 'שׁ', + 'שׂ' => 'שׂ', + 'שּׁ' => 'שּׁ', + 'שּׂ' => 'שּׂ', + 'אַ' => 'אַ', + 'אָ' => 'אָ', + 'אּ' => 'אּ', + 'בּ' => 'בּ', + 'גּ' => 'גּ', + 'דּ' => 'דּ', + 'הּ' => 'הּ', + 'וּ' => 'וּ', + 'זּ' => 'זּ', + 'טּ' => 'טּ', + 'יּ' => 'יּ', + 'ךּ' => 'ךּ', + 'כּ' => 'כּ', + 'לּ' => 'לּ', + 'מּ' => 'מּ', + 'נּ' => 'נּ', + 'סּ' => 'סּ', + 'ףּ' => 'ףּ', + 'פּ' => 'פּ', + 'צּ' => 'צּ', + 'קּ' => 'קּ', + 'רּ' => 'רּ', + 'שּ' => 'שּ', + 'תּ' => 'תּ', + 'וֹ' => 'וֹ', + 'בֿ' => 'בֿ', + 'כֿ' => 'כֿ', + 'פֿ' => 'פֿ', + '𑂚' => '𑂚', + '𑂜' => '𑂜', + '𑂫' => '𑂫', + '𑄮' => '𑄮', + '𑄯' => '𑄯', + '𑍋' => '𑍋', + '𑍌' => '𑍌', + '𑒻' => '𑒻', + '𑒼' => '𑒼', + '𑒾' => '𑒾', + '𑖺' => '𑖺', + '𑖻' => '𑖻', + '𑤸' => '𑤸', + '𝅗𝅥' => '𝅗𝅥', + '𝅘𝅥' => '𝅘𝅥', + '𝅘𝅥𝅮' => '𝅘𝅥𝅮', + '𝅘𝅥𝅯' => '𝅘𝅥𝅯', + '𝅘𝅥𝅰' => '𝅘𝅥𝅰', + '𝅘𝅥𝅱' => '𝅘𝅥𝅱', + '𝅘𝅥𝅲' => '𝅘𝅥𝅲', + '𝆹𝅥' => '𝆹𝅥', + '𝆺𝅥' => '𝆺𝅥', + '𝆹𝅥𝅮' => '𝆹𝅥𝅮', + '𝆺𝅥𝅮' => '𝆺𝅥𝅮', + '𝆹𝅥𝅯' => '𝆹𝅥𝅯', + '𝆺𝅥𝅯' => '𝆺𝅥𝅯', + '丽' => '丽', + '丸' => '丸', + '乁' => '乁', + '𠄢' => '𠄢', + '你' => '你', + '侮' => '侮', + '侻' => '侻', + '倂' => '倂', + '偺' => '偺', + '備' => '備', + '僧' => '僧', + '像' => '像', + '㒞' => '㒞', + '𠘺' => '𠘺', + '免' => '免', + '兔' => '兔', + '兤' => '兤', + '具' => '具', + '𠔜' => '𠔜', + '㒹' => '㒹', + '內' => '內', + '再' => '再', + '𠕋' => '𠕋', + '冗' => '冗', + '冤' => '冤', + '仌' => '仌', + '冬' => '冬', + '况' => '况', + '𩇟' => '𩇟', + '凵' => '凵', + '刃' => '刃', + '㓟' => '㓟', + '刻' => '刻', + '剆' => '剆', + '割' => '割', + '剷' => '剷', + '㔕' => '㔕', + '勇' => '勇', + '勉' => '勉', + '勤' => '勤', + '勺' => '勺', + '包' => '包', + '匆' => '匆', + '北' => '北', + '卉' => '卉', + '卑' => '卑', + '博' => '博', + '即' => '即', + '卽' => '卽', + '卿' => '卿', + '卿' => '卿', + '卿' => '卿', + '𠨬' => '𠨬', + '灰' => '灰', + '及' => '及', + '叟' => '叟', + '𠭣' => '𠭣', + '叫' => '叫', + '叱' => '叱', + '吆' => '吆', + '咞' => '咞', + '吸' => '吸', + '呈' => '呈', + '周' => '周', + '咢' => '咢', + '哶' => '哶', + '唐' => '唐', + '啓' => '啓', + '啣' => '啣', + '善' => '善', + '善' => '善', + '喙' => '喙', + '喫' => '喫', + '喳' => '喳', + '嗂' => '嗂', + '圖' => '圖', + '嘆' => '嘆', + '圗' => '圗', + '噑' => '噑', + '噴' => '噴', + '切' => '切', + '壮' => '壮', + '城' => '城', + '埴' => '埴', + '堍' => '堍', + '型' => '型', + '堲' => '堲', + '報' => '報', + '墬' => '墬', + '𡓤' => '𡓤', + '売' => '売', + '壷' => '壷', + '夆' => '夆', + '多' => '多', + '夢' => '夢', + '奢' => '奢', + '𡚨' => '𡚨', + '𡛪' => '𡛪', + '姬' => '姬', + '娛' => '娛', + '娧' => '娧', + '姘' => '姘', + '婦' => '婦', + '㛮' => '㛮', + '㛼' => '㛼', + '嬈' => '嬈', + '嬾' => '嬾', + '嬾' => '嬾', + '𡧈' => '𡧈', + '寃' => '寃', + '寘' => '寘', + '寧' => '寧', + '寳' => '寳', + '𡬘' => '𡬘', + '寿' => '寿', + '将' => '将', + '当' => '当', + '尢' => '尢', + '㞁' => '㞁', + '屠' => '屠', + '屮' => '屮', + '峀' => '峀', + '岍' => '岍', + '𡷤' => '𡷤', + '嵃' => '嵃', + '𡷦' => '𡷦', + '嵮' => '嵮', + '嵫' => '嵫', + '嵼' => '嵼', + '巡' => '巡', + '巢' => '巢', + '㠯' => '㠯', + '巽' => '巽', + '帨' => '帨', + '帽' => '帽', + '幩' => '幩', + '㡢' => '㡢', + '𢆃' => '𢆃', + '㡼' => '㡼', + '庰' => '庰', + '庳' => '庳', + '庶' => '庶', + '廊' => '廊', + '𪎒' => '𪎒', + '廾' => '廾', + '𢌱' => '𢌱', + '𢌱' => '𢌱', + '舁' => '舁', + '弢' => '弢', + '弢' => '弢', + '㣇' => '㣇', + '𣊸' => '𣊸', + '𦇚' => '𦇚', + '形' => '形', + '彫' => '彫', + '㣣' => '㣣', + '徚' => '徚', + '忍' => '忍', + '志' => '志', + '忹' => '忹', + '悁' => '悁', + '㤺' => '㤺', + '㤜' => '㤜', + '悔' => '悔', + '𢛔' => '𢛔', + '惇' => '惇', + '慈' => '慈', + '慌' => '慌', + '慎' => '慎', + '慌' => '慌', + '慺' => '慺', + '憎' => '憎', + '憲' => '憲', + '憤' => '憤', + '憯' => '憯', + '懞' => '懞', + '懲' => '懲', + '懶' => '懶', + '成' => '成', + '戛' => '戛', + '扝' => '扝', + '抱' => '抱', + '拔' => '拔', + '捐' => '捐', + '𢬌' => '𢬌', + '挽' => '挽', + '拼' => '拼', + '捨' => '捨', + '掃' => '掃', + '揤' => '揤', + '𢯱' => '𢯱', + '搢' => '搢', + '揅' => '揅', + '掩' => '掩', + '㨮' => '㨮', + '摩' => '摩', + '摾' => '摾', + '撝' => '撝', + '摷' => '摷', + '㩬' => '㩬', + '敏' => '敏', + '敬' => '敬', + '𣀊' => '𣀊', + '旣' => '旣', + '書' => '書', + '晉' => '晉', + '㬙' => '㬙', + '暑' => '暑', + '㬈' => '㬈', + '㫤' => '㫤', + '冒' => '冒', + '冕' => '冕', + '最' => '最', + '暜' => '暜', + '肭' => '肭', + '䏙' => '䏙', + '朗' => '朗', + '望' => '望', + '朡' => '朡', + '杞' => '杞', + '杓' => '杓', + '𣏃' => '𣏃', + '㭉' => '㭉', + '柺' => '柺', + '枅' => '枅', + '桒' => '桒', + '梅' => '梅', + '𣑭' => '𣑭', + '梎' => '梎', + '栟' => '栟', + '椔' => '椔', + '㮝' => '㮝', + '楂' => '楂', + '榣' => '榣', + '槪' => '槪', + '檨' => '檨', + '𣚣' => '𣚣', + '櫛' => '櫛', + '㰘' => '㰘', + '次' => '次', + '𣢧' => '𣢧', + '歔' => '歔', + '㱎' => '㱎', + '歲' => '歲', + '殟' => '殟', + '殺' => '殺', + '殻' => '殻', + '𣪍' => '𣪍', + '𡴋' => '𡴋', + '𣫺' => '𣫺', + '汎' => '汎', + '𣲼' => '𣲼', + '沿' => '沿', + '泍' => '泍', + '汧' => '汧', + '洖' => '洖', + '派' => '派', + '海' => '海', + '流' => '流', + '浩' => '浩', + '浸' => '浸', + '涅' => '涅', + '𣴞' => '𣴞', + '洴' => '洴', + '港' => '港', + '湮' => '湮', + '㴳' => '㴳', + '滋' => '滋', + '滇' => '滇', + '𣻑' => '𣻑', + '淹' => '淹', + '潮' => '潮', + '𣽞' => '𣽞', + '𣾎' => '𣾎', + '濆' => '濆', + '瀹' => '瀹', + '瀞' => '瀞', + '瀛' => '瀛', + '㶖' => '㶖', + '灊' => '灊', + '災' => '災', + '灷' => '灷', + '炭' => '炭', + '𠔥' => '𠔥', + '煅' => '煅', + '𤉣' => '𤉣', + '熜' => '熜', + '𤎫' => '𤎫', + '爨' => '爨', + '爵' => '爵', + '牐' => '牐', + '𤘈' => '𤘈', + '犀' => '犀', + '犕' => '犕', + '𤜵' => '𤜵', + '𤠔' => '𤠔', + '獺' => '獺', + '王' => '王', + '㺬' => '㺬', + '玥' => '玥', + '㺸' => '㺸', + '㺸' => '㺸', + '瑇' => '瑇', + '瑜' => '瑜', + '瑱' => '瑱', + '璅' => '璅', + '瓊' => '瓊', + '㼛' => '㼛', + '甤' => '甤', + '𤰶' => '𤰶', + '甾' => '甾', + '𤲒' => '𤲒', + '異' => '異', + '𢆟' => '𢆟', + '瘐' => '瘐', + '𤾡' => '𤾡', + '𤾸' => '𤾸', + '𥁄' => '𥁄', + '㿼' => '㿼', + '䀈' => '䀈', + '直' => '直', + '𥃳' => '𥃳', + '𥃲' => '𥃲', + '𥄙' => '𥄙', + '𥄳' => '𥄳', + '眞' => '眞', + '真' => '真', + '真' => '真', + '睊' => '睊', + '䀹' => '䀹', + '瞋' => '瞋', + '䁆' => '䁆', + '䂖' => '䂖', + '𥐝' => '𥐝', + '硎' => '硎', + '碌' => '碌', + '磌' => '磌', + '䃣' => '䃣', + '𥘦' => '𥘦', + '祖' => '祖', + '𥚚' => '𥚚', + '𥛅' => '𥛅', + '福' => '福', + '秫' => '秫', + '䄯' => '䄯', + '穀' => '穀', + '穊' => '穊', + '穏' => '穏', + '𥥼' => '𥥼', + '𥪧' => '𥪧', + '𥪧' => '𥪧', + '竮' => '竮', + '䈂' => '䈂', + '𥮫' => '𥮫', + '篆' => '篆', + '築' => '築', + '䈧' => '䈧', + '𥲀' => '𥲀', + '糒' => '糒', + '䊠' => '䊠', + '糨' => '糨', + '糣' => '糣', + '紀' => '紀', + '𥾆' => '𥾆', + '絣' => '絣', + '䌁' => '䌁', + '緇' => '緇', + '縂' => '縂', + '繅' => '繅', + '䌴' => '䌴', + '𦈨' => '𦈨', + '𦉇' => '𦉇', + '䍙' => '䍙', + '𦋙' => '𦋙', + '罺' => '罺', + '𦌾' => '𦌾', + '羕' => '羕', + '翺' => '翺', + '者' => '者', + '𦓚' => '𦓚', + '𦔣' => '𦔣', + '聠' => '聠', + '𦖨' => '𦖨', + '聰' => '聰', + '𣍟' => '𣍟', + '䏕' => '䏕', + '育' => '育', + '脃' => '脃', + '䐋' => '䐋', + '脾' => '脾', + '媵' => '媵', + '𦞧' => '𦞧', + '𦞵' => '𦞵', + '𣎓' => '𣎓', + '𣎜' => '𣎜', + '舁' => '舁', + '舄' => '舄', + '辞' => '辞', + '䑫' => '䑫', + '芑' => '芑', + '芋' => '芋', + '芝' => '芝', + '劳' => '劳', + '花' => '花', + '芳' => '芳', + '芽' => '芽', + '苦' => '苦', + '𦬼' => '𦬼', + '若' => '若', + '茝' => '茝', + '荣' => '荣', + '莭' => '莭', + '茣' => '茣', + '莽' => '莽', + '菧' => '菧', + '著' => '著', + '荓' => '荓', + '菊' => '菊', + '菌' => '菌', + '菜' => '菜', + '𦰶' => '𦰶', + '𦵫' => '𦵫', + '𦳕' => '𦳕', + '䔫' => '䔫', + '蓱' => '蓱', + '蓳' => '蓳', + '蔖' => '蔖', + '𧏊' => '𧏊', + '蕤' => '蕤', + '𦼬' => '𦼬', + '䕝' => '䕝', + '䕡' => '䕡', + '𦾱' => '𦾱', + '𧃒' => '𧃒', + '䕫' => '䕫', + '虐' => '虐', + '虜' => '虜', + '虧' => '虧', + '虩' => '虩', + '蚩' => '蚩', + '蚈' => '蚈', + '蜎' => '蜎', + '蛢' => '蛢', + '蝹' => '蝹', + '蜨' => '蜨', + '蝫' => '蝫', + '螆' => '螆', + '䗗' => '䗗', + '蟡' => '蟡', + '蠁' => '蠁', + '䗹' => '䗹', + '衠' => '衠', + '衣' => '衣', + '𧙧' => '𧙧', + '裗' => '裗', + '裞' => '裞', + '䘵' => '䘵', + '裺' => '裺', + '㒻' => '㒻', + '𧢮' => '𧢮', + '𧥦' => '𧥦', + '䚾' => '䚾', + '䛇' => '䛇', + '誠' => '誠', + '諭' => '諭', + '變' => '變', + '豕' => '豕', + '𧲨' => '𧲨', + '貫' => '貫', + '賁' => '賁', + '贛' => '贛', + '起' => '起', + '𧼯' => '𧼯', + '𠠄' => '𠠄', + '跋' => '跋', + '趼' => '趼', + '跰' => '跰', + '𠣞' => '𠣞', + '軔' => '軔', + '輸' => '輸', + '𨗒' => '𨗒', + '𨗭' => '𨗭', + '邔' => '邔', + '郱' => '郱', + '鄑' => '鄑', + '𨜮' => '𨜮', + '鄛' => '鄛', + '鈸' => '鈸', + '鋗' => '鋗', + '鋘' => '鋘', + '鉼' => '鉼', + '鏹' => '鏹', + '鐕' => '鐕', + '𨯺' => '𨯺', + '開' => '開', + '䦕' => '䦕', + '閷' => '閷', + '𨵷' => '𨵷', + '䧦' => '䧦', + '雃' => '雃', + '嶲' => '嶲', + '霣' => '霣', + '𩅅' => '𩅅', + '𩈚' => '𩈚', + '䩮' => '䩮', + '䩶' => '䩶', + '韠' => '韠', + '𩐊' => '𩐊', + '䪲' => '䪲', + '𩒖' => '𩒖', + '頋' => '頋', + '頋' => '頋', + '頩' => '頩', + '𩖶' => '𩖶', + '飢' => '飢', + '䬳' => '䬳', + '餩' => '餩', + '馧' => '馧', + '駂' => '駂', + '駾' => '駾', + '䯎' => '䯎', + '𩬰' => '𩬰', + '鬒' => '鬒', + '鱀' => '鱀', + '鳽' => '鳽', + '䳎' => '䳎', + '䳭' => '䳭', + '鵧' => '鵧', + '𪃎' => '𪃎', + '䳸' => '䳸', + '𪄅' => '𪄅', + '𪈎' => '𪈎', + '𪊑' => '𪊑', + '麻' => '麻', + '䵖' => '䵖', + '黹' => '黹', + '黾' => '黾', + '鼅' => '鼅', + '鼏' => '鼏', + '鼖' => '鼖', + '鼻' => '鼻', + '𪘀' => '𪘀', +); diff --git a/tools/mailer/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php b/tools/mailer/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php new file mode 100644 index 000000000..ec90f36eb --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php @@ -0,0 +1,876 @@ + 230, + '́' => 230, + '̂' => 230, + '̃' => 230, + '̄' => 230, + '̅' => 230, + '̆' => 230, + '̇' => 230, + '̈' => 230, + '̉' => 230, + '̊' => 230, + '̋' => 230, + '̌' => 230, + '̍' => 230, + '̎' => 230, + '̏' => 230, + '̐' => 230, + '̑' => 230, + '̒' => 230, + '̓' => 230, + '̔' => 230, + '̕' => 232, + '̖' => 220, + '̗' => 220, + '̘' => 220, + '̙' => 220, + '̚' => 232, + '̛' => 216, + '̜' => 220, + '̝' => 220, + '̞' => 220, + '̟' => 220, + '̠' => 220, + '̡' => 202, + '̢' => 202, + '̣' => 220, + '̤' => 220, + '̥' => 220, + '̦' => 220, + '̧' => 202, + '̨' => 202, + '̩' => 220, + '̪' => 220, + '̫' => 220, + '̬' => 220, + '̭' => 220, + '̮' => 220, + '̯' => 220, + '̰' => 220, + '̱' => 220, + '̲' => 220, + '̳' => 220, + '̴' => 1, + '̵' => 1, + '̶' => 1, + '̷' => 1, + '̸' => 1, + '̹' => 220, + '̺' => 220, + '̻' => 220, + '̼' => 220, + '̽' => 230, + '̾' => 230, + '̿' => 230, + '̀' => 230, + '́' => 230, + '͂' => 230, + '̓' => 230, + '̈́' => 230, + 'ͅ' => 240, + '͆' => 230, + '͇' => 220, + '͈' => 220, + '͉' => 220, + '͊' => 230, + '͋' => 230, + '͌' => 230, + '͍' => 220, + '͎' => 220, + '͐' => 230, + '͑' => 230, + '͒' => 230, + '͓' => 220, + '͔' => 220, + '͕' => 220, + '͖' => 220, + '͗' => 230, + '͘' => 232, + '͙' => 220, + '͚' => 220, + '͛' => 230, + '͜' => 233, + '͝' => 234, + '͞' => 234, + '͟' => 233, + '͠' => 234, + '͡' => 234, + '͢' => 233, + 'ͣ' => 230, + 'ͤ' => 230, + 'ͥ' => 230, + 'ͦ' => 230, + 'ͧ' => 230, + 'ͨ' => 230, + 'ͩ' => 230, + 'ͪ' => 230, + 'ͫ' => 230, + 'ͬ' => 230, + 'ͭ' => 230, + 'ͮ' => 230, + 'ͯ' => 230, + '҃' => 230, + '҄' => 230, + '҅' => 230, + '҆' => 230, + '҇' => 230, + '֑' => 220, + '֒' => 230, + '֓' => 230, + '֔' => 230, + '֕' => 230, + '֖' => 220, + '֗' => 230, + '֘' => 230, + '֙' => 230, + '֚' => 222, + '֛' => 220, + '֜' => 230, + '֝' => 230, + '֞' => 230, + '֟' => 230, + '֠' => 230, + '֡' => 230, + '֢' => 220, + '֣' => 220, + '֤' => 220, + '֥' => 220, + '֦' => 220, + '֧' => 220, + '֨' => 230, + '֩' => 230, + '֪' => 220, + '֫' => 230, + '֬' => 230, + '֭' => 222, + '֮' => 228, + '֯' => 230, + 'ְ' => 10, + 'ֱ' => 11, + 'ֲ' => 12, + 'ֳ' => 13, + 'ִ' => 14, + 'ֵ' => 15, + 'ֶ' => 16, + 'ַ' => 17, + 'ָ' => 18, + 'ֹ' => 19, + 'ֺ' => 19, + 'ֻ' => 20, + 'ּ' => 21, + 'ֽ' => 22, + 'ֿ' => 23, + 'ׁ' => 24, + 'ׂ' => 25, + 'ׄ' => 230, + 'ׅ' => 220, + 'ׇ' => 18, + 'ؐ' => 230, + 'ؑ' => 230, + 'ؒ' => 230, + 'ؓ' => 230, + 'ؔ' => 230, + 'ؕ' => 230, + 'ؖ' => 230, + 'ؗ' => 230, + 'ؘ' => 30, + 'ؙ' => 31, + 'ؚ' => 32, + 'ً' => 27, + 'ٌ' => 28, + 'ٍ' => 29, + 'َ' => 30, + 'ُ' => 31, + 'ِ' => 32, + 'ّ' => 33, + 'ْ' => 34, + 'ٓ' => 230, + 'ٔ' => 230, + 'ٕ' => 220, + 'ٖ' => 220, + 'ٗ' => 230, + '٘' => 230, + 'ٙ' => 230, + 'ٚ' => 230, + 'ٛ' => 230, + 'ٜ' => 220, + 'ٝ' => 230, + 'ٞ' => 230, + 'ٟ' => 220, + 'ٰ' => 35, + 'ۖ' => 230, + 'ۗ' => 230, + 'ۘ' => 230, + 'ۙ' => 230, + 'ۚ' => 230, + 'ۛ' => 230, + 'ۜ' => 230, + '۟' => 230, + '۠' => 230, + 'ۡ' => 230, + 'ۢ' => 230, + 'ۣ' => 220, + 'ۤ' => 230, + 'ۧ' => 230, + 'ۨ' => 230, + '۪' => 220, + '۫' => 230, + '۬' => 230, + 'ۭ' => 220, + 'ܑ' => 36, + 'ܰ' => 230, + 'ܱ' => 220, + 'ܲ' => 230, + 'ܳ' => 230, + 'ܴ' => 220, + 'ܵ' => 230, + 'ܶ' => 230, + 'ܷ' => 220, + 'ܸ' => 220, + 'ܹ' => 220, + 'ܺ' => 230, + 'ܻ' => 220, + 'ܼ' => 220, + 'ܽ' => 230, + 'ܾ' => 220, + 'ܿ' => 230, + '݀' => 230, + '݁' => 230, + '݂' => 220, + '݃' => 230, + '݄' => 220, + '݅' => 230, + '݆' => 220, + '݇' => 230, + '݈' => 220, + '݉' => 230, + '݊' => 230, + '߫' => 230, + '߬' => 230, + '߭' => 230, + '߮' => 230, + '߯' => 230, + '߰' => 230, + '߱' => 230, + '߲' => 220, + '߳' => 230, + '߽' => 220, + 'ࠖ' => 230, + 'ࠗ' => 230, + '࠘' => 230, + '࠙' => 230, + 'ࠛ' => 230, + 'ࠜ' => 230, + 'ࠝ' => 230, + 'ࠞ' => 230, + 'ࠟ' => 230, + 'ࠠ' => 230, + 'ࠡ' => 230, + 'ࠢ' => 230, + 'ࠣ' => 230, + 'ࠥ' => 230, + 'ࠦ' => 230, + 'ࠧ' => 230, + 'ࠩ' => 230, + 'ࠪ' => 230, + 'ࠫ' => 230, + 'ࠬ' => 230, + '࠭' => 230, + '࡙' => 220, + '࡚' => 220, + '࡛' => 220, + '࣓' => 220, + 'ࣔ' => 230, + 'ࣕ' => 230, + 'ࣖ' => 230, + 'ࣗ' => 230, + 'ࣘ' => 230, + 'ࣙ' => 230, + 'ࣚ' => 230, + 'ࣛ' => 230, + 'ࣜ' => 230, + 'ࣝ' => 230, + 'ࣞ' => 230, + 'ࣟ' => 230, + '࣠' => 230, + '࣡' => 230, + 'ࣣ' => 220, + 'ࣤ' => 230, + 'ࣥ' => 230, + 'ࣦ' => 220, + 'ࣧ' => 230, + 'ࣨ' => 230, + 'ࣩ' => 220, + '࣪' => 230, + '࣫' => 230, + '࣬' => 230, + '࣭' => 220, + '࣮' => 220, + '࣯' => 220, + 'ࣰ' => 27, + 'ࣱ' => 28, + 'ࣲ' => 29, + 'ࣳ' => 230, + 'ࣴ' => 230, + 'ࣵ' => 230, + 'ࣶ' => 220, + 'ࣷ' => 230, + 'ࣸ' => 230, + 'ࣹ' => 220, + 'ࣺ' => 220, + 'ࣻ' => 230, + 'ࣼ' => 230, + 'ࣽ' => 230, + 'ࣾ' => 230, + 'ࣿ' => 230, + '़' => 7, + '्' => 9, + '॑' => 230, + '॒' => 220, + '॓' => 230, + '॔' => 230, + '়' => 7, + '্' => 9, + '৾' => 230, + '਼' => 7, + '੍' => 9, + '઼' => 7, + '્' => 9, + '଼' => 7, + '୍' => 9, + '்' => 9, + '్' => 9, + 'ౕ' => 84, + 'ౖ' => 91, + '಼' => 7, + '್' => 9, + '഻' => 9, + '഼' => 9, + '്' => 9, + '්' => 9, + 'ุ' => 103, + 'ู' => 103, + 'ฺ' => 9, + '่' => 107, + '้' => 107, + '๊' => 107, + '๋' => 107, + 'ຸ' => 118, + 'ູ' => 118, + '຺' => 9, + '່' => 122, + '້' => 122, + '໊' => 122, + '໋' => 122, + '༘' => 220, + '༙' => 220, + '༵' => 220, + '༷' => 220, + '༹' => 216, + 'ཱ' => 129, + 'ི' => 130, + 'ུ' => 132, + 'ེ' => 130, + 'ཻ' => 130, + 'ོ' => 130, + 'ཽ' => 130, + 'ྀ' => 130, + 'ྂ' => 230, + 'ྃ' => 230, + '྄' => 9, + '྆' => 230, + '྇' => 230, + '࿆' => 220, + '့' => 7, + '္' => 9, + '်' => 9, + 'ႍ' => 220, + '፝' => 230, + '፞' => 230, + '፟' => 230, + '᜔' => 9, + '᜴' => 9, + '្' => 9, + '៝' => 230, + 'ᢩ' => 228, + '᤹' => 222, + '᤺' => 230, + '᤻' => 220, + 'ᨗ' => 230, + 'ᨘ' => 220, + '᩠' => 9, + '᩵' => 230, + '᩶' => 230, + '᩷' => 230, + '᩸' => 230, + '᩹' => 230, + '᩺' => 230, + '᩻' => 230, + '᩼' => 230, + '᩿' => 220, + '᪰' => 230, + '᪱' => 230, + '᪲' => 230, + '᪳' => 230, + '᪴' => 230, + '᪵' => 220, + '᪶' => 220, + '᪷' => 220, + '᪸' => 220, + '᪹' => 220, + '᪺' => 220, + '᪻' => 230, + '᪼' => 230, + '᪽' => 220, + 'ᪿ' => 220, + 'ᫀ' => 220, + '᬴' => 7, + '᭄' => 9, + '᭫' => 230, + '᭬' => 220, + '᭭' => 230, + '᭮' => 230, + '᭯' => 230, + '᭰' => 230, + '᭱' => 230, + '᭲' => 230, + '᭳' => 230, + '᮪' => 9, + '᮫' => 9, + '᯦' => 7, + '᯲' => 9, + '᯳' => 9, + '᰷' => 7, + '᳐' => 230, + '᳑' => 230, + '᳒' => 230, + '᳔' => 1, + '᳕' => 220, + '᳖' => 220, + '᳗' => 220, + '᳘' => 220, + '᳙' => 220, + '᳚' => 230, + '᳛' => 230, + '᳜' => 220, + '᳝' => 220, + '᳞' => 220, + '᳟' => 220, + '᳠' => 230, + '᳢' => 1, + '᳣' => 1, + '᳤' => 1, + '᳥' => 1, + '᳦' => 1, + '᳧' => 1, + '᳨' => 1, + '᳭' => 220, + '᳴' => 230, + '᳸' => 230, + '᳹' => 230, + '᷀' => 230, + '᷁' => 230, + '᷂' => 220, + '᷃' => 230, + '᷄' => 230, + '᷅' => 230, + '᷆' => 230, + '᷇' => 230, + '᷈' => 230, + '᷉' => 230, + '᷊' => 220, + '᷋' => 230, + '᷌' => 230, + '᷍' => 234, + '᷎' => 214, + '᷏' => 220, + '᷐' => 202, + '᷑' => 230, + '᷒' => 230, + 'ᷓ' => 230, + 'ᷔ' => 230, + 'ᷕ' => 230, + 'ᷖ' => 230, + 'ᷗ' => 230, + 'ᷘ' => 230, + 'ᷙ' => 230, + 'ᷚ' => 230, + 'ᷛ' => 230, + 'ᷜ' => 230, + 'ᷝ' => 230, + 'ᷞ' => 230, + 'ᷟ' => 230, + 'ᷠ' => 230, + 'ᷡ' => 230, + 'ᷢ' => 230, + 'ᷣ' => 230, + 'ᷤ' => 230, + 'ᷥ' => 230, + 'ᷦ' => 230, + 'ᷧ' => 230, + 'ᷨ' => 230, + 'ᷩ' => 230, + 'ᷪ' => 230, + 'ᷫ' => 230, + 'ᷬ' => 230, + 'ᷭ' => 230, + 'ᷮ' => 230, + 'ᷯ' => 230, + 'ᷰ' => 230, + 'ᷱ' => 230, + 'ᷲ' => 230, + 'ᷳ' => 230, + 'ᷴ' => 230, + '᷵' => 230, + '᷶' => 232, + '᷷' => 228, + '᷸' => 228, + '᷹' => 220, + '᷻' => 230, + '᷼' => 233, + '᷽' => 220, + '᷾' => 230, + '᷿' => 220, + '⃐' => 230, + '⃑' => 230, + '⃒' => 1, + '⃓' => 1, + '⃔' => 230, + '⃕' => 230, + '⃖' => 230, + '⃗' => 230, + '⃘' => 1, + '⃙' => 1, + '⃚' => 1, + '⃛' => 230, + '⃜' => 230, + '⃡' => 230, + '⃥' => 1, + '⃦' => 1, + '⃧' => 230, + '⃨' => 220, + '⃩' => 230, + '⃪' => 1, + '⃫' => 1, + '⃬' => 220, + '⃭' => 220, + '⃮' => 220, + '⃯' => 220, + '⃰' => 230, + '⳯' => 230, + '⳰' => 230, + '⳱' => 230, + '⵿' => 9, + 'ⷠ' => 230, + 'ⷡ' => 230, + 'ⷢ' => 230, + 'ⷣ' => 230, + 'ⷤ' => 230, + 'ⷥ' => 230, + 'ⷦ' => 230, + 'ⷧ' => 230, + 'ⷨ' => 230, + 'ⷩ' => 230, + 'ⷪ' => 230, + 'ⷫ' => 230, + 'ⷬ' => 230, + 'ⷭ' => 230, + 'ⷮ' => 230, + 'ⷯ' => 230, + 'ⷰ' => 230, + 'ⷱ' => 230, + 'ⷲ' => 230, + 'ⷳ' => 230, + 'ⷴ' => 230, + 'ⷵ' => 230, + 'ⷶ' => 230, + 'ⷷ' => 230, + 'ⷸ' => 230, + 'ⷹ' => 230, + 'ⷺ' => 230, + 'ⷻ' => 230, + 'ⷼ' => 230, + 'ⷽ' => 230, + 'ⷾ' => 230, + 'ⷿ' => 230, + '〪' => 218, + '〫' => 228, + '〬' => 232, + '〭' => 222, + '〮' => 224, + '〯' => 224, + '゙' => 8, + '゚' => 8, + '꙯' => 230, + 'ꙴ' => 230, + 'ꙵ' => 230, + 'ꙶ' => 230, + 'ꙷ' => 230, + 'ꙸ' => 230, + 'ꙹ' => 230, + 'ꙺ' => 230, + 'ꙻ' => 230, + '꙼' => 230, + '꙽' => 230, + 'ꚞ' => 230, + 'ꚟ' => 230, + '꛰' => 230, + '꛱' => 230, + '꠆' => 9, + '꠬' => 9, + '꣄' => 9, + '꣠' => 230, + '꣡' => 230, + '꣢' => 230, + '꣣' => 230, + '꣤' => 230, + '꣥' => 230, + '꣦' => 230, + '꣧' => 230, + '꣨' => 230, + '꣩' => 230, + '꣪' => 230, + '꣫' => 230, + '꣬' => 230, + '꣭' => 230, + '꣮' => 230, + '꣯' => 230, + '꣰' => 230, + '꣱' => 230, + '꤫' => 220, + '꤬' => 220, + '꤭' => 220, + '꥓' => 9, + '꦳' => 7, + '꧀' => 9, + 'ꪰ' => 230, + 'ꪲ' => 230, + 'ꪳ' => 230, + 'ꪴ' => 220, + 'ꪷ' => 230, + 'ꪸ' => 230, + 'ꪾ' => 230, + '꪿' => 230, + '꫁' => 230, + '꫶' => 9, + '꯭' => 9, + 'ﬞ' => 26, + '︠' => 230, + '︡' => 230, + '︢' => 230, + '︣' => 230, + '︤' => 230, + '︥' => 230, + '︦' => 230, + '︧' => 220, + '︨' => 220, + '︩' => 220, + '︪' => 220, + '︫' => 220, + '︬' => 220, + '︭' => 220, + '︮' => 230, + '︯' => 230, + '𐇽' => 220, + '𐋠' => 220, + '𐍶' => 230, + '𐍷' => 230, + '𐍸' => 230, + '𐍹' => 230, + '𐍺' => 230, + '𐨍' => 220, + '𐨏' => 230, + '𐨸' => 230, + '𐨹' => 1, + '𐨺' => 220, + '𐨿' => 9, + '𐫥' => 230, + '𐫦' => 220, + '𐴤' => 230, + '𐴥' => 230, + '𐴦' => 230, + '𐴧' => 230, + '𐺫' => 230, + '𐺬' => 230, + '𐽆' => 220, + '𐽇' => 220, + '𐽈' => 230, + '𐽉' => 230, + '𐽊' => 230, + '𐽋' => 220, + '𐽌' => 230, + '𐽍' => 220, + '𐽎' => 220, + '𐽏' => 220, + '𐽐' => 220, + '𑁆' => 9, + '𑁿' => 9, + '𑂹' => 9, + '𑂺' => 7, + '𑄀' => 230, + '𑄁' => 230, + '𑄂' => 230, + '𑄳' => 9, + '𑄴' => 9, + '𑅳' => 7, + '𑇀' => 9, + '𑇊' => 7, + '𑈵' => 9, + '𑈶' => 7, + '𑋩' => 7, + '𑋪' => 9, + '𑌻' => 7, + '𑌼' => 7, + '𑍍' => 9, + '𑍦' => 230, + '𑍧' => 230, + '𑍨' => 230, + '𑍩' => 230, + '𑍪' => 230, + '𑍫' => 230, + '𑍬' => 230, + '𑍰' => 230, + '𑍱' => 230, + '𑍲' => 230, + '𑍳' => 230, + '𑍴' => 230, + '𑑂' => 9, + '𑑆' => 7, + '𑑞' => 230, + '𑓂' => 9, + '𑓃' => 7, + '𑖿' => 9, + '𑗀' => 7, + '𑘿' => 9, + '𑚶' => 9, + '𑚷' => 7, + '𑜫' => 9, + '𑠹' => 9, + '𑠺' => 7, + '𑤽' => 9, + '𑤾' => 9, + '𑥃' => 7, + '𑧠' => 9, + '𑨴' => 9, + '𑩇' => 9, + '𑪙' => 9, + '𑰿' => 9, + '𑵂' => 7, + '𑵄' => 9, + '𑵅' => 9, + '𑶗' => 9, + '𖫰' => 1, + '𖫱' => 1, + '𖫲' => 1, + '𖫳' => 1, + '𖫴' => 1, + '𖬰' => 230, + '𖬱' => 230, + '𖬲' => 230, + '𖬳' => 230, + '𖬴' => 230, + '𖬵' => 230, + '𖬶' => 230, + '𖿰' => 6, + '𖿱' => 6, + '𛲞' => 1, + '𝅥' => 216, + '𝅦' => 216, + '𝅧' => 1, + '𝅨' => 1, + '𝅩' => 1, + '𝅭' => 226, + '𝅮' => 216, + '𝅯' => 216, + '𝅰' => 216, + '𝅱' => 216, + '𝅲' => 216, + '𝅻' => 220, + '𝅼' => 220, + '𝅽' => 220, + '𝅾' => 220, + '𝅿' => 220, + '𝆀' => 220, + '𝆁' => 220, + '𝆂' => 220, + '𝆅' => 230, + '𝆆' => 230, + '𝆇' => 230, + '𝆈' => 230, + '𝆉' => 230, + '𝆊' => 220, + '𝆋' => 220, + '𝆪' => 230, + '𝆫' => 230, + '𝆬' => 230, + '𝆭' => 230, + '𝉂' => 230, + '𝉃' => 230, + '𝉄' => 230, + '𞀀' => 230, + '𞀁' => 230, + '𞀂' => 230, + '𞀃' => 230, + '𞀄' => 230, + '𞀅' => 230, + '𞀆' => 230, + '𞀈' => 230, + '𞀉' => 230, + '𞀊' => 230, + '𞀋' => 230, + '𞀌' => 230, + '𞀍' => 230, + '𞀎' => 230, + '𞀏' => 230, + '𞀐' => 230, + '𞀑' => 230, + '𞀒' => 230, + '𞀓' => 230, + '𞀔' => 230, + '𞀕' => 230, + '𞀖' => 230, + '𞀗' => 230, + '𞀘' => 230, + '𞀛' => 230, + '𞀜' => 230, + '𞀝' => 230, + '𞀞' => 230, + '𞀟' => 230, + '𞀠' => 230, + '𞀡' => 230, + '𞀣' => 230, + '𞀤' => 230, + '𞀦' => 230, + '𞀧' => 230, + '𞀨' => 230, + '𞀩' => 230, + '𞀪' => 230, + '𞄰' => 230, + '𞄱' => 230, + '𞄲' => 230, + '𞄳' => 230, + '𞄴' => 230, + '𞄵' => 230, + '𞄶' => 230, + '𞋬' => 230, + '𞋭' => 230, + '𞋮' => 230, + '𞋯' => 230, + '𞣐' => 220, + '𞣑' => 220, + '𞣒' => 220, + '𞣓' => 220, + '𞣔' => 220, + '𞣕' => 220, + '𞣖' => 220, + '𞥄' => 230, + '𞥅' => 230, + '𞥆' => 230, + '𞥇' => 230, + '𞥈' => 230, + '𞥉' => 230, + '𞥊' => 7, +); diff --git a/tools/mailer/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php b/tools/mailer/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php new file mode 100644 index 000000000..157490289 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php @@ -0,0 +1,3695 @@ + ' ', + '¨' => ' ̈', + 'ª' => 'a', + '¯' => ' ̄', + '²' => '2', + '³' => '3', + '´' => ' ́', + 'µ' => 'μ', + '¸' => ' ̧', + '¹' => '1', + 'º' => 'o', + '¼' => '1⁄4', + '½' => '1⁄2', + '¾' => '3⁄4', + 'IJ' => 'IJ', + 'ij' => 'ij', + 'Ŀ' => 'L·', + 'ŀ' => 'l·', + 'ʼn' => 'ʼn', + 'ſ' => 's', + 'DŽ' => 'DŽ', + 'Dž' => 'Dž', + 'dž' => 'dž', + 'LJ' => 'LJ', + 'Lj' => 'Lj', + 'lj' => 'lj', + 'NJ' => 'NJ', + 'Nj' => 'Nj', + 'nj' => 'nj', + 'DZ' => 'DZ', + 'Dz' => 'Dz', + 'dz' => 'dz', + 'ʰ' => 'h', + 'ʱ' => 'ɦ', + 'ʲ' => 'j', + 'ʳ' => 'r', + 'ʴ' => 'ɹ', + 'ʵ' => 'ɻ', + 'ʶ' => 'ʁ', + 'ʷ' => 'w', + 'ʸ' => 'y', + '˘' => ' ̆', + '˙' => ' ̇', + '˚' => ' ̊', + '˛' => ' ̨', + '˜' => ' ̃', + '˝' => ' ̋', + 'ˠ' => 'ɣ', + 'ˡ' => 'l', + 'ˢ' => 's', + 'ˣ' => 'x', + 'ˤ' => 'ʕ', + 'ͺ' => ' ͅ', + '΄' => ' ́', + '΅' => ' ̈́', + 'ϐ' => 'β', + 'ϑ' => 'θ', + 'ϒ' => 'Υ', + 'ϓ' => 'Ύ', + 'ϔ' => 'Ϋ', + 'ϕ' => 'φ', + 'ϖ' => 'π', + 'ϰ' => 'κ', + 'ϱ' => 'ρ', + 'ϲ' => 'ς', + 'ϴ' => 'Θ', + 'ϵ' => 'ε', + 'Ϲ' => 'Σ', + 'և' => 'եւ', + 'ٵ' => 'اٴ', + 'ٶ' => 'وٴ', + 'ٷ' => 'ۇٴ', + 'ٸ' => 'يٴ', + 'ำ' => 'ํา', + 'ຳ' => 'ໍາ', + 'ໜ' => 'ຫນ', + 'ໝ' => 'ຫມ', + '༌' => '་', + 'ཷ' => 'ྲཱྀ', + 'ཹ' => 'ླཱྀ', + 'ჼ' => 'ნ', + 'ᴬ' => 'A', + 'ᴭ' => 'Æ', + 'ᴮ' => 'B', + 'ᴰ' => 'D', + 'ᴱ' => 'E', + 'ᴲ' => 'Ǝ', + 'ᴳ' => 'G', + 'ᴴ' => 'H', + 'ᴵ' => 'I', + 'ᴶ' => 'J', + 'ᴷ' => 'K', + 'ᴸ' => 'L', + 'ᴹ' => 'M', + 'ᴺ' => 'N', + 'ᴼ' => 'O', + 'ᴽ' => 'Ȣ', + 'ᴾ' => 'P', + 'ᴿ' => 'R', + 'ᵀ' => 'T', + 'ᵁ' => 'U', + 'ᵂ' => 'W', + 'ᵃ' => 'a', + 'ᵄ' => 'ɐ', + 'ᵅ' => 'ɑ', + 'ᵆ' => 'ᴂ', + 'ᵇ' => 'b', + 'ᵈ' => 'd', + 'ᵉ' => 'e', + 'ᵊ' => 'ə', + 'ᵋ' => 'ɛ', + 'ᵌ' => 'ɜ', + 'ᵍ' => 'g', + 'ᵏ' => 'k', + 'ᵐ' => 'm', + 'ᵑ' => 'ŋ', + 'ᵒ' => 'o', + 'ᵓ' => 'ɔ', + 'ᵔ' => 'ᴖ', + 'ᵕ' => 'ᴗ', + 'ᵖ' => 'p', + 'ᵗ' => 't', + 'ᵘ' => 'u', + 'ᵙ' => 'ᴝ', + 'ᵚ' => 'ɯ', + 'ᵛ' => 'v', + 'ᵜ' => 'ᴥ', + 'ᵝ' => 'β', + 'ᵞ' => 'γ', + 'ᵟ' => 'δ', + 'ᵠ' => 'φ', + 'ᵡ' => 'χ', + 'ᵢ' => 'i', + 'ᵣ' => 'r', + 'ᵤ' => 'u', + 'ᵥ' => 'v', + 'ᵦ' => 'β', + 'ᵧ' => 'γ', + 'ᵨ' => 'ρ', + 'ᵩ' => 'φ', + 'ᵪ' => 'χ', + 'ᵸ' => 'н', + 'ᶛ' => 'ɒ', + 'ᶜ' => 'c', + 'ᶝ' => 'ɕ', + 'ᶞ' => 'ð', + 'ᶟ' => 'ɜ', + 'ᶠ' => 'f', + 'ᶡ' => 'ɟ', + 'ᶢ' => 'ɡ', + 'ᶣ' => 'ɥ', + 'ᶤ' => 'ɨ', + 'ᶥ' => 'ɩ', + 'ᶦ' => 'ɪ', + 'ᶧ' => 'ᵻ', + 'ᶨ' => 'ʝ', + 'ᶩ' => 'ɭ', + 'ᶪ' => 'ᶅ', + 'ᶫ' => 'ʟ', + 'ᶬ' => 'ɱ', + 'ᶭ' => 'ɰ', + 'ᶮ' => 'ɲ', + 'ᶯ' => 'ɳ', + 'ᶰ' => 'ɴ', + 'ᶱ' => 'ɵ', + 'ᶲ' => 'ɸ', + 'ᶳ' => 'ʂ', + 'ᶴ' => 'ʃ', + 'ᶵ' => 'ƫ', + 'ᶶ' => 'ʉ', + 'ᶷ' => 'ʊ', + 'ᶸ' => 'ᴜ', + 'ᶹ' => 'ʋ', + 'ᶺ' => 'ʌ', + 'ᶻ' => 'z', + 'ᶼ' => 'ʐ', + 'ᶽ' => 'ʑ', + 'ᶾ' => 'ʒ', + 'ᶿ' => 'θ', + 'ẚ' => 'aʾ', + 'ẛ' => 'ṡ', + '᾽' => ' ̓', + '᾿' => ' ̓', + '῀' => ' ͂', + '῁' => ' ̈͂', + '῍' => ' ̓̀', + '῎' => ' ̓́', + '῏' => ' ̓͂', + '῝' => ' ̔̀', + '῞' => ' ̔́', + '῟' => ' ̔͂', + '῭' => ' ̈̀', + '΅' => ' ̈́', + '´' => ' ́', + '῾' => ' ̔', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + '‑' => '‐', + '‗' => ' ̳', + '․' => '.', + '‥' => '..', + '…' => '...', + ' ' => ' ', + '″' => '′′', + '‴' => '′′′', + '‶' => '‵‵', + '‷' => '‵‵‵', + '‼' => '!!', + '‾' => ' ̅', + '⁇' => '??', + '⁈' => '?!', + '⁉' => '!?', + '⁗' => '′′′′', + ' ' => ' ', + '⁰' => '0', + 'ⁱ' => 'i', + '⁴' => '4', + '⁵' => '5', + '⁶' => '6', + '⁷' => '7', + '⁸' => '8', + '⁹' => '9', + '⁺' => '+', + '⁻' => '−', + '⁼' => '=', + '⁽' => '(', + '⁾' => ')', + 'ⁿ' => 'n', + '₀' => '0', + '₁' => '1', + '₂' => '2', + '₃' => '3', + '₄' => '4', + '₅' => '5', + '₆' => '6', + '₇' => '7', + '₈' => '8', + '₉' => '9', + '₊' => '+', + '₋' => '−', + '₌' => '=', + '₍' => '(', + '₎' => ')', + 'ₐ' => 'a', + 'ₑ' => 'e', + 'ₒ' => 'o', + 'ₓ' => 'x', + 'ₔ' => 'ə', + 'ₕ' => 'h', + 'ₖ' => 'k', + 'ₗ' => 'l', + 'ₘ' => 'm', + 'ₙ' => 'n', + 'ₚ' => 'p', + 'ₛ' => 's', + 'ₜ' => 't', + '₨' => 'Rs', + '℀' => 'a/c', + '℁' => 'a/s', + 'ℂ' => 'C', + '℃' => '°C', + '℅' => 'c/o', + '℆' => 'c/u', + 'ℇ' => 'Ɛ', + '℉' => '°F', + 'ℊ' => 'g', + 'ℋ' => 'H', + 'ℌ' => 'H', + 'ℍ' => 'H', + 'ℎ' => 'h', + 'ℏ' => 'ħ', + 'ℐ' => 'I', + 'ℑ' => 'I', + 'ℒ' => 'L', + 'ℓ' => 'l', + 'ℕ' => 'N', + '№' => 'No', + 'ℙ' => 'P', + 'ℚ' => 'Q', + 'ℛ' => 'R', + 'ℜ' => 'R', + 'ℝ' => 'R', + '℠' => 'SM', + '℡' => 'TEL', + '™' => 'TM', + 'ℤ' => 'Z', + 'ℨ' => 'Z', + 'ℬ' => 'B', + 'ℭ' => 'C', + 'ℯ' => 'e', + 'ℰ' => 'E', + 'ℱ' => 'F', + 'ℳ' => 'M', + 'ℴ' => 'o', + 'ℵ' => 'א', + 'ℶ' => 'ב', + 'ℷ' => 'ג', + 'ℸ' => 'ד', + 'ℹ' => 'i', + '℻' => 'FAX', + 'ℼ' => 'π', + 'ℽ' => 'γ', + 'ℾ' => 'Γ', + 'ℿ' => 'Π', + '⅀' => '∑', + 'ⅅ' => 'D', + 'ⅆ' => 'd', + 'ⅇ' => 'e', + 'ⅈ' => 'i', + 'ⅉ' => 'j', + '⅐' => '1⁄7', + '⅑' => '1⁄9', + '⅒' => '1⁄10', + '⅓' => '1⁄3', + '⅔' => '2⁄3', + '⅕' => '1⁄5', + '⅖' => '2⁄5', + '⅗' => '3⁄5', + '⅘' => '4⁄5', + '⅙' => '1⁄6', + '⅚' => '5⁄6', + '⅛' => '1⁄8', + '⅜' => '3⁄8', + '⅝' => '5⁄8', + '⅞' => '7⁄8', + '⅟' => '1⁄', + 'Ⅰ' => 'I', + 'Ⅱ' => 'II', + 'Ⅲ' => 'III', + 'Ⅳ' => 'IV', + 'Ⅴ' => 'V', + 'Ⅵ' => 'VI', + 'Ⅶ' => 'VII', + 'Ⅷ' => 'VIII', + 'Ⅸ' => 'IX', + 'Ⅹ' => 'X', + 'Ⅺ' => 'XI', + 'Ⅻ' => 'XII', + 'Ⅼ' => 'L', + 'Ⅽ' => 'C', + 'Ⅾ' => 'D', + 'Ⅿ' => 'M', + 'ⅰ' => 'i', + 'ⅱ' => 'ii', + 'ⅲ' => 'iii', + 'ⅳ' => 'iv', + 'ⅴ' => 'v', + 'ⅵ' => 'vi', + 'ⅶ' => 'vii', + 'ⅷ' => 'viii', + 'ⅸ' => 'ix', + 'ⅹ' => 'x', + 'ⅺ' => 'xi', + 'ⅻ' => 'xii', + 'ⅼ' => 'l', + 'ⅽ' => 'c', + 'ⅾ' => 'd', + 'ⅿ' => 'm', + '↉' => '0⁄3', + '∬' => '∫∫', + '∭' => '∫∫∫', + '∯' => '∮∮', + '∰' => '∮∮∮', + '①' => '1', + '②' => '2', + '③' => '3', + '④' => '4', + '⑤' => '5', + '⑥' => '6', + '⑦' => '7', + '⑧' => '8', + '⑨' => '9', + '⑩' => '10', + '⑪' => '11', + '⑫' => '12', + '⑬' => '13', + '⑭' => '14', + '⑮' => '15', + '⑯' => '16', + '⑰' => '17', + '⑱' => '18', + '⑲' => '19', + '⑳' => '20', + '⑴' => '(1)', + '⑵' => '(2)', + '⑶' => '(3)', + '⑷' => '(4)', + '⑸' => '(5)', + '⑹' => '(6)', + '⑺' => '(7)', + '⑻' => '(8)', + '⑼' => '(9)', + '⑽' => '(10)', + '⑾' => '(11)', + '⑿' => '(12)', + '⒀' => '(13)', + '⒁' => '(14)', + '⒂' => '(15)', + '⒃' => '(16)', + '⒄' => '(17)', + '⒅' => '(18)', + '⒆' => '(19)', + '⒇' => '(20)', + '⒈' => '1.', + '⒉' => '2.', + '⒊' => '3.', + '⒋' => '4.', + '⒌' => '5.', + '⒍' => '6.', + '⒎' => '7.', + '⒏' => '8.', + '⒐' => '9.', + '⒑' => '10.', + '⒒' => '11.', + '⒓' => '12.', + '⒔' => '13.', + '⒕' => '14.', + '⒖' => '15.', + '⒗' => '16.', + '⒘' => '17.', + '⒙' => '18.', + '⒚' => '19.', + '⒛' => '20.', + '⒜' => '(a)', + '⒝' => '(b)', + '⒞' => '(c)', + '⒟' => '(d)', + '⒠' => '(e)', + '⒡' => '(f)', + '⒢' => '(g)', + '⒣' => '(h)', + '⒤' => '(i)', + '⒥' => '(j)', + '⒦' => '(k)', + '⒧' => '(l)', + '⒨' => '(m)', + '⒩' => '(n)', + '⒪' => '(o)', + '⒫' => '(p)', + '⒬' => '(q)', + '⒭' => '(r)', + '⒮' => '(s)', + '⒯' => '(t)', + '⒰' => '(u)', + '⒱' => '(v)', + '⒲' => '(w)', + '⒳' => '(x)', + '⒴' => '(y)', + '⒵' => '(z)', + 'Ⓐ' => 'A', + 'Ⓑ' => 'B', + 'Ⓒ' => 'C', + 'Ⓓ' => 'D', + 'Ⓔ' => 'E', + 'Ⓕ' => 'F', + 'Ⓖ' => 'G', + 'Ⓗ' => 'H', + 'Ⓘ' => 'I', + 'Ⓙ' => 'J', + 'Ⓚ' => 'K', + 'Ⓛ' => 'L', + 'Ⓜ' => 'M', + 'Ⓝ' => 'N', + 'Ⓞ' => 'O', + 'Ⓟ' => 'P', + 'Ⓠ' => 'Q', + 'Ⓡ' => 'R', + 'Ⓢ' => 'S', + 'Ⓣ' => 'T', + 'Ⓤ' => 'U', + 'Ⓥ' => 'V', + 'Ⓦ' => 'W', + 'Ⓧ' => 'X', + 'Ⓨ' => 'Y', + 'Ⓩ' => 'Z', + 'ⓐ' => 'a', + 'ⓑ' => 'b', + 'ⓒ' => 'c', + 'ⓓ' => 'd', + 'ⓔ' => 'e', + 'ⓕ' => 'f', + 'ⓖ' => 'g', + 'ⓗ' => 'h', + 'ⓘ' => 'i', + 'ⓙ' => 'j', + 'ⓚ' => 'k', + 'ⓛ' => 'l', + 'ⓜ' => 'm', + 'ⓝ' => 'n', + 'ⓞ' => 'o', + 'ⓟ' => 'p', + 'ⓠ' => 'q', + 'ⓡ' => 'r', + 'ⓢ' => 's', + 'ⓣ' => 't', + 'ⓤ' => 'u', + 'ⓥ' => 'v', + 'ⓦ' => 'w', + 'ⓧ' => 'x', + 'ⓨ' => 'y', + 'ⓩ' => 'z', + '⓪' => '0', + '⨌' => '∫∫∫∫', + '⩴' => '::=', + '⩵' => '==', + '⩶' => '===', + 'ⱼ' => 'j', + 'ⱽ' => 'V', + 'ⵯ' => 'ⵡ', + '⺟' => '母', + '⻳' => '龟', + '⼀' => '一', + '⼁' => '丨', + '⼂' => '丶', + '⼃' => '丿', + '⼄' => '乙', + '⼅' => '亅', + '⼆' => '二', + '⼇' => '亠', + '⼈' => '人', + '⼉' => '儿', + '⼊' => '入', + '⼋' => '八', + '⼌' => '冂', + '⼍' => '冖', + '⼎' => '冫', + '⼏' => '几', + '⼐' => '凵', + '⼑' => '刀', + '⼒' => '力', + '⼓' => '勹', + '⼔' => '匕', + '⼕' => '匚', + '⼖' => '匸', + '⼗' => '十', + '⼘' => '卜', + '⼙' => '卩', + '⼚' => '厂', + '⼛' => '厶', + '⼜' => '又', + '⼝' => '口', + '⼞' => '囗', + '⼟' => '土', + '⼠' => '士', + '⼡' => '夂', + '⼢' => '夊', + '⼣' => '夕', + '⼤' => '大', + '⼥' => '女', + '⼦' => '子', + '⼧' => '宀', + '⼨' => '寸', + '⼩' => '小', + '⼪' => '尢', + '⼫' => '尸', + '⼬' => '屮', + '⼭' => '山', + '⼮' => '巛', + '⼯' => '工', + '⼰' => '己', + '⼱' => '巾', + '⼲' => '干', + '⼳' => '幺', + '⼴' => '广', + '⼵' => '廴', + '⼶' => '廾', + '⼷' => '弋', + '⼸' => '弓', + '⼹' => '彐', + '⼺' => '彡', + '⼻' => '彳', + '⼼' => '心', + '⼽' => '戈', + '⼾' => '戶', + '⼿' => '手', + '⽀' => '支', + '⽁' => '攴', + '⽂' => '文', + '⽃' => '斗', + '⽄' => '斤', + '⽅' => '方', + '⽆' => '无', + '⽇' => '日', + '⽈' => '曰', + '⽉' => '月', + '⽊' => '木', + '⽋' => '欠', + '⽌' => '止', + '⽍' => '歹', + '⽎' => '殳', + '⽏' => '毋', + '⽐' => '比', + '⽑' => '毛', + '⽒' => '氏', + '⽓' => '气', + '⽔' => '水', + '⽕' => '火', + '⽖' => '爪', + '⽗' => '父', + '⽘' => '爻', + '⽙' => '爿', + '⽚' => '片', + '⽛' => '牙', + '⽜' => '牛', + '⽝' => '犬', + '⽞' => '玄', + '⽟' => '玉', + '⽠' => '瓜', + '⽡' => '瓦', + '⽢' => '甘', + '⽣' => '生', + '⽤' => '用', + '⽥' => '田', + '⽦' => '疋', + '⽧' => '疒', + '⽨' => '癶', + '⽩' => '白', + '⽪' => '皮', + '⽫' => '皿', + '⽬' => '目', + '⽭' => '矛', + '⽮' => '矢', + '⽯' => '石', + '⽰' => '示', + '⽱' => '禸', + '⽲' => '禾', + '⽳' => '穴', + '⽴' => '立', + '⽵' => '竹', + '⽶' => '米', + '⽷' => '糸', + '⽸' => '缶', + '⽹' => '网', + '⽺' => '羊', + '⽻' => '羽', + '⽼' => '老', + '⽽' => '而', + '⽾' => '耒', + '⽿' => '耳', + '⾀' => '聿', + '⾁' => '肉', + '⾂' => '臣', + '⾃' => '自', + '⾄' => '至', + '⾅' => '臼', + '⾆' => '舌', + '⾇' => '舛', + '⾈' => '舟', + '⾉' => '艮', + '⾊' => '色', + '⾋' => '艸', + '⾌' => '虍', + '⾍' => '虫', + '⾎' => '血', + '⾏' => '行', + '⾐' => '衣', + '⾑' => '襾', + '⾒' => '見', + '⾓' => '角', + '⾔' => '言', + '⾕' => '谷', + '⾖' => '豆', + '⾗' => '豕', + '⾘' => '豸', + '⾙' => '貝', + '⾚' => '赤', + '⾛' => '走', + '⾜' => '足', + '⾝' => '身', + '⾞' => '車', + '⾟' => '辛', + '⾠' => '辰', + '⾡' => '辵', + '⾢' => '邑', + '⾣' => '酉', + '⾤' => '釆', + '⾥' => '里', + '⾦' => '金', + '⾧' => '長', + '⾨' => '門', + '⾩' => '阜', + '⾪' => '隶', + '⾫' => '隹', + '⾬' => '雨', + '⾭' => '靑', + '⾮' => '非', + '⾯' => '面', + '⾰' => '革', + '⾱' => '韋', + '⾲' => '韭', + '⾳' => '音', + '⾴' => '頁', + '⾵' => '風', + '⾶' => '飛', + '⾷' => '食', + '⾸' => '首', + '⾹' => '香', + '⾺' => '馬', + '⾻' => '骨', + '⾼' => '高', + '⾽' => '髟', + '⾾' => '鬥', + '⾿' => '鬯', + '⿀' => '鬲', + '⿁' => '鬼', + '⿂' => '魚', + '⿃' => '鳥', + '⿄' => '鹵', + '⿅' => '鹿', + '⿆' => '麥', + '⿇' => '麻', + '⿈' => '黃', + '⿉' => '黍', + '⿊' => '黑', + '⿋' => '黹', + '⿌' => '黽', + '⿍' => '鼎', + '⿎' => '鼓', + '⿏' => '鼠', + '⿐' => '鼻', + '⿑' => '齊', + '⿒' => '齒', + '⿓' => '龍', + '⿔' => '龜', + '⿕' => '龠', + ' ' => ' ', + '〶' => '〒', + '〸' => '十', + '〹' => '卄', + '〺' => '卅', + '゛' => ' ゙', + '゜' => ' ゚', + 'ゟ' => 'より', + 'ヿ' => 'コト', + 'ㄱ' => 'ᄀ', + 'ㄲ' => 'ᄁ', + 'ㄳ' => 'ᆪ', + 'ㄴ' => 'ᄂ', + 'ㄵ' => 'ᆬ', + 'ㄶ' => 'ᆭ', + 'ㄷ' => 'ᄃ', + 'ㄸ' => 'ᄄ', + 'ㄹ' => 'ᄅ', + 'ㄺ' => 'ᆰ', + 'ㄻ' => 'ᆱ', + 'ㄼ' => 'ᆲ', + 'ㄽ' => 'ᆳ', + 'ㄾ' => 'ᆴ', + 'ㄿ' => 'ᆵ', + 'ㅀ' => 'ᄚ', + 'ㅁ' => 'ᄆ', + 'ㅂ' => 'ᄇ', + 'ㅃ' => 'ᄈ', + 'ㅄ' => 'ᄡ', + 'ㅅ' => 'ᄉ', + 'ㅆ' => 'ᄊ', + 'ㅇ' => 'ᄋ', + 'ㅈ' => 'ᄌ', + 'ㅉ' => 'ᄍ', + 'ㅊ' => 'ᄎ', + 'ㅋ' => 'ᄏ', + 'ㅌ' => 'ᄐ', + 'ㅍ' => 'ᄑ', + 'ㅎ' => 'ᄒ', + 'ㅏ' => 'ᅡ', + 'ㅐ' => 'ᅢ', + 'ㅑ' => 'ᅣ', + 'ㅒ' => 'ᅤ', + 'ㅓ' => 'ᅥ', + 'ㅔ' => 'ᅦ', + 'ㅕ' => 'ᅧ', + 'ㅖ' => 'ᅨ', + 'ㅗ' => 'ᅩ', + 'ㅘ' => 'ᅪ', + 'ㅙ' => 'ᅫ', + 'ㅚ' => 'ᅬ', + 'ㅛ' => 'ᅭ', + 'ㅜ' => 'ᅮ', + 'ㅝ' => 'ᅯ', + 'ㅞ' => 'ᅰ', + 'ㅟ' => 'ᅱ', + 'ㅠ' => 'ᅲ', + 'ㅡ' => 'ᅳ', + 'ㅢ' => 'ᅴ', + 'ㅣ' => 'ᅵ', + 'ㅤ' => 'ᅠ', + 'ㅥ' => 'ᄔ', + 'ㅦ' => 'ᄕ', + 'ㅧ' => 'ᇇ', + 'ㅨ' => 'ᇈ', + 'ㅩ' => 'ᇌ', + 'ㅪ' => 'ᇎ', + 'ㅫ' => 'ᇓ', + 'ㅬ' => 'ᇗ', + 'ㅭ' => 'ᇙ', + 'ㅮ' => 'ᄜ', + 'ㅯ' => 'ᇝ', + 'ㅰ' => 'ᇟ', + 'ㅱ' => 'ᄝ', + 'ㅲ' => 'ᄞ', + 'ㅳ' => 'ᄠ', + 'ㅴ' => 'ᄢ', + 'ㅵ' => 'ᄣ', + 'ㅶ' => 'ᄧ', + 'ㅷ' => 'ᄩ', + 'ㅸ' => 'ᄫ', + 'ㅹ' => 'ᄬ', + 'ㅺ' => 'ᄭ', + 'ㅻ' => 'ᄮ', + 'ㅼ' => 'ᄯ', + 'ㅽ' => 'ᄲ', + 'ㅾ' => 'ᄶ', + 'ㅿ' => 'ᅀ', + 'ㆀ' => 'ᅇ', + 'ㆁ' => 'ᅌ', + 'ㆂ' => 'ᇱ', + 'ㆃ' => 'ᇲ', + 'ㆄ' => 'ᅗ', + 'ㆅ' => 'ᅘ', + 'ㆆ' => 'ᅙ', + 'ㆇ' => 'ᆄ', + 'ㆈ' => 'ᆅ', + 'ㆉ' => 'ᆈ', + 'ㆊ' => 'ᆑ', + 'ㆋ' => 'ᆒ', + 'ㆌ' => 'ᆔ', + 'ㆍ' => 'ᆞ', + 'ㆎ' => 'ᆡ', + '㆒' => '一', + '㆓' => '二', + '㆔' => '三', + '㆕' => '四', + '㆖' => '上', + '㆗' => '中', + '㆘' => '下', + '㆙' => '甲', + '㆚' => '乙', + '㆛' => '丙', + '㆜' => '丁', + '㆝' => '天', + '㆞' => '地', + '㆟' => '人', + '㈀' => '(ᄀ)', + '㈁' => '(ᄂ)', + '㈂' => '(ᄃ)', + '㈃' => '(ᄅ)', + '㈄' => '(ᄆ)', + '㈅' => '(ᄇ)', + '㈆' => '(ᄉ)', + '㈇' => '(ᄋ)', + '㈈' => '(ᄌ)', + '㈉' => '(ᄎ)', + '㈊' => '(ᄏ)', + '㈋' => '(ᄐ)', + '㈌' => '(ᄑ)', + '㈍' => '(ᄒ)', + '㈎' => '(가)', + '㈏' => '(나)', + '㈐' => '(다)', + '㈑' => '(라)', + '㈒' => '(마)', + '㈓' => '(바)', + '㈔' => '(사)', + '㈕' => '(아)', + '㈖' => '(자)', + '㈗' => '(차)', + '㈘' => '(카)', + '㈙' => '(타)', + '㈚' => '(파)', + '㈛' => '(하)', + '㈜' => '(주)', + '㈝' => '(오전)', + '㈞' => '(오후)', + '㈠' => '(一)', + '㈡' => '(二)', + '㈢' => '(三)', + '㈣' => '(四)', + '㈤' => '(五)', + '㈥' => '(六)', + '㈦' => '(七)', + '㈧' => '(八)', + '㈨' => '(九)', + '㈩' => '(十)', + '㈪' => '(月)', + '㈫' => '(火)', + '㈬' => '(水)', + '㈭' => '(木)', + '㈮' => '(金)', + '㈯' => '(土)', + '㈰' => '(日)', + '㈱' => '(株)', + '㈲' => '(有)', + '㈳' => '(社)', + '㈴' => '(名)', + '㈵' => '(特)', + '㈶' => '(財)', + '㈷' => '(祝)', + '㈸' => '(労)', + '㈹' => '(代)', + '㈺' => '(呼)', + '㈻' => '(学)', + '㈼' => '(監)', + '㈽' => '(企)', + '㈾' => '(資)', + '㈿' => '(協)', + '㉀' => '(祭)', + '㉁' => '(休)', + '㉂' => '(自)', + '㉃' => '(至)', + '㉄' => '問', + '㉅' => '幼', + '㉆' => '文', + '㉇' => '箏', + '㉐' => 'PTE', + '㉑' => '21', + '㉒' => '22', + '㉓' => '23', + '㉔' => '24', + '㉕' => '25', + '㉖' => '26', + '㉗' => '27', + '㉘' => '28', + '㉙' => '29', + '㉚' => '30', + '㉛' => '31', + '㉜' => '32', + '㉝' => '33', + '㉞' => '34', + '㉟' => '35', + '㉠' => 'ᄀ', + '㉡' => 'ᄂ', + '㉢' => 'ᄃ', + '㉣' => 'ᄅ', + '㉤' => 'ᄆ', + '㉥' => 'ᄇ', + '㉦' => 'ᄉ', + '㉧' => 'ᄋ', + '㉨' => 'ᄌ', + '㉩' => 'ᄎ', + '㉪' => 'ᄏ', + '㉫' => 'ᄐ', + '㉬' => 'ᄑ', + '㉭' => 'ᄒ', + '㉮' => '가', + '㉯' => '나', + '㉰' => '다', + '㉱' => '라', + '㉲' => '마', + '㉳' => '바', + '㉴' => '사', + '㉵' => '아', + '㉶' => '자', + '㉷' => '차', + '㉸' => '카', + '㉹' => '타', + '㉺' => '파', + '㉻' => '하', + '㉼' => '참고', + '㉽' => '주의', + '㉾' => '우', + '㊀' => '一', + '㊁' => '二', + '㊂' => '三', + '㊃' => '四', + '㊄' => '五', + '㊅' => '六', + '㊆' => '七', + '㊇' => '八', + '㊈' => '九', + '㊉' => '十', + '㊊' => '月', + '㊋' => '火', + '㊌' => '水', + '㊍' => '木', + '㊎' => '金', + '㊏' => '土', + '㊐' => '日', + '㊑' => '株', + '㊒' => '有', + '㊓' => '社', + '㊔' => '名', + '㊕' => '特', + '㊖' => '財', + '㊗' => '祝', + '㊘' => '労', + '㊙' => '秘', + '㊚' => '男', + '㊛' => '女', + '㊜' => '適', + '㊝' => '優', + '㊞' => '印', + '㊟' => '注', + '㊠' => '項', + '㊡' => '休', + '㊢' => '写', + '㊣' => '正', + '㊤' => '上', + '㊥' => '中', + '㊦' => '下', + '㊧' => '左', + '㊨' => '右', + '㊩' => '医', + '㊪' => '宗', + '㊫' => '学', + '㊬' => '監', + '㊭' => '企', + '㊮' => '資', + '㊯' => '協', + '㊰' => '夜', + '㊱' => '36', + '㊲' => '37', + '㊳' => '38', + '㊴' => '39', + '㊵' => '40', + '㊶' => '41', + '㊷' => '42', + '㊸' => '43', + '㊹' => '44', + '㊺' => '45', + '㊻' => '46', + '㊼' => '47', + '㊽' => '48', + '㊾' => '49', + '㊿' => '50', + '㋀' => '1月', + '㋁' => '2月', + '㋂' => '3月', + '㋃' => '4月', + '㋄' => '5月', + '㋅' => '6月', + '㋆' => '7月', + '㋇' => '8月', + '㋈' => '9月', + '㋉' => '10月', + '㋊' => '11月', + '㋋' => '12月', + '㋌' => 'Hg', + '㋍' => 'erg', + '㋎' => 'eV', + '㋏' => 'LTD', + '㋐' => 'ア', + '㋑' => 'イ', + '㋒' => 'ウ', + '㋓' => 'エ', + '㋔' => 'オ', + '㋕' => 'カ', + '㋖' => 'キ', + '㋗' => 'ク', + '㋘' => 'ケ', + '㋙' => 'コ', + '㋚' => 'サ', + '㋛' => 'シ', + '㋜' => 'ス', + '㋝' => 'セ', + '㋞' => 'ソ', + '㋟' => 'タ', + '㋠' => 'チ', + '㋡' => 'ツ', + '㋢' => 'テ', + '㋣' => 'ト', + '㋤' => 'ナ', + '㋥' => 'ニ', + '㋦' => 'ヌ', + '㋧' => 'ネ', + '㋨' => 'ノ', + '㋩' => 'ハ', + '㋪' => 'ヒ', + '㋫' => 'フ', + '㋬' => 'ヘ', + '㋭' => 'ホ', + '㋮' => 'マ', + '㋯' => 'ミ', + '㋰' => 'ム', + '㋱' => 'メ', + '㋲' => 'モ', + '㋳' => 'ヤ', + '㋴' => 'ユ', + '㋵' => 'ヨ', + '㋶' => 'ラ', + '㋷' => 'リ', + '㋸' => 'ル', + '㋹' => 'レ', + '㋺' => 'ロ', + '㋻' => 'ワ', + '㋼' => 'ヰ', + '㋽' => 'ヱ', + '㋾' => 'ヲ', + '㋿' => '令和', + '㌀' => 'アパート', + '㌁' => 'アルファ', + '㌂' => 'アンペア', + '㌃' => 'アール', + '㌄' => 'イニング', + '㌅' => 'インチ', + '㌆' => 'ウォン', + '㌇' => 'エスクード', + '㌈' => 'エーカー', + '㌉' => 'オンス', + '㌊' => 'オーム', + '㌋' => 'カイリ', + '㌌' => 'カラット', + '㌍' => 'カロリー', + '㌎' => 'ガロン', + '㌏' => 'ガンマ', + '㌐' => 'ギガ', + '㌑' => 'ギニー', + '㌒' => 'キュリー', + '㌓' => 'ギルダー', + '㌔' => 'キロ', + '㌕' => 'キログラム', + '㌖' => 'キロメートル', + '㌗' => 'キロワット', + '㌘' => 'グラム', + '㌙' => 'グラムトン', + '㌚' => 'クルゼイロ', + '㌛' => 'クローネ', + '㌜' => 'ケース', + '㌝' => 'コルナ', + '㌞' => 'コーポ', + '㌟' => 'サイクル', + '㌠' => 'サンチーム', + '㌡' => 'シリング', + '㌢' => 'センチ', + '㌣' => 'セント', + '㌤' => 'ダース', + '㌥' => 'デシ', + '㌦' => 'ドル', + '㌧' => 'トン', + '㌨' => 'ナノ', + '㌩' => 'ノット', + '㌪' => 'ハイツ', + '㌫' => 'パーセント', + '㌬' => 'パーツ', + '㌭' => 'バーレル', + '㌮' => 'ピアストル', + '㌯' => 'ピクル', + '㌰' => 'ピコ', + '㌱' => 'ビル', + '㌲' => 'ファラッド', + '㌳' => 'フィート', + '㌴' => 'ブッシェル', + '㌵' => 'フラン', + '㌶' => 'ヘクタール', + '㌷' => 'ペソ', + '㌸' => 'ペニヒ', + '㌹' => 'ヘルツ', + '㌺' => 'ペンス', + '㌻' => 'ページ', + '㌼' => 'ベータ', + '㌽' => 'ポイント', + '㌾' => 'ボルト', + '㌿' => 'ホン', + '㍀' => 'ポンド', + '㍁' => 'ホール', + '㍂' => 'ホーン', + '㍃' => 'マイクロ', + '㍄' => 'マイル', + '㍅' => 'マッハ', + '㍆' => 'マルク', + '㍇' => 'マンション', + '㍈' => 'ミクロン', + '㍉' => 'ミリ', + '㍊' => 'ミリバール', + '㍋' => 'メガ', + '㍌' => 'メガトン', + '㍍' => 'メートル', + '㍎' => 'ヤード', + '㍏' => 'ヤール', + '㍐' => 'ユアン', + '㍑' => 'リットル', + '㍒' => 'リラ', + '㍓' => 'ルピー', + '㍔' => 'ルーブル', + '㍕' => 'レム', + '㍖' => 'レントゲン', + '㍗' => 'ワット', + '㍘' => '0点', + '㍙' => '1点', + '㍚' => '2点', + '㍛' => '3点', + '㍜' => '4点', + '㍝' => '5点', + '㍞' => '6点', + '㍟' => '7点', + '㍠' => '8点', + '㍡' => '9点', + '㍢' => '10点', + '㍣' => '11点', + '㍤' => '12点', + '㍥' => '13点', + '㍦' => '14点', + '㍧' => '15点', + '㍨' => '16点', + '㍩' => '17点', + '㍪' => '18点', + '㍫' => '19点', + '㍬' => '20点', + '㍭' => '21点', + '㍮' => '22点', + '㍯' => '23点', + '㍰' => '24点', + '㍱' => 'hPa', + '㍲' => 'da', + '㍳' => 'AU', + '㍴' => 'bar', + '㍵' => 'oV', + '㍶' => 'pc', + '㍷' => 'dm', + '㍸' => 'dm2', + '㍹' => 'dm3', + '㍺' => 'IU', + '㍻' => '平成', + '㍼' => '昭和', + '㍽' => '大正', + '㍾' => '明治', + '㍿' => '株式会社', + '㎀' => 'pA', + '㎁' => 'nA', + '㎂' => 'μA', + '㎃' => 'mA', + '㎄' => 'kA', + '㎅' => 'KB', + '㎆' => 'MB', + '㎇' => 'GB', + '㎈' => 'cal', + '㎉' => 'kcal', + '㎊' => 'pF', + '㎋' => 'nF', + '㎌' => 'μF', + '㎍' => 'μg', + '㎎' => 'mg', + '㎏' => 'kg', + '㎐' => 'Hz', + '㎑' => 'kHz', + '㎒' => 'MHz', + '㎓' => 'GHz', + '㎔' => 'THz', + '㎕' => 'μl', + '㎖' => 'ml', + '㎗' => 'dl', + '㎘' => 'kl', + '㎙' => 'fm', + '㎚' => 'nm', + '㎛' => 'μm', + '㎜' => 'mm', + '㎝' => 'cm', + '㎞' => 'km', + '㎟' => 'mm2', + '㎠' => 'cm2', + '㎡' => 'm2', + '㎢' => 'km2', + '㎣' => 'mm3', + '㎤' => 'cm3', + '㎥' => 'm3', + '㎦' => 'km3', + '㎧' => 'm∕s', + '㎨' => 'm∕s2', + '㎩' => 'Pa', + '㎪' => 'kPa', + '㎫' => 'MPa', + '㎬' => 'GPa', + '㎭' => 'rad', + '㎮' => 'rad∕s', + '㎯' => 'rad∕s2', + '㎰' => 'ps', + '㎱' => 'ns', + '㎲' => 'μs', + '㎳' => 'ms', + '㎴' => 'pV', + '㎵' => 'nV', + '㎶' => 'μV', + '㎷' => 'mV', + '㎸' => 'kV', + '㎹' => 'MV', + '㎺' => 'pW', + '㎻' => 'nW', + '㎼' => 'μW', + '㎽' => 'mW', + '㎾' => 'kW', + '㎿' => 'MW', + '㏀' => 'kΩ', + '㏁' => 'MΩ', + '㏂' => 'a.m.', + '㏃' => 'Bq', + '㏄' => 'cc', + '㏅' => 'cd', + '㏆' => 'C∕kg', + '㏇' => 'Co.', + '㏈' => 'dB', + '㏉' => 'Gy', + '㏊' => 'ha', + '㏋' => 'HP', + '㏌' => 'in', + '㏍' => 'KK', + '㏎' => 'KM', + '㏏' => 'kt', + '㏐' => 'lm', + '㏑' => 'ln', + '㏒' => 'log', + '㏓' => 'lx', + '㏔' => 'mb', + '㏕' => 'mil', + '㏖' => 'mol', + '㏗' => 'PH', + '㏘' => 'p.m.', + '㏙' => 'PPM', + '㏚' => 'PR', + '㏛' => 'sr', + '㏜' => 'Sv', + '㏝' => 'Wb', + '㏞' => 'V∕m', + '㏟' => 'A∕m', + '㏠' => '1日', + '㏡' => '2日', + '㏢' => '3日', + '㏣' => '4日', + '㏤' => '5日', + '㏥' => '6日', + '㏦' => '7日', + '㏧' => '8日', + '㏨' => '9日', + '㏩' => '10日', + '㏪' => '11日', + '㏫' => '12日', + '㏬' => '13日', + '㏭' => '14日', + '㏮' => '15日', + '㏯' => '16日', + '㏰' => '17日', + '㏱' => '18日', + '㏲' => '19日', + '㏳' => '20日', + '㏴' => '21日', + '㏵' => '22日', + '㏶' => '23日', + '㏷' => '24日', + '㏸' => '25日', + '㏹' => '26日', + '㏺' => '27日', + '㏻' => '28日', + '㏼' => '29日', + '㏽' => '30日', + '㏾' => '31日', + '㏿' => 'gal', + 'ꚜ' => 'ъ', + 'ꚝ' => 'ь', + 'ꝰ' => 'ꝯ', + 'ꟸ' => 'Ħ', + 'ꟹ' => 'œ', + 'ꭜ' => 'ꜧ', + 'ꭝ' => 'ꬷ', + 'ꭞ' => 'ɫ', + 'ꭟ' => 'ꭒ', + 'ꭩ' => 'ʍ', + 'ff' => 'ff', + 'fi' => 'fi', + 'fl' => 'fl', + 'ffi' => 'ffi', + 'ffl' => 'ffl', + 'ſt' => 'st', + 'st' => 'st', + 'ﬓ' => 'մն', + 'ﬔ' => 'մե', + 'ﬕ' => 'մի', + 'ﬖ' => 'վն', + 'ﬗ' => 'մխ', + 'ﬠ' => 'ע', + 'ﬡ' => 'א', + 'ﬢ' => 'ד', + 'ﬣ' => 'ה', + 'ﬤ' => 'כ', + 'ﬥ' => 'ל', + 'ﬦ' => 'ם', + 'ﬧ' => 'ר', + 'ﬨ' => 'ת', + '﬩' => '+', + 'ﭏ' => 'אל', + 'ﭐ' => 'ٱ', + 'ﭑ' => 'ٱ', + 'ﭒ' => 'ٻ', + 'ﭓ' => 'ٻ', + 'ﭔ' => 'ٻ', + 'ﭕ' => 'ٻ', + 'ﭖ' => 'پ', + 'ﭗ' => 'پ', + 'ﭘ' => 'پ', + 'ﭙ' => 'پ', + 'ﭚ' => 'ڀ', + 'ﭛ' => 'ڀ', + 'ﭜ' => 'ڀ', + 'ﭝ' => 'ڀ', + 'ﭞ' => 'ٺ', + 'ﭟ' => 'ٺ', + 'ﭠ' => 'ٺ', + 'ﭡ' => 'ٺ', + 'ﭢ' => 'ٿ', + 'ﭣ' => 'ٿ', + 'ﭤ' => 'ٿ', + 'ﭥ' => 'ٿ', + 'ﭦ' => 'ٹ', + 'ﭧ' => 'ٹ', + 'ﭨ' => 'ٹ', + 'ﭩ' => 'ٹ', + 'ﭪ' => 'ڤ', + 'ﭫ' => 'ڤ', + 'ﭬ' => 'ڤ', + 'ﭭ' => 'ڤ', + 'ﭮ' => 'ڦ', + 'ﭯ' => 'ڦ', + 'ﭰ' => 'ڦ', + 'ﭱ' => 'ڦ', + 'ﭲ' => 'ڄ', + 'ﭳ' => 'ڄ', + 'ﭴ' => 'ڄ', + 'ﭵ' => 'ڄ', + 'ﭶ' => 'ڃ', + 'ﭷ' => 'ڃ', + 'ﭸ' => 'ڃ', + 'ﭹ' => 'ڃ', + 'ﭺ' => 'چ', + 'ﭻ' => 'چ', + 'ﭼ' => 'چ', + 'ﭽ' => 'چ', + 'ﭾ' => 'ڇ', + 'ﭿ' => 'ڇ', + 'ﮀ' => 'ڇ', + 'ﮁ' => 'ڇ', + 'ﮂ' => 'ڍ', + 'ﮃ' => 'ڍ', + 'ﮄ' => 'ڌ', + 'ﮅ' => 'ڌ', + 'ﮆ' => 'ڎ', + 'ﮇ' => 'ڎ', + 'ﮈ' => 'ڈ', + 'ﮉ' => 'ڈ', + 'ﮊ' => 'ژ', + 'ﮋ' => 'ژ', + 'ﮌ' => 'ڑ', + 'ﮍ' => 'ڑ', + 'ﮎ' => 'ک', + 'ﮏ' => 'ک', + 'ﮐ' => 'ک', + 'ﮑ' => 'ک', + 'ﮒ' => 'گ', + 'ﮓ' => 'گ', + 'ﮔ' => 'گ', + 'ﮕ' => 'گ', + 'ﮖ' => 'ڳ', + 'ﮗ' => 'ڳ', + 'ﮘ' => 'ڳ', + 'ﮙ' => 'ڳ', + 'ﮚ' => 'ڱ', + 'ﮛ' => 'ڱ', + 'ﮜ' => 'ڱ', + 'ﮝ' => 'ڱ', + 'ﮞ' => 'ں', + 'ﮟ' => 'ں', + 'ﮠ' => 'ڻ', + 'ﮡ' => 'ڻ', + 'ﮢ' => 'ڻ', + 'ﮣ' => 'ڻ', + 'ﮤ' => 'ۀ', + 'ﮥ' => 'ۀ', + 'ﮦ' => 'ہ', + 'ﮧ' => 'ہ', + 'ﮨ' => 'ہ', + 'ﮩ' => 'ہ', + 'ﮪ' => 'ھ', + 'ﮫ' => 'ھ', + 'ﮬ' => 'ھ', + 'ﮭ' => 'ھ', + 'ﮮ' => 'ے', + 'ﮯ' => 'ے', + 'ﮰ' => 'ۓ', + 'ﮱ' => 'ۓ', + 'ﯓ' => 'ڭ', + 'ﯔ' => 'ڭ', + 'ﯕ' => 'ڭ', + 'ﯖ' => 'ڭ', + 'ﯗ' => 'ۇ', + 'ﯘ' => 'ۇ', + 'ﯙ' => 'ۆ', + 'ﯚ' => 'ۆ', + 'ﯛ' => 'ۈ', + 'ﯜ' => 'ۈ', + 'ﯝ' => 'ۇٴ', + 'ﯞ' => 'ۋ', + 'ﯟ' => 'ۋ', + 'ﯠ' => 'ۅ', + 'ﯡ' => 'ۅ', + 'ﯢ' => 'ۉ', + 'ﯣ' => 'ۉ', + 'ﯤ' => 'ې', + 'ﯥ' => 'ې', + 'ﯦ' => 'ې', + 'ﯧ' => 'ې', + 'ﯨ' => 'ى', + 'ﯩ' => 'ى', + 'ﯪ' => 'ئا', + 'ﯫ' => 'ئا', + 'ﯬ' => 'ئە', + 'ﯭ' => 'ئە', + 'ﯮ' => 'ئو', + 'ﯯ' => 'ئو', + 'ﯰ' => 'ئۇ', + 'ﯱ' => 'ئۇ', + 'ﯲ' => 'ئۆ', + 'ﯳ' => 'ئۆ', + 'ﯴ' => 'ئۈ', + 'ﯵ' => 'ئۈ', + 'ﯶ' => 'ئې', + 'ﯷ' => 'ئې', + 'ﯸ' => 'ئې', + 'ﯹ' => 'ئى', + 'ﯺ' => 'ئى', + 'ﯻ' => 'ئى', + 'ﯼ' => 'ی', + 'ﯽ' => 'ی', + 'ﯾ' => 'ی', + 'ﯿ' => 'ی', + 'ﰀ' => 'ئج', + 'ﰁ' => 'ئح', + 'ﰂ' => 'ئم', + 'ﰃ' => 'ئى', + 'ﰄ' => 'ئي', + 'ﰅ' => 'بج', + 'ﰆ' => 'بح', + 'ﰇ' => 'بخ', + 'ﰈ' => 'بم', + 'ﰉ' => 'بى', + 'ﰊ' => 'بي', + 'ﰋ' => 'تج', + 'ﰌ' => 'تح', + 'ﰍ' => 'تخ', + 'ﰎ' => 'تم', + 'ﰏ' => 'تى', + 'ﰐ' => 'تي', + 'ﰑ' => 'ثج', + 'ﰒ' => 'ثم', + 'ﰓ' => 'ثى', + 'ﰔ' => 'ثي', + 'ﰕ' => 'جح', + 'ﰖ' => 'جم', + 'ﰗ' => 'حج', + 'ﰘ' => 'حم', + 'ﰙ' => 'خج', + 'ﰚ' => 'خح', + 'ﰛ' => 'خم', + 'ﰜ' => 'سج', + 'ﰝ' => 'سح', + 'ﰞ' => 'سخ', + 'ﰟ' => 'سم', + 'ﰠ' => 'صح', + 'ﰡ' => 'صم', + 'ﰢ' => 'ضج', + 'ﰣ' => 'ضح', + 'ﰤ' => 'ضخ', + 'ﰥ' => 'ضم', + 'ﰦ' => 'طح', + 'ﰧ' => 'طم', + 'ﰨ' => 'ظم', + 'ﰩ' => 'عج', + 'ﰪ' => 'عم', + 'ﰫ' => 'غج', + 'ﰬ' => 'غم', + 'ﰭ' => 'فج', + 'ﰮ' => 'فح', + 'ﰯ' => 'فخ', + 'ﰰ' => 'فم', + 'ﰱ' => 'فى', + 'ﰲ' => 'في', + 'ﰳ' => 'قح', + 'ﰴ' => 'قم', + 'ﰵ' => 'قى', + 'ﰶ' => 'قي', + 'ﰷ' => 'كا', + 'ﰸ' => 'كج', + 'ﰹ' => 'كح', + 'ﰺ' => 'كخ', + 'ﰻ' => 'كل', + 'ﰼ' => 'كم', + 'ﰽ' => 'كى', + 'ﰾ' => 'كي', + 'ﰿ' => 'لج', + 'ﱀ' => 'لح', + 'ﱁ' => 'لخ', + 'ﱂ' => 'لم', + 'ﱃ' => 'لى', + 'ﱄ' => 'لي', + 'ﱅ' => 'مج', + 'ﱆ' => 'مح', + 'ﱇ' => 'مخ', + 'ﱈ' => 'مم', + 'ﱉ' => 'مى', + 'ﱊ' => 'مي', + 'ﱋ' => 'نج', + 'ﱌ' => 'نح', + 'ﱍ' => 'نخ', + 'ﱎ' => 'نم', + 'ﱏ' => 'نى', + 'ﱐ' => 'ني', + 'ﱑ' => 'هج', + 'ﱒ' => 'هم', + 'ﱓ' => 'هى', + 'ﱔ' => 'هي', + 'ﱕ' => 'يج', + 'ﱖ' => 'يح', + 'ﱗ' => 'يخ', + 'ﱘ' => 'يم', + 'ﱙ' => 'يى', + 'ﱚ' => 'يي', + 'ﱛ' => 'ذٰ', + 'ﱜ' => 'رٰ', + 'ﱝ' => 'ىٰ', + 'ﱞ' => ' ٌّ', + 'ﱟ' => ' ٍّ', + 'ﱠ' => ' َّ', + 'ﱡ' => ' ُّ', + 'ﱢ' => ' ِّ', + 'ﱣ' => ' ّٰ', + 'ﱤ' => 'ئر', + 'ﱥ' => 'ئز', + 'ﱦ' => 'ئم', + 'ﱧ' => 'ئن', + 'ﱨ' => 'ئى', + 'ﱩ' => 'ئي', + 'ﱪ' => 'بر', + 'ﱫ' => 'بز', + 'ﱬ' => 'بم', + 'ﱭ' => 'بن', + 'ﱮ' => 'بى', + 'ﱯ' => 'بي', + 'ﱰ' => 'تر', + 'ﱱ' => 'تز', + 'ﱲ' => 'تم', + 'ﱳ' => 'تن', + 'ﱴ' => 'تى', + 'ﱵ' => 'تي', + 'ﱶ' => 'ثر', + 'ﱷ' => 'ثز', + 'ﱸ' => 'ثم', + 'ﱹ' => 'ثن', + 'ﱺ' => 'ثى', + 'ﱻ' => 'ثي', + 'ﱼ' => 'فى', + 'ﱽ' => 'في', + 'ﱾ' => 'قى', + 'ﱿ' => 'قي', + 'ﲀ' => 'كا', + 'ﲁ' => 'كل', + 'ﲂ' => 'كم', + 'ﲃ' => 'كى', + 'ﲄ' => 'كي', + 'ﲅ' => 'لم', + 'ﲆ' => 'لى', + 'ﲇ' => 'لي', + 'ﲈ' => 'ما', + 'ﲉ' => 'مم', + 'ﲊ' => 'نر', + 'ﲋ' => 'نز', + 'ﲌ' => 'نم', + 'ﲍ' => 'نن', + 'ﲎ' => 'نى', + 'ﲏ' => 'ني', + 'ﲐ' => 'ىٰ', + 'ﲑ' => 'ير', + 'ﲒ' => 'يز', + 'ﲓ' => 'يم', + 'ﲔ' => 'ين', + 'ﲕ' => 'يى', + 'ﲖ' => 'يي', + 'ﲗ' => 'ئج', + 'ﲘ' => 'ئح', + 'ﲙ' => 'ئخ', + 'ﲚ' => 'ئم', + 'ﲛ' => 'ئه', + 'ﲜ' => 'بج', + 'ﲝ' => 'بح', + 'ﲞ' => 'بخ', + 'ﲟ' => 'بم', + 'ﲠ' => 'به', + 'ﲡ' => 'تج', + 'ﲢ' => 'تح', + 'ﲣ' => 'تخ', + 'ﲤ' => 'تم', + 'ﲥ' => 'ته', + 'ﲦ' => 'ثم', + 'ﲧ' => 'جح', + 'ﲨ' => 'جم', + 'ﲩ' => 'حج', + 'ﲪ' => 'حم', + 'ﲫ' => 'خج', + 'ﲬ' => 'خم', + 'ﲭ' => 'سج', + 'ﲮ' => 'سح', + 'ﲯ' => 'سخ', + 'ﲰ' => 'سم', + 'ﲱ' => 'صح', + 'ﲲ' => 'صخ', + 'ﲳ' => 'صم', + 'ﲴ' => 'ضج', + 'ﲵ' => 'ضح', + 'ﲶ' => 'ضخ', + 'ﲷ' => 'ضم', + 'ﲸ' => 'طح', + 'ﲹ' => 'ظم', + 'ﲺ' => 'عج', + 'ﲻ' => 'عم', + 'ﲼ' => 'غج', + 'ﲽ' => 'غم', + 'ﲾ' => 'فج', + 'ﲿ' => 'فح', + 'ﳀ' => 'فخ', + 'ﳁ' => 'فم', + 'ﳂ' => 'قح', + 'ﳃ' => 'قم', + 'ﳄ' => 'كج', + 'ﳅ' => 'كح', + 'ﳆ' => 'كخ', + 'ﳇ' => 'كل', + 'ﳈ' => 'كم', + 'ﳉ' => 'لج', + 'ﳊ' => 'لح', + 'ﳋ' => 'لخ', + 'ﳌ' => 'لم', + 'ﳍ' => 'له', + 'ﳎ' => 'مج', + 'ﳏ' => 'مح', + 'ﳐ' => 'مخ', + 'ﳑ' => 'مم', + 'ﳒ' => 'نج', + 'ﳓ' => 'نح', + 'ﳔ' => 'نخ', + 'ﳕ' => 'نم', + 'ﳖ' => 'نه', + 'ﳗ' => 'هج', + 'ﳘ' => 'هم', + 'ﳙ' => 'هٰ', + 'ﳚ' => 'يج', + 'ﳛ' => 'يح', + 'ﳜ' => 'يخ', + 'ﳝ' => 'يم', + 'ﳞ' => 'يه', + 'ﳟ' => 'ئم', + 'ﳠ' => 'ئه', + 'ﳡ' => 'بم', + 'ﳢ' => 'به', + 'ﳣ' => 'تم', + 'ﳤ' => 'ته', + 'ﳥ' => 'ثم', + 'ﳦ' => 'ثه', + 'ﳧ' => 'سم', + 'ﳨ' => 'سه', + 'ﳩ' => 'شم', + 'ﳪ' => 'شه', + 'ﳫ' => 'كل', + 'ﳬ' => 'كم', + 'ﳭ' => 'لم', + 'ﳮ' => 'نم', + 'ﳯ' => 'نه', + 'ﳰ' => 'يم', + 'ﳱ' => 'يه', + 'ﳲ' => 'ـَّ', + 'ﳳ' => 'ـُّ', + 'ﳴ' => 'ـِّ', + 'ﳵ' => 'طى', + 'ﳶ' => 'طي', + 'ﳷ' => 'عى', + 'ﳸ' => 'عي', + 'ﳹ' => 'غى', + 'ﳺ' => 'غي', + 'ﳻ' => 'سى', + 'ﳼ' => 'سي', + 'ﳽ' => 'شى', + 'ﳾ' => 'شي', + 'ﳿ' => 'حى', + 'ﴀ' => 'حي', + 'ﴁ' => 'جى', + 'ﴂ' => 'جي', + 'ﴃ' => 'خى', + 'ﴄ' => 'خي', + 'ﴅ' => 'صى', + 'ﴆ' => 'صي', + 'ﴇ' => 'ضى', + 'ﴈ' => 'ضي', + 'ﴉ' => 'شج', + 'ﴊ' => 'شح', + 'ﴋ' => 'شخ', + 'ﴌ' => 'شم', + 'ﴍ' => 'شر', + 'ﴎ' => 'سر', + 'ﴏ' => 'صر', + 'ﴐ' => 'ضر', + 'ﴑ' => 'طى', + 'ﴒ' => 'طي', + 'ﴓ' => 'عى', + 'ﴔ' => 'عي', + 'ﴕ' => 'غى', + 'ﴖ' => 'غي', + 'ﴗ' => 'سى', + 'ﴘ' => 'سي', + 'ﴙ' => 'شى', + 'ﴚ' => 'شي', + 'ﴛ' => 'حى', + 'ﴜ' => 'حي', + 'ﴝ' => 'جى', + 'ﴞ' => 'جي', + 'ﴟ' => 'خى', + 'ﴠ' => 'خي', + 'ﴡ' => 'صى', + 'ﴢ' => 'صي', + 'ﴣ' => 'ضى', + 'ﴤ' => 'ضي', + 'ﴥ' => 'شج', + 'ﴦ' => 'شح', + 'ﴧ' => 'شخ', + 'ﴨ' => 'شم', + 'ﴩ' => 'شر', + 'ﴪ' => 'سر', + 'ﴫ' => 'صر', + 'ﴬ' => 'ضر', + 'ﴭ' => 'شج', + 'ﴮ' => 'شح', + 'ﴯ' => 'شخ', + 'ﴰ' => 'شم', + 'ﴱ' => 'سه', + 'ﴲ' => 'شه', + 'ﴳ' => 'طم', + 'ﴴ' => 'سج', + 'ﴵ' => 'سح', + 'ﴶ' => 'سخ', + 'ﴷ' => 'شج', + 'ﴸ' => 'شح', + 'ﴹ' => 'شخ', + 'ﴺ' => 'طم', + 'ﴻ' => 'ظم', + 'ﴼ' => 'اً', + 'ﴽ' => 'اً', + 'ﵐ' => 'تجم', + 'ﵑ' => 'تحج', + 'ﵒ' => 'تحج', + 'ﵓ' => 'تحم', + 'ﵔ' => 'تخم', + 'ﵕ' => 'تمج', + 'ﵖ' => 'تمح', + 'ﵗ' => 'تمخ', + 'ﵘ' => 'جمح', + 'ﵙ' => 'جمح', + 'ﵚ' => 'حمي', + 'ﵛ' => 'حمى', + 'ﵜ' => 'سحج', + 'ﵝ' => 'سجح', + 'ﵞ' => 'سجى', + 'ﵟ' => 'سمح', + 'ﵠ' => 'سمح', + 'ﵡ' => 'سمج', + 'ﵢ' => 'سمم', + 'ﵣ' => 'سمم', + 'ﵤ' => 'صحح', + 'ﵥ' => 'صحح', + 'ﵦ' => 'صمم', + 'ﵧ' => 'شحم', + 'ﵨ' => 'شحم', + 'ﵩ' => 'شجي', + 'ﵪ' => 'شمخ', + 'ﵫ' => 'شمخ', + 'ﵬ' => 'شمم', + 'ﵭ' => 'شمم', + 'ﵮ' => 'ضحى', + 'ﵯ' => 'ضخم', + 'ﵰ' => 'ضخم', + 'ﵱ' => 'طمح', + 'ﵲ' => 'طمح', + 'ﵳ' => 'طمم', + 'ﵴ' => 'طمي', + 'ﵵ' => 'عجم', + 'ﵶ' => 'عمم', + 'ﵷ' => 'عمم', + 'ﵸ' => 'عمى', + 'ﵹ' => 'غمم', + 'ﵺ' => 'غمي', + 'ﵻ' => 'غمى', + 'ﵼ' => 'فخم', + 'ﵽ' => 'فخم', + 'ﵾ' => 'قمح', + 'ﵿ' => 'قمم', + 'ﶀ' => 'لحم', + 'ﶁ' => 'لحي', + 'ﶂ' => 'لحى', + 'ﶃ' => 'لجج', + 'ﶄ' => 'لجج', + 'ﶅ' => 'لخم', + 'ﶆ' => 'لخم', + 'ﶇ' => 'لمح', + 'ﶈ' => 'لمح', + 'ﶉ' => 'محج', + 'ﶊ' => 'محم', + 'ﶋ' => 'محي', + 'ﶌ' => 'مجح', + 'ﶍ' => 'مجم', + 'ﶎ' => 'مخج', + 'ﶏ' => 'مخم', + 'ﶒ' => 'مجخ', + 'ﶓ' => 'همج', + 'ﶔ' => 'همم', + 'ﶕ' => 'نحم', + 'ﶖ' => 'نحى', + 'ﶗ' => 'نجم', + 'ﶘ' => 'نجم', + 'ﶙ' => 'نجى', + 'ﶚ' => 'نمي', + 'ﶛ' => 'نمى', + 'ﶜ' => 'يمم', + 'ﶝ' => 'يمم', + 'ﶞ' => 'بخي', + 'ﶟ' => 'تجي', + 'ﶠ' => 'تجى', + 'ﶡ' => 'تخي', + 'ﶢ' => 'تخى', + 'ﶣ' => 'تمي', + 'ﶤ' => 'تمى', + 'ﶥ' => 'جمي', + 'ﶦ' => 'جحى', + 'ﶧ' => 'جمى', + 'ﶨ' => 'سخى', + 'ﶩ' => 'صحي', + 'ﶪ' => 'شحي', + 'ﶫ' => 'ضحي', + 'ﶬ' => 'لجي', + 'ﶭ' => 'لمي', + 'ﶮ' => 'يحي', + 'ﶯ' => 'يجي', + 'ﶰ' => 'يمي', + 'ﶱ' => 'ممي', + 'ﶲ' => 'قمي', + 'ﶳ' => 'نحي', + 'ﶴ' => 'قمح', + 'ﶵ' => 'لحم', + 'ﶶ' => 'عمي', + 'ﶷ' => 'كمي', + 'ﶸ' => 'نجح', + 'ﶹ' => 'مخي', + 'ﶺ' => 'لجم', + 'ﶻ' => 'كمم', + 'ﶼ' => 'لجم', + 'ﶽ' => 'نجح', + 'ﶾ' => 'جحي', + 'ﶿ' => 'حجي', + 'ﷀ' => 'مجي', + 'ﷁ' => 'فمي', + 'ﷂ' => 'بحي', + 'ﷃ' => 'كمم', + 'ﷄ' => 'عجم', + 'ﷅ' => 'صمم', + 'ﷆ' => 'سخي', + 'ﷇ' => 'نجي', + 'ﷰ' => 'صلے', + 'ﷱ' => 'قلے', + 'ﷲ' => 'الله', + 'ﷳ' => 'اكبر', + 'ﷴ' => 'محمد', + 'ﷵ' => 'صلعم', + 'ﷶ' => 'رسول', + 'ﷷ' => 'عليه', + 'ﷸ' => 'وسلم', + 'ﷹ' => 'صلى', + 'ﷺ' => 'صلى الله عليه وسلم', + 'ﷻ' => 'جل جلاله', + '﷼' => 'ریال', + '︐' => ',', + '︑' => '、', + '︒' => '。', + '︓' => ':', + '︔' => ';', + '︕' => '!', + '︖' => '?', + '︗' => '〖', + '︘' => '〗', + '︙' => '...', + '︰' => '..', + '︱' => '—', + '︲' => '–', + '︳' => '_', + '︴' => '_', + '︵' => '(', + '︶' => ')', + '︷' => '{', + '︸' => '}', + '︹' => '〔', + '︺' => '〕', + '︻' => '【', + '︼' => '】', + '︽' => '《', + '︾' => '》', + '︿' => '〈', + '﹀' => '〉', + '﹁' => '「', + '﹂' => '」', + '﹃' => '『', + '﹄' => '』', + '﹇' => '[', + '﹈' => ']', + '﹉' => ' ̅', + '﹊' => ' ̅', + '﹋' => ' ̅', + '﹌' => ' ̅', + '﹍' => '_', + '﹎' => '_', + '﹏' => '_', + '﹐' => ',', + '﹑' => '、', + '﹒' => '.', + '﹔' => ';', + '﹕' => ':', + '﹖' => '?', + '﹗' => '!', + '﹘' => '—', + '﹙' => '(', + '﹚' => ')', + '﹛' => '{', + '﹜' => '}', + '﹝' => '〔', + '﹞' => '〕', + '﹟' => '#', + '﹠' => '&', + '﹡' => '*', + '﹢' => '+', + '﹣' => '-', + '﹤' => '<', + '﹥' => '>', + '﹦' => '=', + '﹨' => '\\', + '﹩' => '$', + '﹪' => '%', + '﹫' => '@', + 'ﹰ' => ' ً', + 'ﹱ' => 'ـً', + 'ﹲ' => ' ٌ', + 'ﹴ' => ' ٍ', + 'ﹶ' => ' َ', + 'ﹷ' => 'ـَ', + 'ﹸ' => ' ُ', + 'ﹹ' => 'ـُ', + 'ﹺ' => ' ِ', + 'ﹻ' => 'ـِ', + 'ﹼ' => ' ّ', + 'ﹽ' => 'ـّ', + 'ﹾ' => ' ْ', + 'ﹿ' => 'ـْ', + 'ﺀ' => 'ء', + 'ﺁ' => 'آ', + 'ﺂ' => 'آ', + 'ﺃ' => 'أ', + 'ﺄ' => 'أ', + 'ﺅ' => 'ؤ', + 'ﺆ' => 'ؤ', + 'ﺇ' => 'إ', + 'ﺈ' => 'إ', + 'ﺉ' => 'ئ', + 'ﺊ' => 'ئ', + 'ﺋ' => 'ئ', + 'ﺌ' => 'ئ', + 'ﺍ' => 'ا', + 'ﺎ' => 'ا', + 'ﺏ' => 'ب', + 'ﺐ' => 'ب', + 'ﺑ' => 'ب', + 'ﺒ' => 'ب', + 'ﺓ' => 'ة', + 'ﺔ' => 'ة', + 'ﺕ' => 'ت', + 'ﺖ' => 'ت', + 'ﺗ' => 'ت', + 'ﺘ' => 'ت', + 'ﺙ' => 'ث', + 'ﺚ' => 'ث', + 'ﺛ' => 'ث', + 'ﺜ' => 'ث', + 'ﺝ' => 'ج', + 'ﺞ' => 'ج', + 'ﺟ' => 'ج', + 'ﺠ' => 'ج', + 'ﺡ' => 'ح', + 'ﺢ' => 'ح', + 'ﺣ' => 'ح', + 'ﺤ' => 'ح', + 'ﺥ' => 'خ', + 'ﺦ' => 'خ', + 'ﺧ' => 'خ', + 'ﺨ' => 'خ', + 'ﺩ' => 'د', + 'ﺪ' => 'د', + 'ﺫ' => 'ذ', + 'ﺬ' => 'ذ', + 'ﺭ' => 'ر', + 'ﺮ' => 'ر', + 'ﺯ' => 'ز', + 'ﺰ' => 'ز', + 'ﺱ' => 'س', + 'ﺲ' => 'س', + 'ﺳ' => 'س', + 'ﺴ' => 'س', + 'ﺵ' => 'ش', + 'ﺶ' => 'ش', + 'ﺷ' => 'ش', + 'ﺸ' => 'ش', + 'ﺹ' => 'ص', + 'ﺺ' => 'ص', + 'ﺻ' => 'ص', + 'ﺼ' => 'ص', + 'ﺽ' => 'ض', + 'ﺾ' => 'ض', + 'ﺿ' => 'ض', + 'ﻀ' => 'ض', + 'ﻁ' => 'ط', + 'ﻂ' => 'ط', + 'ﻃ' => 'ط', + 'ﻄ' => 'ط', + 'ﻅ' => 'ظ', + 'ﻆ' => 'ظ', + 'ﻇ' => 'ظ', + 'ﻈ' => 'ظ', + 'ﻉ' => 'ع', + 'ﻊ' => 'ع', + 'ﻋ' => 'ع', + 'ﻌ' => 'ع', + 'ﻍ' => 'غ', + 'ﻎ' => 'غ', + 'ﻏ' => 'غ', + 'ﻐ' => 'غ', + 'ﻑ' => 'ف', + 'ﻒ' => 'ف', + 'ﻓ' => 'ف', + 'ﻔ' => 'ف', + 'ﻕ' => 'ق', + 'ﻖ' => 'ق', + 'ﻗ' => 'ق', + 'ﻘ' => 'ق', + 'ﻙ' => 'ك', + 'ﻚ' => 'ك', + 'ﻛ' => 'ك', + 'ﻜ' => 'ك', + 'ﻝ' => 'ل', + 'ﻞ' => 'ل', + 'ﻟ' => 'ل', + 'ﻠ' => 'ل', + 'ﻡ' => 'م', + 'ﻢ' => 'م', + 'ﻣ' => 'م', + 'ﻤ' => 'م', + 'ﻥ' => 'ن', + 'ﻦ' => 'ن', + 'ﻧ' => 'ن', + 'ﻨ' => 'ن', + 'ﻩ' => 'ه', + 'ﻪ' => 'ه', + 'ﻫ' => 'ه', + 'ﻬ' => 'ه', + 'ﻭ' => 'و', + 'ﻮ' => 'و', + 'ﻯ' => 'ى', + 'ﻰ' => 'ى', + 'ﻱ' => 'ي', + 'ﻲ' => 'ي', + 'ﻳ' => 'ي', + 'ﻴ' => 'ي', + 'ﻵ' => 'لآ', + 'ﻶ' => 'لآ', + 'ﻷ' => 'لأ', + 'ﻸ' => 'لأ', + 'ﻹ' => 'لإ', + 'ﻺ' => 'لإ', + 'ﻻ' => 'لا', + 'ﻼ' => 'لا', + '!' => '!', + '"' => '"', + '#' => '#', + '$' => '$', + '%' => '%', + '&' => '&', + ''' => '\'', + '(' => '(', + ')' => ')', + '*' => '*', + '+' => '+', + ',' => ',', + '-' => '-', + '.' => '.', + '/' => '/', + '0' => '0', + '1' => '1', + '2' => '2', + '3' => '3', + '4' => '4', + '5' => '5', + '6' => '6', + '7' => '7', + '8' => '8', + '9' => '9', + ':' => ':', + ';' => ';', + '<' => '<', + '=' => '=', + '>' => '>', + '?' => '?', + '@' => '@', + 'A' => 'A', + 'B' => 'B', + 'C' => 'C', + 'D' => 'D', + 'E' => 'E', + 'F' => 'F', + 'G' => 'G', + 'H' => 'H', + 'I' => 'I', + 'J' => 'J', + 'K' => 'K', + 'L' => 'L', + 'M' => 'M', + 'N' => 'N', + 'O' => 'O', + 'P' => 'P', + 'Q' => 'Q', + 'R' => 'R', + 'S' => 'S', + 'T' => 'T', + 'U' => 'U', + 'V' => 'V', + 'W' => 'W', + 'X' => 'X', + 'Y' => 'Y', + 'Z' => 'Z', + '[' => '[', + '\' => '\\', + ']' => ']', + '^' => '^', + '_' => '_', + '`' => '`', + 'a' => 'a', + 'b' => 'b', + 'c' => 'c', + 'd' => 'd', + 'e' => 'e', + 'f' => 'f', + 'g' => 'g', + 'h' => 'h', + 'i' => 'i', + 'j' => 'j', + 'k' => 'k', + 'l' => 'l', + 'm' => 'm', + 'n' => 'n', + 'o' => 'o', + 'p' => 'p', + 'q' => 'q', + 'r' => 'r', + 's' => 's', + 't' => 't', + 'u' => 'u', + 'v' => 'v', + 'w' => 'w', + 'x' => 'x', + 'y' => 'y', + 'z' => 'z', + '{' => '{', + '|' => '|', + '}' => '}', + '~' => '~', + '⦅' => '⦅', + '⦆' => '⦆', + '。' => '。', + '「' => '「', + '」' => '」', + '、' => '、', + '・' => '・', + 'ヲ' => 'ヲ', + 'ァ' => 'ァ', + 'ィ' => 'ィ', + 'ゥ' => 'ゥ', + 'ェ' => 'ェ', + 'ォ' => 'ォ', + 'ャ' => 'ャ', + 'ュ' => 'ュ', + 'ョ' => 'ョ', + 'ッ' => 'ッ', + 'ー' => 'ー', + 'ア' => 'ア', + 'イ' => 'イ', + 'ウ' => 'ウ', + 'エ' => 'エ', + 'オ' => 'オ', + 'カ' => 'カ', + 'キ' => 'キ', + 'ク' => 'ク', + 'ケ' => 'ケ', + 'コ' => 'コ', + 'サ' => 'サ', + 'シ' => 'シ', + 'ス' => 'ス', + 'セ' => 'セ', + 'ソ' => 'ソ', + 'タ' => 'タ', + 'チ' => 'チ', + 'ツ' => 'ツ', + 'テ' => 'テ', + 'ト' => 'ト', + 'ナ' => 'ナ', + 'ニ' => 'ニ', + 'ヌ' => 'ヌ', + 'ネ' => 'ネ', + 'ノ' => 'ノ', + 'ハ' => 'ハ', + 'ヒ' => 'ヒ', + 'フ' => 'フ', + 'ヘ' => 'ヘ', + 'ホ' => 'ホ', + 'マ' => 'マ', + 'ミ' => 'ミ', + 'ム' => 'ム', + 'メ' => 'メ', + 'モ' => 'モ', + 'ヤ' => 'ヤ', + 'ユ' => 'ユ', + 'ヨ' => 'ヨ', + 'ラ' => 'ラ', + 'リ' => 'リ', + 'ル' => 'ル', + 'レ' => 'レ', + 'ロ' => 'ロ', + 'ワ' => 'ワ', + 'ン' => 'ン', + '゙' => '゙', + '゚' => '゚', + 'ᅠ' => 'ᅠ', + 'ᄀ' => 'ᄀ', + 'ᄁ' => 'ᄁ', + 'ᆪ' => 'ᆪ', + 'ᄂ' => 'ᄂ', + 'ᆬ' => 'ᆬ', + 'ᆭ' => 'ᆭ', + 'ᄃ' => 'ᄃ', + 'ᄄ' => 'ᄄ', + 'ᄅ' => 'ᄅ', + 'ᆰ' => 'ᆰ', + 'ᆱ' => 'ᆱ', + 'ᆲ' => 'ᆲ', + 'ᆳ' => 'ᆳ', + 'ᆴ' => 'ᆴ', + 'ᆵ' => 'ᆵ', + 'ᄚ' => 'ᄚ', + 'ᄆ' => 'ᄆ', + 'ᄇ' => 'ᄇ', + 'ᄈ' => 'ᄈ', + 'ᄡ' => 'ᄡ', + 'ᄉ' => 'ᄉ', + 'ᄊ' => 'ᄊ', + 'ᄋ' => 'ᄋ', + 'ᄌ' => 'ᄌ', + 'ᄍ' => 'ᄍ', + 'ᄎ' => 'ᄎ', + 'ᄏ' => 'ᄏ', + 'ᄐ' => 'ᄐ', + 'ᄑ' => 'ᄑ', + 'ᄒ' => 'ᄒ', + 'ᅡ' => 'ᅡ', + 'ᅢ' => 'ᅢ', + 'ᅣ' => 'ᅣ', + 'ᅤ' => 'ᅤ', + 'ᅥ' => 'ᅥ', + 'ᅦ' => 'ᅦ', + 'ᅧ' => 'ᅧ', + 'ᅨ' => 'ᅨ', + 'ᅩ' => 'ᅩ', + 'ᅪ' => 'ᅪ', + 'ᅫ' => 'ᅫ', + 'ᅬ' => 'ᅬ', + 'ᅭ' => 'ᅭ', + 'ᅮ' => 'ᅮ', + 'ᅯ' => 'ᅯ', + 'ᅰ' => 'ᅰ', + 'ᅱ' => 'ᅱ', + 'ᅲ' => 'ᅲ', + 'ᅳ' => 'ᅳ', + 'ᅴ' => 'ᅴ', + 'ᅵ' => 'ᅵ', + '¢' => '¢', + '£' => '£', + '¬' => '¬', + ' ̄' => ' ̄', + '¦' => '¦', + '¥' => '¥', + '₩' => '₩', + '│' => '│', + '←' => '←', + '↑' => '↑', + '→' => '→', + '↓' => '↓', + '■' => '■', + '○' => '○', + '𝐀' => 'A', + '𝐁' => 'B', + '𝐂' => 'C', + '𝐃' => 'D', + '𝐄' => 'E', + '𝐅' => 'F', + '𝐆' => 'G', + '𝐇' => 'H', + '𝐈' => 'I', + '𝐉' => 'J', + '𝐊' => 'K', + '𝐋' => 'L', + '𝐌' => 'M', + '𝐍' => 'N', + '𝐎' => 'O', + '𝐏' => 'P', + '𝐐' => 'Q', + '𝐑' => 'R', + '𝐒' => 'S', + '𝐓' => 'T', + '𝐔' => 'U', + '𝐕' => 'V', + '𝐖' => 'W', + '𝐗' => 'X', + '𝐘' => 'Y', + '𝐙' => 'Z', + '𝐚' => 'a', + '𝐛' => 'b', + '𝐜' => 'c', + '𝐝' => 'd', + '𝐞' => 'e', + '𝐟' => 'f', + '𝐠' => 'g', + '𝐡' => 'h', + '𝐢' => 'i', + '𝐣' => 'j', + '𝐤' => 'k', + '𝐥' => 'l', + '𝐦' => 'm', + '𝐧' => 'n', + '𝐨' => 'o', + '𝐩' => 'p', + '𝐪' => 'q', + '𝐫' => 'r', + '𝐬' => 's', + '𝐭' => 't', + '𝐮' => 'u', + '𝐯' => 'v', + '𝐰' => 'w', + '𝐱' => 'x', + '𝐲' => 'y', + '𝐳' => 'z', + '𝐴' => 'A', + '𝐵' => 'B', + '𝐶' => 'C', + '𝐷' => 'D', + '𝐸' => 'E', + '𝐹' => 'F', + '𝐺' => 'G', + '𝐻' => 'H', + '𝐼' => 'I', + '𝐽' => 'J', + '𝐾' => 'K', + '𝐿' => 'L', + '𝑀' => 'M', + '𝑁' => 'N', + '𝑂' => 'O', + '𝑃' => 'P', + '𝑄' => 'Q', + '𝑅' => 'R', + '𝑆' => 'S', + '𝑇' => 'T', + '𝑈' => 'U', + '𝑉' => 'V', + '𝑊' => 'W', + '𝑋' => 'X', + '𝑌' => 'Y', + '𝑍' => 'Z', + '𝑎' => 'a', + '𝑏' => 'b', + '𝑐' => 'c', + '𝑑' => 'd', + '𝑒' => 'e', + '𝑓' => 'f', + '𝑔' => 'g', + '𝑖' => 'i', + '𝑗' => 'j', + '𝑘' => 'k', + '𝑙' => 'l', + '𝑚' => 'm', + '𝑛' => 'n', + '𝑜' => 'o', + '𝑝' => 'p', + '𝑞' => 'q', + '𝑟' => 'r', + '𝑠' => 's', + '𝑡' => 't', + '𝑢' => 'u', + '𝑣' => 'v', + '𝑤' => 'w', + '𝑥' => 'x', + '𝑦' => 'y', + '𝑧' => 'z', + '𝑨' => 'A', + '𝑩' => 'B', + '𝑪' => 'C', + '𝑫' => 'D', + '𝑬' => 'E', + '𝑭' => 'F', + '𝑮' => 'G', + '𝑯' => 'H', + '𝑰' => 'I', + '𝑱' => 'J', + '𝑲' => 'K', + '𝑳' => 'L', + '𝑴' => 'M', + '𝑵' => 'N', + '𝑶' => 'O', + '𝑷' => 'P', + '𝑸' => 'Q', + '𝑹' => 'R', + '𝑺' => 'S', + '𝑻' => 'T', + '𝑼' => 'U', + '𝑽' => 'V', + '𝑾' => 'W', + '𝑿' => 'X', + '𝒀' => 'Y', + '𝒁' => 'Z', + '𝒂' => 'a', + '𝒃' => 'b', + '𝒄' => 'c', + '𝒅' => 'd', + '𝒆' => 'e', + '𝒇' => 'f', + '𝒈' => 'g', + '𝒉' => 'h', + '𝒊' => 'i', + '𝒋' => 'j', + '𝒌' => 'k', + '𝒍' => 'l', + '𝒎' => 'm', + '𝒏' => 'n', + '𝒐' => 'o', + '𝒑' => 'p', + '𝒒' => 'q', + '𝒓' => 'r', + '𝒔' => 's', + '𝒕' => 't', + '𝒖' => 'u', + '𝒗' => 'v', + '𝒘' => 'w', + '𝒙' => 'x', + '𝒚' => 'y', + '𝒛' => 'z', + '𝒜' => 'A', + '𝒞' => 'C', + '𝒟' => 'D', + '𝒢' => 'G', + '𝒥' => 'J', + '𝒦' => 'K', + '𝒩' => 'N', + '𝒪' => 'O', + '𝒫' => 'P', + '𝒬' => 'Q', + '𝒮' => 'S', + '𝒯' => 'T', + '𝒰' => 'U', + '𝒱' => 'V', + '𝒲' => 'W', + '𝒳' => 'X', + '𝒴' => 'Y', + '𝒵' => 'Z', + '𝒶' => 'a', + '𝒷' => 'b', + '𝒸' => 'c', + '𝒹' => 'd', + '𝒻' => 'f', + '𝒽' => 'h', + '𝒾' => 'i', + '𝒿' => 'j', + '𝓀' => 'k', + '𝓁' => 'l', + '𝓂' => 'm', + '𝓃' => 'n', + '𝓅' => 'p', + '𝓆' => 'q', + '𝓇' => 'r', + '𝓈' => 's', + '𝓉' => 't', + '𝓊' => 'u', + '𝓋' => 'v', + '𝓌' => 'w', + '𝓍' => 'x', + '𝓎' => 'y', + '𝓏' => 'z', + '𝓐' => 'A', + '𝓑' => 'B', + '𝓒' => 'C', + '𝓓' => 'D', + '𝓔' => 'E', + '𝓕' => 'F', + '𝓖' => 'G', + '𝓗' => 'H', + '𝓘' => 'I', + '𝓙' => 'J', + '𝓚' => 'K', + '𝓛' => 'L', + '𝓜' => 'M', + '𝓝' => 'N', + '𝓞' => 'O', + '𝓟' => 'P', + '𝓠' => 'Q', + '𝓡' => 'R', + '𝓢' => 'S', + '𝓣' => 'T', + '𝓤' => 'U', + '𝓥' => 'V', + '𝓦' => 'W', + '𝓧' => 'X', + '𝓨' => 'Y', + '𝓩' => 'Z', + '𝓪' => 'a', + '𝓫' => 'b', + '𝓬' => 'c', + '𝓭' => 'd', + '𝓮' => 'e', + '𝓯' => 'f', + '𝓰' => 'g', + '𝓱' => 'h', + '𝓲' => 'i', + '𝓳' => 'j', + '𝓴' => 'k', + '𝓵' => 'l', + '𝓶' => 'm', + '𝓷' => 'n', + '𝓸' => 'o', + '𝓹' => 'p', + '𝓺' => 'q', + '𝓻' => 'r', + '𝓼' => 's', + '𝓽' => 't', + '𝓾' => 'u', + '𝓿' => 'v', + '𝔀' => 'w', + '𝔁' => 'x', + '𝔂' => 'y', + '𝔃' => 'z', + '𝔄' => 'A', + '𝔅' => 'B', + '𝔇' => 'D', + '𝔈' => 'E', + '𝔉' => 'F', + '𝔊' => 'G', + '𝔍' => 'J', + '𝔎' => 'K', + '𝔏' => 'L', + '𝔐' => 'M', + '𝔑' => 'N', + '𝔒' => 'O', + '𝔓' => 'P', + '𝔔' => 'Q', + '𝔖' => 'S', + '𝔗' => 'T', + '𝔘' => 'U', + '𝔙' => 'V', + '𝔚' => 'W', + '𝔛' => 'X', + '𝔜' => 'Y', + '𝔞' => 'a', + '𝔟' => 'b', + '𝔠' => 'c', + '𝔡' => 'd', + '𝔢' => 'e', + '𝔣' => 'f', + '𝔤' => 'g', + '𝔥' => 'h', + '𝔦' => 'i', + '𝔧' => 'j', + '𝔨' => 'k', + '𝔩' => 'l', + '𝔪' => 'm', + '𝔫' => 'n', + '𝔬' => 'o', + '𝔭' => 'p', + '𝔮' => 'q', + '𝔯' => 'r', + '𝔰' => 's', + '𝔱' => 't', + '𝔲' => 'u', + '𝔳' => 'v', + '𝔴' => 'w', + '𝔵' => 'x', + '𝔶' => 'y', + '𝔷' => 'z', + '𝔸' => 'A', + '𝔹' => 'B', + '𝔻' => 'D', + '𝔼' => 'E', + '𝔽' => 'F', + '𝔾' => 'G', + '𝕀' => 'I', + '𝕁' => 'J', + '𝕂' => 'K', + '𝕃' => 'L', + '𝕄' => 'M', + '𝕆' => 'O', + '𝕊' => 'S', + '𝕋' => 'T', + '𝕌' => 'U', + '𝕍' => 'V', + '𝕎' => 'W', + '𝕏' => 'X', + '𝕐' => 'Y', + '𝕒' => 'a', + '𝕓' => 'b', + '𝕔' => 'c', + '𝕕' => 'd', + '𝕖' => 'e', + '𝕗' => 'f', + '𝕘' => 'g', + '𝕙' => 'h', + '𝕚' => 'i', + '𝕛' => 'j', + '𝕜' => 'k', + '𝕝' => 'l', + '𝕞' => 'm', + '𝕟' => 'n', + '𝕠' => 'o', + '𝕡' => 'p', + '𝕢' => 'q', + '𝕣' => 'r', + '𝕤' => 's', + '𝕥' => 't', + '𝕦' => 'u', + '𝕧' => 'v', + '𝕨' => 'w', + '𝕩' => 'x', + '𝕪' => 'y', + '𝕫' => 'z', + '𝕬' => 'A', + '𝕭' => 'B', + '𝕮' => 'C', + '𝕯' => 'D', + '𝕰' => 'E', + '𝕱' => 'F', + '𝕲' => 'G', + '𝕳' => 'H', + '𝕴' => 'I', + '𝕵' => 'J', + '𝕶' => 'K', + '𝕷' => 'L', + '𝕸' => 'M', + '𝕹' => 'N', + '𝕺' => 'O', + '𝕻' => 'P', + '𝕼' => 'Q', + '𝕽' => 'R', + '𝕾' => 'S', + '𝕿' => 'T', + '𝖀' => 'U', + '𝖁' => 'V', + '𝖂' => 'W', + '𝖃' => 'X', + '𝖄' => 'Y', + '𝖅' => 'Z', + '𝖆' => 'a', + '𝖇' => 'b', + '𝖈' => 'c', + '𝖉' => 'd', + '𝖊' => 'e', + '𝖋' => 'f', + '𝖌' => 'g', + '𝖍' => 'h', + '𝖎' => 'i', + '𝖏' => 'j', + '𝖐' => 'k', + '𝖑' => 'l', + '𝖒' => 'm', + '𝖓' => 'n', + '𝖔' => 'o', + '𝖕' => 'p', + '𝖖' => 'q', + '𝖗' => 'r', + '𝖘' => 's', + '𝖙' => 't', + '𝖚' => 'u', + '𝖛' => 'v', + '𝖜' => 'w', + '𝖝' => 'x', + '𝖞' => 'y', + '𝖟' => 'z', + '𝖠' => 'A', + '𝖡' => 'B', + '𝖢' => 'C', + '𝖣' => 'D', + '𝖤' => 'E', + '𝖥' => 'F', + '𝖦' => 'G', + '𝖧' => 'H', + '𝖨' => 'I', + '𝖩' => 'J', + '𝖪' => 'K', + '𝖫' => 'L', + '𝖬' => 'M', + '𝖭' => 'N', + '𝖮' => 'O', + '𝖯' => 'P', + '𝖰' => 'Q', + '𝖱' => 'R', + '𝖲' => 'S', + '𝖳' => 'T', + '𝖴' => 'U', + '𝖵' => 'V', + '𝖶' => 'W', + '𝖷' => 'X', + '𝖸' => 'Y', + '𝖹' => 'Z', + '𝖺' => 'a', + '𝖻' => 'b', + '𝖼' => 'c', + '𝖽' => 'd', + '𝖾' => 'e', + '𝖿' => 'f', + '𝗀' => 'g', + '𝗁' => 'h', + '𝗂' => 'i', + '𝗃' => 'j', + '𝗄' => 'k', + '𝗅' => 'l', + '𝗆' => 'm', + '𝗇' => 'n', + '𝗈' => 'o', + '𝗉' => 'p', + '𝗊' => 'q', + '𝗋' => 'r', + '𝗌' => 's', + '𝗍' => 't', + '𝗎' => 'u', + '𝗏' => 'v', + '𝗐' => 'w', + '𝗑' => 'x', + '𝗒' => 'y', + '𝗓' => 'z', + '𝗔' => 'A', + '𝗕' => 'B', + '𝗖' => 'C', + '𝗗' => 'D', + '𝗘' => 'E', + '𝗙' => 'F', + '𝗚' => 'G', + '𝗛' => 'H', + '𝗜' => 'I', + '𝗝' => 'J', + '𝗞' => 'K', + '𝗟' => 'L', + '𝗠' => 'M', + '𝗡' => 'N', + '𝗢' => 'O', + '𝗣' => 'P', + '𝗤' => 'Q', + '𝗥' => 'R', + '𝗦' => 'S', + '𝗧' => 'T', + '𝗨' => 'U', + '𝗩' => 'V', + '𝗪' => 'W', + '𝗫' => 'X', + '𝗬' => 'Y', + '𝗭' => 'Z', + '𝗮' => 'a', + '𝗯' => 'b', + '𝗰' => 'c', + '𝗱' => 'd', + '𝗲' => 'e', + '𝗳' => 'f', + '𝗴' => 'g', + '𝗵' => 'h', + '𝗶' => 'i', + '𝗷' => 'j', + '𝗸' => 'k', + '𝗹' => 'l', + '𝗺' => 'm', + '𝗻' => 'n', + '𝗼' => 'o', + '𝗽' => 'p', + '𝗾' => 'q', + '𝗿' => 'r', + '𝘀' => 's', + '𝘁' => 't', + '𝘂' => 'u', + '𝘃' => 'v', + '𝘄' => 'w', + '𝘅' => 'x', + '𝘆' => 'y', + '𝘇' => 'z', + '𝘈' => 'A', + '𝘉' => 'B', + '𝘊' => 'C', + '𝘋' => 'D', + '𝘌' => 'E', + '𝘍' => 'F', + '𝘎' => 'G', + '𝘏' => 'H', + '𝘐' => 'I', + '𝘑' => 'J', + '𝘒' => 'K', + '𝘓' => 'L', + '𝘔' => 'M', + '𝘕' => 'N', + '𝘖' => 'O', + '𝘗' => 'P', + '𝘘' => 'Q', + '𝘙' => 'R', + '𝘚' => 'S', + '𝘛' => 'T', + '𝘜' => 'U', + '𝘝' => 'V', + '𝘞' => 'W', + '𝘟' => 'X', + '𝘠' => 'Y', + '𝘡' => 'Z', + '𝘢' => 'a', + '𝘣' => 'b', + '𝘤' => 'c', + '𝘥' => 'd', + '𝘦' => 'e', + '𝘧' => 'f', + '𝘨' => 'g', + '𝘩' => 'h', + '𝘪' => 'i', + '𝘫' => 'j', + '𝘬' => 'k', + '𝘭' => 'l', + '𝘮' => 'm', + '𝘯' => 'n', + '𝘰' => 'o', + '𝘱' => 'p', + '𝘲' => 'q', + '𝘳' => 'r', + '𝘴' => 's', + '𝘵' => 't', + '𝘶' => 'u', + '𝘷' => 'v', + '𝘸' => 'w', + '𝘹' => 'x', + '𝘺' => 'y', + '𝘻' => 'z', + '𝘼' => 'A', + '𝘽' => 'B', + '𝘾' => 'C', + '𝘿' => 'D', + '𝙀' => 'E', + '𝙁' => 'F', + '𝙂' => 'G', + '𝙃' => 'H', + '𝙄' => 'I', + '𝙅' => 'J', + '𝙆' => 'K', + '𝙇' => 'L', + '𝙈' => 'M', + '𝙉' => 'N', + '𝙊' => 'O', + '𝙋' => 'P', + '𝙌' => 'Q', + '𝙍' => 'R', + '𝙎' => 'S', + '𝙏' => 'T', + '𝙐' => 'U', + '𝙑' => 'V', + '𝙒' => 'W', + '𝙓' => 'X', + '𝙔' => 'Y', + '𝙕' => 'Z', + '𝙖' => 'a', + '𝙗' => 'b', + '𝙘' => 'c', + '𝙙' => 'd', + '𝙚' => 'e', + '𝙛' => 'f', + '𝙜' => 'g', + '𝙝' => 'h', + '𝙞' => 'i', + '𝙟' => 'j', + '𝙠' => 'k', + '𝙡' => 'l', + '𝙢' => 'm', + '𝙣' => 'n', + '𝙤' => 'o', + '𝙥' => 'p', + '𝙦' => 'q', + '𝙧' => 'r', + '𝙨' => 's', + '𝙩' => 't', + '𝙪' => 'u', + '𝙫' => 'v', + '𝙬' => 'w', + '𝙭' => 'x', + '𝙮' => 'y', + '𝙯' => 'z', + '𝙰' => 'A', + '𝙱' => 'B', + '𝙲' => 'C', + '𝙳' => 'D', + '𝙴' => 'E', + '𝙵' => 'F', + '𝙶' => 'G', + '𝙷' => 'H', + '𝙸' => 'I', + '𝙹' => 'J', + '𝙺' => 'K', + '𝙻' => 'L', + '𝙼' => 'M', + '𝙽' => 'N', + '𝙾' => 'O', + '𝙿' => 'P', + '𝚀' => 'Q', + '𝚁' => 'R', + '𝚂' => 'S', + '𝚃' => 'T', + '𝚄' => 'U', + '𝚅' => 'V', + '𝚆' => 'W', + '𝚇' => 'X', + '𝚈' => 'Y', + '𝚉' => 'Z', + '𝚊' => 'a', + '𝚋' => 'b', + '𝚌' => 'c', + '𝚍' => 'd', + '𝚎' => 'e', + '𝚏' => 'f', + '𝚐' => 'g', + '𝚑' => 'h', + '𝚒' => 'i', + '𝚓' => 'j', + '𝚔' => 'k', + '𝚕' => 'l', + '𝚖' => 'm', + '𝚗' => 'n', + '𝚘' => 'o', + '𝚙' => 'p', + '𝚚' => 'q', + '𝚛' => 'r', + '𝚜' => 's', + '𝚝' => 't', + '𝚞' => 'u', + '𝚟' => 'v', + '𝚠' => 'w', + '𝚡' => 'x', + '𝚢' => 'y', + '𝚣' => 'z', + '𝚤' => 'ı', + '𝚥' => 'ȷ', + '𝚨' => 'Α', + '𝚩' => 'Β', + '𝚪' => 'Γ', + '𝚫' => 'Δ', + '𝚬' => 'Ε', + '𝚭' => 'Ζ', + '𝚮' => 'Η', + '𝚯' => 'Θ', + '𝚰' => 'Ι', + '𝚱' => 'Κ', + '𝚲' => 'Λ', + '𝚳' => 'Μ', + '𝚴' => 'Ν', + '𝚵' => 'Ξ', + '𝚶' => 'Ο', + '𝚷' => 'Π', + '𝚸' => 'Ρ', + '𝚹' => 'Θ', + '𝚺' => 'Σ', + '𝚻' => 'Τ', + '𝚼' => 'Υ', + '𝚽' => 'Φ', + '𝚾' => 'Χ', + '𝚿' => 'Ψ', + '𝛀' => 'Ω', + '𝛁' => '∇', + '𝛂' => 'α', + '𝛃' => 'β', + '𝛄' => 'γ', + '𝛅' => 'δ', + '𝛆' => 'ε', + '𝛇' => 'ζ', + '𝛈' => 'η', + '𝛉' => 'θ', + '𝛊' => 'ι', + '𝛋' => 'κ', + '𝛌' => 'λ', + '𝛍' => 'μ', + '𝛎' => 'ν', + '𝛏' => 'ξ', + '𝛐' => 'ο', + '𝛑' => 'π', + '𝛒' => 'ρ', + '𝛓' => 'ς', + '𝛔' => 'σ', + '𝛕' => 'τ', + '𝛖' => 'υ', + '𝛗' => 'φ', + '𝛘' => 'χ', + '𝛙' => 'ψ', + '𝛚' => 'ω', + '𝛛' => '∂', + '𝛜' => 'ε', + '𝛝' => 'θ', + '𝛞' => 'κ', + '𝛟' => 'φ', + '𝛠' => 'ρ', + '𝛡' => 'π', + '𝛢' => 'Α', + '𝛣' => 'Β', + '𝛤' => 'Γ', + '𝛥' => 'Δ', + '𝛦' => 'Ε', + '𝛧' => 'Ζ', + '𝛨' => 'Η', + '𝛩' => 'Θ', + '𝛪' => 'Ι', + '𝛫' => 'Κ', + '𝛬' => 'Λ', + '𝛭' => 'Μ', + '𝛮' => 'Ν', + '𝛯' => 'Ξ', + '𝛰' => 'Ο', + '𝛱' => 'Π', + '𝛲' => 'Ρ', + '𝛳' => 'Θ', + '𝛴' => 'Σ', + '𝛵' => 'Τ', + '𝛶' => 'Υ', + '𝛷' => 'Φ', + '𝛸' => 'Χ', + '𝛹' => 'Ψ', + '𝛺' => 'Ω', + '𝛻' => '∇', + '𝛼' => 'α', + '𝛽' => 'β', + '𝛾' => 'γ', + '𝛿' => 'δ', + '𝜀' => 'ε', + '𝜁' => 'ζ', + '𝜂' => 'η', + '𝜃' => 'θ', + '𝜄' => 'ι', + '𝜅' => 'κ', + '𝜆' => 'λ', + '𝜇' => 'μ', + '𝜈' => 'ν', + '𝜉' => 'ξ', + '𝜊' => 'ο', + '𝜋' => 'π', + '𝜌' => 'ρ', + '𝜍' => 'ς', + '𝜎' => 'σ', + '𝜏' => 'τ', + '𝜐' => 'υ', + '𝜑' => 'φ', + '𝜒' => 'χ', + '𝜓' => 'ψ', + '𝜔' => 'ω', + '𝜕' => '∂', + '𝜖' => 'ε', + '𝜗' => 'θ', + '𝜘' => 'κ', + '𝜙' => 'φ', + '𝜚' => 'ρ', + '𝜛' => 'π', + '𝜜' => 'Α', + '𝜝' => 'Β', + '𝜞' => 'Γ', + '𝜟' => 'Δ', + '𝜠' => 'Ε', + '𝜡' => 'Ζ', + '𝜢' => 'Η', + '𝜣' => 'Θ', + '𝜤' => 'Ι', + '𝜥' => 'Κ', + '𝜦' => 'Λ', + '𝜧' => 'Μ', + '𝜨' => 'Ν', + '𝜩' => 'Ξ', + '𝜪' => 'Ο', + '𝜫' => 'Π', + '𝜬' => 'Ρ', + '𝜭' => 'Θ', + '𝜮' => 'Σ', + '𝜯' => 'Τ', + '𝜰' => 'Υ', + '𝜱' => 'Φ', + '𝜲' => 'Χ', + '𝜳' => 'Ψ', + '𝜴' => 'Ω', + '𝜵' => '∇', + '𝜶' => 'α', + '𝜷' => 'β', + '𝜸' => 'γ', + '𝜹' => 'δ', + '𝜺' => 'ε', + '𝜻' => 'ζ', + '𝜼' => 'η', + '𝜽' => 'θ', + '𝜾' => 'ι', + '𝜿' => 'κ', + '𝝀' => 'λ', + '𝝁' => 'μ', + '𝝂' => 'ν', + '𝝃' => 'ξ', + '𝝄' => 'ο', + '𝝅' => 'π', + '𝝆' => 'ρ', + '𝝇' => 'ς', + '𝝈' => 'σ', + '𝝉' => 'τ', + '𝝊' => 'υ', + '𝝋' => 'φ', + '𝝌' => 'χ', + '𝝍' => 'ψ', + '𝝎' => 'ω', + '𝝏' => '∂', + '𝝐' => 'ε', + '𝝑' => 'θ', + '𝝒' => 'κ', + '𝝓' => 'φ', + '𝝔' => 'ρ', + '𝝕' => 'π', + '𝝖' => 'Α', + '𝝗' => 'Β', + '𝝘' => 'Γ', + '𝝙' => 'Δ', + '𝝚' => 'Ε', + '𝝛' => 'Ζ', + '𝝜' => 'Η', + '𝝝' => 'Θ', + '𝝞' => 'Ι', + '𝝟' => 'Κ', + '𝝠' => 'Λ', + '𝝡' => 'Μ', + '𝝢' => 'Ν', + '𝝣' => 'Ξ', + '𝝤' => 'Ο', + '𝝥' => 'Π', + '𝝦' => 'Ρ', + '𝝧' => 'Θ', + '𝝨' => 'Σ', + '𝝩' => 'Τ', + '𝝪' => 'Υ', + '𝝫' => 'Φ', + '𝝬' => 'Χ', + '𝝭' => 'Ψ', + '𝝮' => 'Ω', + '𝝯' => '∇', + '𝝰' => 'α', + '𝝱' => 'β', + '𝝲' => 'γ', + '𝝳' => 'δ', + '𝝴' => 'ε', + '𝝵' => 'ζ', + '𝝶' => 'η', + '𝝷' => 'θ', + '𝝸' => 'ι', + '𝝹' => 'κ', + '𝝺' => 'λ', + '𝝻' => 'μ', + '𝝼' => 'ν', + '𝝽' => 'ξ', + '𝝾' => 'ο', + '𝝿' => 'π', + '𝞀' => 'ρ', + '𝞁' => 'ς', + '𝞂' => 'σ', + '𝞃' => 'τ', + '𝞄' => 'υ', + '𝞅' => 'φ', + '𝞆' => 'χ', + '𝞇' => 'ψ', + '𝞈' => 'ω', + '𝞉' => '∂', + '𝞊' => 'ε', + '𝞋' => 'θ', + '𝞌' => 'κ', + '𝞍' => 'φ', + '𝞎' => 'ρ', + '𝞏' => 'π', + '𝞐' => 'Α', + '𝞑' => 'Β', + '𝞒' => 'Γ', + '𝞓' => 'Δ', + '𝞔' => 'Ε', + '𝞕' => 'Ζ', + '𝞖' => 'Η', + '𝞗' => 'Θ', + '𝞘' => 'Ι', + '𝞙' => 'Κ', + '𝞚' => 'Λ', + '𝞛' => 'Μ', + '𝞜' => 'Ν', + '𝞝' => 'Ξ', + '𝞞' => 'Ο', + '𝞟' => 'Π', + '𝞠' => 'Ρ', + '𝞡' => 'Θ', + '𝞢' => 'Σ', + '𝞣' => 'Τ', + '𝞤' => 'Υ', + '𝞥' => 'Φ', + '𝞦' => 'Χ', + '𝞧' => 'Ψ', + '𝞨' => 'Ω', + '𝞩' => '∇', + '𝞪' => 'α', + '𝞫' => 'β', + '𝞬' => 'γ', + '𝞭' => 'δ', + '𝞮' => 'ε', + '𝞯' => 'ζ', + '𝞰' => 'η', + '𝞱' => 'θ', + '𝞲' => 'ι', + '𝞳' => 'κ', + '𝞴' => 'λ', + '𝞵' => 'μ', + '𝞶' => 'ν', + '𝞷' => 'ξ', + '𝞸' => 'ο', + '𝞹' => 'π', + '𝞺' => 'ρ', + '𝞻' => 'ς', + '𝞼' => 'σ', + '𝞽' => 'τ', + '𝞾' => 'υ', + '𝞿' => 'φ', + '𝟀' => 'χ', + '𝟁' => 'ψ', + '𝟂' => 'ω', + '𝟃' => '∂', + '𝟄' => 'ε', + '𝟅' => 'θ', + '𝟆' => 'κ', + '𝟇' => 'φ', + '𝟈' => 'ρ', + '𝟉' => 'π', + '𝟊' => 'Ϝ', + '𝟋' => 'ϝ', + '𝟎' => '0', + '𝟏' => '1', + '𝟐' => '2', + '𝟑' => '3', + '𝟒' => '4', + '𝟓' => '5', + '𝟔' => '6', + '𝟕' => '7', + '𝟖' => '8', + '𝟗' => '9', + '𝟘' => '0', + '𝟙' => '1', + '𝟚' => '2', + '𝟛' => '3', + '𝟜' => '4', + '𝟝' => '5', + '𝟞' => '6', + '𝟟' => '7', + '𝟠' => '8', + '𝟡' => '9', + '𝟢' => '0', + '𝟣' => '1', + '𝟤' => '2', + '𝟥' => '3', + '𝟦' => '4', + '𝟧' => '5', + '𝟨' => '6', + '𝟩' => '7', + '𝟪' => '8', + '𝟫' => '9', + '𝟬' => '0', + '𝟭' => '1', + '𝟮' => '2', + '𝟯' => '3', + '𝟰' => '4', + '𝟱' => '5', + '𝟲' => '6', + '𝟳' => '7', + '𝟴' => '8', + '𝟵' => '9', + '𝟶' => '0', + '𝟷' => '1', + '𝟸' => '2', + '𝟹' => '3', + '𝟺' => '4', + '𝟻' => '5', + '𝟼' => '6', + '𝟽' => '7', + '𝟾' => '8', + '𝟿' => '9', + '𞸀' => 'ا', + '𞸁' => 'ب', + '𞸂' => 'ج', + '𞸃' => 'د', + '𞸅' => 'و', + '𞸆' => 'ز', + '𞸇' => 'ح', + '𞸈' => 'ط', + '𞸉' => 'ي', + '𞸊' => 'ك', + '𞸋' => 'ل', + '𞸌' => 'م', + '𞸍' => 'ن', + '𞸎' => 'س', + '𞸏' => 'ع', + '𞸐' => 'ف', + '𞸑' => 'ص', + '𞸒' => 'ق', + '𞸓' => 'ر', + '𞸔' => 'ش', + '𞸕' => 'ت', + '𞸖' => 'ث', + '𞸗' => 'خ', + '𞸘' => 'ذ', + '𞸙' => 'ض', + '𞸚' => 'ظ', + '𞸛' => 'غ', + '𞸜' => 'ٮ', + '𞸝' => 'ں', + '𞸞' => 'ڡ', + '𞸟' => 'ٯ', + '𞸡' => 'ب', + '𞸢' => 'ج', + '𞸤' => 'ه', + '𞸧' => 'ح', + '𞸩' => 'ي', + '𞸪' => 'ك', + '𞸫' => 'ل', + '𞸬' => 'م', + '𞸭' => 'ن', + '𞸮' => 'س', + '𞸯' => 'ع', + '𞸰' => 'ف', + '𞸱' => 'ص', + '𞸲' => 'ق', + '𞸴' => 'ش', + '𞸵' => 'ت', + '𞸶' => 'ث', + '𞸷' => 'خ', + '𞸹' => 'ض', + '𞸻' => 'غ', + '𞹂' => 'ج', + '𞹇' => 'ح', + '𞹉' => 'ي', + '𞹋' => 'ل', + '𞹍' => 'ن', + '𞹎' => 'س', + '𞹏' => 'ع', + '𞹑' => 'ص', + '𞹒' => 'ق', + '𞹔' => 'ش', + '𞹗' => 'خ', + '𞹙' => 'ض', + '𞹛' => 'غ', + '𞹝' => 'ں', + '𞹟' => 'ٯ', + '𞹡' => 'ب', + '𞹢' => 'ج', + '𞹤' => 'ه', + '𞹧' => 'ح', + '𞹨' => 'ط', + '𞹩' => 'ي', + '𞹪' => 'ك', + '𞹬' => 'م', + '𞹭' => 'ن', + '𞹮' => 'س', + '𞹯' => 'ع', + '𞹰' => 'ف', + '𞹱' => 'ص', + '𞹲' => 'ق', + '𞹴' => 'ش', + '𞹵' => 'ت', + '𞹶' => 'ث', + '𞹷' => 'خ', + '𞹹' => 'ض', + '𞹺' => 'ظ', + '𞹻' => 'غ', + '𞹼' => 'ٮ', + '𞹾' => 'ڡ', + '𞺀' => 'ا', + '𞺁' => 'ب', + '𞺂' => 'ج', + '𞺃' => 'د', + '𞺄' => 'ه', + '𞺅' => 'و', + '𞺆' => 'ز', + '𞺇' => 'ح', + '𞺈' => 'ط', + '𞺉' => 'ي', + '𞺋' => 'ل', + '𞺌' => 'م', + '𞺍' => 'ن', + '𞺎' => 'س', + '𞺏' => 'ع', + '𞺐' => 'ف', + '𞺑' => 'ص', + '𞺒' => 'ق', + '𞺓' => 'ر', + '𞺔' => 'ش', + '𞺕' => 'ت', + '𞺖' => 'ث', + '𞺗' => 'خ', + '𞺘' => 'ذ', + '𞺙' => 'ض', + '𞺚' => 'ظ', + '𞺛' => 'غ', + '𞺡' => 'ب', + '𞺢' => 'ج', + '𞺣' => 'د', + '𞺥' => 'و', + '𞺦' => 'ز', + '𞺧' => 'ح', + '𞺨' => 'ط', + '𞺩' => 'ي', + '𞺫' => 'ل', + '𞺬' => 'م', + '𞺭' => 'ن', + '𞺮' => 'س', + '𞺯' => 'ع', + '𞺰' => 'ف', + '𞺱' => 'ص', + '𞺲' => 'ق', + '𞺳' => 'ر', + '𞺴' => 'ش', + '𞺵' => 'ت', + '𞺶' => 'ث', + '𞺷' => 'خ', + '𞺸' => 'ذ', + '𞺹' => 'ض', + '𞺺' => 'ظ', + '𞺻' => 'غ', + '🄀' => '0.', + '🄁' => '0,', + '🄂' => '1,', + '🄃' => '2,', + '🄄' => '3,', + '🄅' => '4,', + '🄆' => '5,', + '🄇' => '6,', + '🄈' => '7,', + '🄉' => '8,', + '🄊' => '9,', + '🄐' => '(A)', + '🄑' => '(B)', + '🄒' => '(C)', + '🄓' => '(D)', + '🄔' => '(E)', + '🄕' => '(F)', + '🄖' => '(G)', + '🄗' => '(H)', + '🄘' => '(I)', + '🄙' => '(J)', + '🄚' => '(K)', + '🄛' => '(L)', + '🄜' => '(M)', + '🄝' => '(N)', + '🄞' => '(O)', + '🄟' => '(P)', + '🄠' => '(Q)', + '🄡' => '(R)', + '🄢' => '(S)', + '🄣' => '(T)', + '🄤' => '(U)', + '🄥' => '(V)', + '🄦' => '(W)', + '🄧' => '(X)', + '🄨' => '(Y)', + '🄩' => '(Z)', + '🄪' => '〔S〕', + '🄫' => 'C', + '🄬' => 'R', + '🄭' => 'CD', + '🄮' => 'WZ', + '🄰' => 'A', + '🄱' => 'B', + '🄲' => 'C', + '🄳' => 'D', + '🄴' => 'E', + '🄵' => 'F', + '🄶' => 'G', + '🄷' => 'H', + '🄸' => 'I', + '🄹' => 'J', + '🄺' => 'K', + '🄻' => 'L', + '🄼' => 'M', + '🄽' => 'N', + '🄾' => 'O', + '🄿' => 'P', + '🅀' => 'Q', + '🅁' => 'R', + '🅂' => 'S', + '🅃' => 'T', + '🅄' => 'U', + '🅅' => 'V', + '🅆' => 'W', + '🅇' => 'X', + '🅈' => 'Y', + '🅉' => 'Z', + '🅊' => 'HV', + '🅋' => 'MV', + '🅌' => 'SD', + '🅍' => 'SS', + '🅎' => 'PPV', + '🅏' => 'WC', + '🅪' => 'MC', + '🅫' => 'MD', + '🅬' => 'MR', + '🆐' => 'DJ', + '🈀' => 'ほか', + '🈁' => 'ココ', + '🈂' => 'サ', + '🈐' => '手', + '🈑' => '字', + '🈒' => '双', + '🈓' => 'デ', + '🈔' => '二', + '🈕' => '多', + '🈖' => '解', + '🈗' => '天', + '🈘' => '交', + '🈙' => '映', + '🈚' => '無', + '🈛' => '料', + '🈜' => '前', + '🈝' => '後', + '🈞' => '再', + '🈟' => '新', + '🈠' => '初', + '🈡' => '終', + '🈢' => '生', + '🈣' => '販', + '🈤' => '声', + '🈥' => '吹', + '🈦' => '演', + '🈧' => '投', + '🈨' => '捕', + '🈩' => '一', + '🈪' => '三', + '🈫' => '遊', + '🈬' => '左', + '🈭' => '中', + '🈮' => '右', + '🈯' => '指', + '🈰' => '走', + '🈱' => '打', + '🈲' => '禁', + '🈳' => '空', + '🈴' => '合', + '🈵' => '満', + '🈶' => '有', + '🈷' => '月', + '🈸' => '申', + '🈹' => '割', + '🈺' => '営', + '🈻' => '配', + '🉀' => '〔本〕', + '🉁' => '〔三〕', + '🉂' => '〔二〕', + '🉃' => '〔安〕', + '🉄' => '〔点〕', + '🉅' => '〔打〕', + '🉆' => '〔盗〕', + '🉇' => '〔勝〕', + '🉈' => '〔敗〕', + '🉐' => '得', + '🉑' => '可', + '🯰' => '0', + '🯱' => '1', + '🯲' => '2', + '🯳' => '3', + '🯴' => '4', + '🯵' => '5', + '🯶' => '6', + '🯷' => '7', + '🯸' => '8', + '🯹' => '9', +); diff --git a/tools/mailer/symfony/polyfill-intl-normalizer/bootstrap.php b/tools/mailer/symfony/polyfill-intl-normalizer/bootstrap.php new file mode 100644 index 000000000..3608e5c05 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-normalizer/bootstrap.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Intl\Normalizer as p; + +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__.'/bootstrap80.php'; +} + +if (!function_exists('normalizer_is_normalized')) { + function normalizer_is_normalized($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::isNormalized($string, $form); } +} +if (!function_exists('normalizer_normalize')) { + function normalizer_normalize($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::normalize($string, $form); } +} diff --git a/tools/mailer/symfony/polyfill-intl-normalizer/bootstrap80.php b/tools/mailer/symfony/polyfill-intl-normalizer/bootstrap80.php new file mode 100644 index 000000000..e36d1a947 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-normalizer/bootstrap80.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Intl\Normalizer as p; + +if (!function_exists('normalizer_is_normalized')) { + function normalizer_is_normalized(?string $string, ?int $form = p\Normalizer::FORM_C): bool { return p\Normalizer::isNormalized((string) $string, (int) $form); } +} +if (!function_exists('normalizer_normalize')) { + function normalizer_normalize(?string $string, ?int $form = p\Normalizer::FORM_C): string|false { return p\Normalizer::normalize((string) $string, (int) $form); } +} diff --git a/tools/mailer/symfony/polyfill-intl-normalizer/composer.json b/tools/mailer/symfony/polyfill-intl-normalizer/composer.json new file mode 100644 index 000000000..9bd04e887 --- /dev/null +++ b/tools/mailer/symfony/polyfill-intl-normalizer/composer.json @@ -0,0 +1,36 @@ +{ + "name": "symfony/polyfill-intl-normalizer", + "type": "library", + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "keywords": ["polyfill", "shim", "compatibility", "portable", "intl", "normalizer"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "suggest": { + "ext-intl": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/tools/mailer/symfony/polyfill-mbstring/LICENSE b/tools/mailer/symfony/polyfill-mbstring/LICENSE new file mode 100644 index 000000000..6e3afce69 --- /dev/null +++ b/tools/mailer/symfony/polyfill-mbstring/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-present Fabien Potencier + +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/tools/mailer/symfony/polyfill-mbstring/Mbstring.php b/tools/mailer/symfony/polyfill-mbstring/Mbstring.php new file mode 100644 index 000000000..3d45c9d9a --- /dev/null +++ b/tools/mailer/symfony/polyfill-mbstring/Mbstring.php @@ -0,0 +1,1045 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Mbstring; + +/** + * Partial mbstring implementation in PHP, iconv based, UTF-8 centric. + * + * Implemented: + * - mb_chr - Returns a specific character from its Unicode code point + * - mb_convert_encoding - Convert character encoding + * - mb_convert_variables - Convert character code in variable(s) + * - mb_decode_mimeheader - Decode string in MIME header field + * - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED + * - mb_decode_numericentity - Decode HTML numeric string reference to character + * - mb_encode_numericentity - Encode character to HTML numeric string reference + * - mb_convert_case - Perform case folding on a string + * - mb_detect_encoding - Detect character encoding + * - mb_get_info - Get internal settings of mbstring + * - mb_http_input - Detect HTTP input character encoding + * - mb_http_output - Set/Get HTTP output character encoding + * - mb_internal_encoding - Set/Get internal character encoding + * - mb_list_encodings - Returns an array of all supported encodings + * - mb_ord - Returns the Unicode code point of a character + * - mb_output_handler - Callback function converts character encoding in output buffer + * - mb_scrub - Replaces ill-formed byte sequences with substitute characters + * - mb_strlen - Get string length + * - mb_strpos - Find position of first occurrence of string in a string + * - mb_strrpos - Find position of last occurrence of a string in a string + * - mb_str_split - Convert a string to an array + * - mb_strtolower - Make a string lowercase + * - mb_strtoupper - Make a string uppercase + * - mb_substitute_character - Set/Get substitution character + * - mb_substr - Get part of string + * - mb_stripos - Finds position of first occurrence of a string within another, case insensitive + * - mb_stristr - Finds first occurrence of a string within another, case insensitive + * - mb_strrchr - Finds the last occurrence of a character in a string within another + * - mb_strrichr - Finds the last occurrence of a character in a string within another, case insensitive + * - mb_strripos - Finds position of last occurrence of a string within another, case insensitive + * - mb_strstr - Finds first occurrence of a string within another + * - mb_strwidth - Return width of string + * - mb_substr_count - Count the number of substring occurrences + * - mb_ucfirst - Make a string's first character uppercase + * - mb_lcfirst - Make a string's first character lowercase + * - mb_trim - Strip whitespace (or other characters) from the beginning and end of a string + * - mb_ltrim - Strip whitespace (or other characters) from the beginning of a string + * - mb_rtrim - Strip whitespace (or other characters) from the end of a string + * + * Not implemented: + * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more) + * - mb_ereg_* - Regular expression with multibyte support + * - mb_parse_str - Parse GET/POST/COOKIE data and set global variable + * - mb_preferred_mime_name - Get MIME charset string + * - mb_regex_encoding - Returns current encoding for multibyte regex as string + * - mb_regex_set_options - Set/Get the default options for mbregex functions + * - mb_send_mail - Send encoded mail + * - mb_split - Split multibyte string using regular expression + * - mb_strcut - Get part of string + * - mb_strimwidth - Get truncated string with specified width + * + * @author Nicolas Grekas + * + * @internal + */ +final class Mbstring +{ + public const MB_CASE_FOLD = \PHP_INT_MAX; + + private const SIMPLE_CASE_FOLD = [ + ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], + ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], + ]; + + private static $encodingList = ['ASCII', 'UTF-8']; + private static $language = 'neutral'; + private static $internalEncoding = 'UTF-8'; + + public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null) + { + if (\is_array($s)) { + $r = []; + foreach ($s as $str) { + $r[] = self::mb_convert_encoding($str, $toEncoding, $fromEncoding); + } + + return $r; + } + + if (\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) { + $fromEncoding = self::mb_detect_encoding($s, $fromEncoding); + } else { + $fromEncoding = self::getEncoding($fromEncoding); + } + + $toEncoding = self::getEncoding($toEncoding); + + if ('BASE64' === $fromEncoding) { + $s = base64_decode($s); + $fromEncoding = $toEncoding; + } + + if ('BASE64' === $toEncoding) { + return base64_encode($s); + } + + if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) { + if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) { + $fromEncoding = 'Windows-1252'; + } + if ('UTF-8' !== $fromEncoding) { + $s = iconv($fromEncoding, 'UTF-8//IGNORE', $s); + } + + return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s); + } + + if ('HTML-ENTITIES' === $fromEncoding) { + $s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8'); + $fromEncoding = 'UTF-8'; + } + + return iconv($fromEncoding, $toEncoding.'//IGNORE', $s); + } + + public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars) + { + $ok = true; + array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) { + if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) { + $ok = false; + } + }); + + return $ok ? $fromEncoding : false; + } + + public static function mb_decode_mimeheader($s) + { + return iconv_mime_decode($s, 2, self::$internalEncoding); + } + + public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null) + { + trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING); + } + + public static function mb_decode_numericentity($s, $convmap, $encoding = null) + { + if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) { + trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING); + + return null; + } + + if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) { + return false; + } + + if (null !== $encoding && !\is_scalar($encoding)) { + trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING); + + return ''; // Instead of null (cf. mb_encode_numericentity). + } + + $s = (string) $s; + if ('' === $s) { + return ''; + } + + $encoding = self::getEncoding($encoding); + + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $s)) { + $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s); + } + } else { + $s = iconv($encoding, 'UTF-8//IGNORE', $s); + } + + $cnt = floor(\count($convmap) / 4) * 4; + + for ($i = 0; $i < $cnt; $i += 4) { + // collector_decode_htmlnumericentity ignores $convmap[$i + 3] + $convmap[$i] += $convmap[$i + 2]; + $convmap[$i + 1] += $convmap[$i + 2]; + } + + $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) { + $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1]; + for ($i = 0; $i < $cnt; $i += 4) { + if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) { + return self::mb_chr($c - $convmap[$i + 2]); + } + } + + return $m[0]; + }, $s); + + if (null === $encoding) { + return $s; + } + + return iconv('UTF-8', $encoding.'//IGNORE', $s); + } + + public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false) + { + if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) { + trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING); + + return null; + } + + if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) { + return false; + } + + if (null !== $encoding && !\is_scalar($encoding)) { + trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING); + + return null; // Instead of '' (cf. mb_decode_numericentity). + } + + if (null !== $is_hex && !\is_scalar($is_hex)) { + trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING); + + return null; + } + + $s = (string) $s; + if ('' === $s) { + return ''; + } + + $encoding = self::getEncoding($encoding); + + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $s)) { + $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s); + } + } else { + $s = iconv($encoding, 'UTF-8//IGNORE', $s); + } + + static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; + + $cnt = floor(\count($convmap) / 4) * 4; + $i = 0; + $len = \strlen($s); + $result = ''; + + while ($i < $len) { + $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"]; + $uchr = substr($s, $i, $ulen); + $i += $ulen; + $c = self::mb_ord($uchr); + + for ($j = 0; $j < $cnt; $j += 4) { + if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) { + $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3]; + $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';'; + continue 2; + } + } + $result .= $uchr; + } + + if (null === $encoding) { + return $result; + } + + return iconv('UTF-8', $encoding.'//IGNORE', $result); + } + + public static function mb_convert_case($s, $mode, $encoding = null) + { + $s = (string) $s; + if ('' === $s) { + return ''; + } + + $encoding = self::getEncoding($encoding); + + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $s)) { + $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s); + } + } else { + $s = iconv($encoding, 'UTF-8//IGNORE', $s); + } + + if (\MB_CASE_TITLE == $mode) { + static $titleRegexp = null; + if (null === $titleRegexp) { + $titleRegexp = self::getData('titleCaseRegexp'); + } + $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s); + } else { + if (\MB_CASE_UPPER == $mode) { + static $upper = null; + if (null === $upper) { + $upper = self::getData('upperCase'); + } + $map = $upper; + } else { + if (self::MB_CASE_FOLD === $mode) { + static $caseFolding = null; + if (null === $caseFolding) { + $caseFolding = self::getData('caseFolding'); + } + $s = strtr($s, $caseFolding); + } + + static $lower = null; + if (null === $lower) { + $lower = self::getData('lowerCase'); + } + $map = $lower; + } + + static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; + + $i = 0; + $len = \strlen($s); + + while ($i < $len) { + $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"]; + $uchr = substr($s, $i, $ulen); + $i += $ulen; + + if (isset($map[$uchr])) { + $uchr = $map[$uchr]; + $nlen = \strlen($uchr); + + if ($nlen == $ulen) { + $nlen = $i; + do { + $s[--$nlen] = $uchr[--$ulen]; + } while ($ulen); + } else { + $s = substr_replace($s, $uchr, $i - $ulen, $ulen); + $len += $nlen - $ulen; + $i += $nlen - $ulen; + } + } + } + } + + if (null === $encoding) { + return $s; + } + + return iconv('UTF-8', $encoding.'//IGNORE', $s); + } + + public static function mb_internal_encoding($encoding = null) + { + if (null === $encoding) { + return self::$internalEncoding; + } + + $normalizedEncoding = self::getEncoding($encoding); + + if ('UTF-8' === $normalizedEncoding || false !== @iconv($normalizedEncoding, $normalizedEncoding, ' ')) { + self::$internalEncoding = $normalizedEncoding; + + return true; + } + + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding)); + } + + public static function mb_language($lang = null) + { + if (null === $lang) { + return self::$language; + } + + switch ($normalizedLang = strtolower($lang)) { + case 'uni': + case 'neutral': + self::$language = $normalizedLang; + + return true; + } + + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang)); + } + + public static function mb_list_encodings() + { + return ['UTF-8']; + } + + public static function mb_encoding_aliases($encoding) + { + switch (strtoupper($encoding)) { + case 'UTF8': + case 'UTF-8': + return ['utf8']; + } + + return false; + } + + public static function mb_check_encoding($var = null, $encoding = null) + { + if (null === $encoding) { + if (null === $var) { + return false; + } + $encoding = self::$internalEncoding; + } + + if (!\is_array($var)) { + return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var); + } + + foreach ($var as $key => $value) { + if (!self::mb_check_encoding($key, $encoding)) { + return false; + } + if (!self::mb_check_encoding($value, $encoding)) { + return false; + } + } + + return true; + } + + public static function mb_detect_encoding($str, $encodingList = null, $strict = false) + { + if (null === $encodingList) { + $encodingList = self::$encodingList; + } else { + if (!\is_array($encodingList)) { + $encodingList = array_map('trim', explode(',', $encodingList)); + } + $encodingList = array_map('strtoupper', $encodingList); + } + + foreach ($encodingList as $enc) { + switch ($enc) { + case 'ASCII': + if (!preg_match('/[\x80-\xFF]/', $str)) { + return $enc; + } + break; + + case 'UTF8': + case 'UTF-8': + if (preg_match('//u', $str)) { + return 'UTF-8'; + } + break; + + default: + if (0 === strncmp($enc, 'ISO-8859-', 9)) { + return $enc; + } + } + } + + return false; + } + + public static function mb_detect_order($encodingList = null) + { + if (null === $encodingList) { + return self::$encodingList; + } + + if (!\is_array($encodingList)) { + $encodingList = array_map('trim', explode(',', $encodingList)); + } + $encodingList = array_map('strtoupper', $encodingList); + + foreach ($encodingList as $enc) { + switch ($enc) { + default: + if (strncmp($enc, 'ISO-8859-', 9)) { + return false; + } + // no break + case 'ASCII': + case 'UTF8': + case 'UTF-8': + } + } + + self::$encodingList = $encodingList; + + return true; + } + + public static function mb_strlen($s, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return \strlen($s); + } + + return @iconv_strlen($s, $encoding); + } + + public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return strpos($haystack, $needle, $offset); + } + + $needle = (string) $needle; + if ('' === $needle) { + if (80000 > \PHP_VERSION_ID) { + trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING); + + return false; + } + + return 0; + } + + return iconv_strpos($haystack, $needle, $offset, $encoding); + } + + public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return strrpos($haystack, $needle, $offset); + } + + if ($offset != (int) $offset) { + $offset = 0; + } elseif ($offset = (int) $offset) { + if ($offset < 0) { + if (0 > $offset += self::mb_strlen($needle)) { + $haystack = self::mb_substr($haystack, 0, $offset, $encoding); + } + $offset = 0; + } else { + $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding); + } + } + + $pos = '' !== $needle || 80000 > \PHP_VERSION_ID + ? iconv_strrpos($haystack, $needle, $encoding) + : self::mb_strlen($haystack, $encoding); + + return false !== $pos ? $offset + $pos : false; + } + + public static function mb_str_split($string, $split_length = 1, $encoding = null) + { + if (null !== $string && !\is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) { + trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING); + + return null; + } + + if (1 > $split_length = (int) $split_length) { + if (80000 > \PHP_VERSION_ID) { + trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING); + + return false; + } + + throw new \ValueError('Argument #2 ($length) must be greater than 0'); + } + + if (null === $encoding) { + $encoding = mb_internal_encoding(); + } + + if ('UTF-8' === $encoding = self::getEncoding($encoding)) { + $rx = '/('; + while (65535 < $split_length) { + $rx .= '.{65535}'; + $split_length -= 65535; + } + $rx .= '.{'.$split_length.'})/us'; + + return preg_split($rx, $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); + } + + $result = []; + $length = mb_strlen($string, $encoding); + + for ($i = 0; $i < $length; $i += $split_length) { + $result[] = mb_substr($string, $i, $split_length, $encoding); + } + + return $result; + } + + public static function mb_strtolower($s, $encoding = null) + { + return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding); + } + + public static function mb_strtoupper($s, $encoding = null) + { + return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding); + } + + public static function mb_substitute_character($c = null) + { + if (null === $c) { + return 'none'; + } + if (0 === strcasecmp($c, 'none')) { + return true; + } + if (80000 > \PHP_VERSION_ID) { + return false; + } + if (\is_int($c) || 'long' === $c || 'entity' === $c) { + return false; + } + + throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint'); + } + + public static function mb_substr($s, $start, $length = null, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return (string) substr($s, $start, null === $length ? 2147483647 : $length); + } + + if ($start < 0) { + $start = iconv_strlen($s, $encoding) + $start; + if ($start < 0) { + $start = 0; + } + } + + if (null === $length) { + $length = 2147483647; + } elseif ($length < 0) { + $length = iconv_strlen($s, $encoding) + $length - $start; + if ($length < 0) { + return ''; + } + } + + return (string) iconv_substr($s, $start, $length, $encoding); + } + + public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) + { + [$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [ + self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding), + self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding), + ]); + + return self::mb_strpos($haystack, $needle, $offset, $encoding); + } + + public static function mb_stristr($haystack, $needle, $part = false, $encoding = null) + { + $pos = self::mb_stripos($haystack, $needle, 0, $encoding); + + return self::getSubpart($pos, $part, $haystack, $encoding); + } + + public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + $pos = strrpos($haystack, $needle); + } else { + $needle = self::mb_substr($needle, 0, 1, $encoding); + $pos = iconv_strrpos($haystack, $needle, $encoding); + } + + return self::getSubpart($pos, $part, $haystack, $encoding); + } + + public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null) + { + $needle = self::mb_substr($needle, 0, 1, $encoding); + $pos = self::mb_strripos($haystack, $needle, $encoding); + + return self::getSubpart($pos, $part, $haystack, $encoding); + } + + public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) + { + $haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding); + $needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding); + + $haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack); + $needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle); + + return self::mb_strrpos($haystack, $needle, $offset, $encoding); + } + + public static function mb_strstr($haystack, $needle, $part = false, $encoding = null) + { + $pos = strpos($haystack, $needle); + if (false === $pos) { + return false; + } + if ($part) { + return substr($haystack, 0, $pos); + } + + return substr($haystack, $pos); + } + + public static function mb_get_info($type = 'all') + { + $info = [ + 'internal_encoding' => self::$internalEncoding, + 'http_output' => 'pass', + 'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)', + 'func_overload' => 0, + 'func_overload_list' => 'no overload', + 'mail_charset' => 'UTF-8', + 'mail_header_encoding' => 'BASE64', + 'mail_body_encoding' => 'BASE64', + 'illegal_chars' => 0, + 'encoding_translation' => 'Off', + 'language' => self::$language, + 'detect_order' => self::$encodingList, + 'substitute_character' => 'none', + 'strict_detection' => 'Off', + ]; + + if ('all' === $type) { + return $info; + } + if (isset($info[$type])) { + return $info[$type]; + } + + return false; + } + + public static function mb_http_input($type = '') + { + return false; + } + + public static function mb_http_output($encoding = null) + { + return null !== $encoding ? 'pass' === $encoding : 'pass'; + } + + public static function mb_strwidth($s, $encoding = null) + { + $encoding = self::getEncoding($encoding); + + if ('UTF-8' !== $encoding) { + $s = iconv($encoding, 'UTF-8//IGNORE', $s); + } + + $s = preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide); + + return ($wide << 1) + iconv_strlen($s, 'UTF-8'); + } + + public static function mb_substr_count($haystack, $needle, $encoding = null) + { + return substr_count($haystack, $needle); + } + + public static function mb_output_handler($contents, $status) + { + return $contents; + } + + public static function mb_chr($code, $encoding = null) + { + if (0x80 > $code %= 0x200000) { + $s = \chr($code); + } elseif (0x800 > $code) { + $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F); + } elseif (0x10000 > $code) { + $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); + } else { + $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); + } + + if ('UTF-8' !== $encoding = self::getEncoding($encoding)) { + $s = mb_convert_encoding($s, $encoding, 'UTF-8'); + } + + return $s; + } + + public static function mb_ord($s, $encoding = null) + { + if ('UTF-8' !== $encoding = self::getEncoding($encoding)) { + $s = mb_convert_encoding($s, 'UTF-8', $encoding); + } + + if (1 === \strlen($s)) { + return \ord($s); + } + + $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0; + if (0xF0 <= $code) { + return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80; + } + if (0xE0 <= $code) { + return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80; + } + if (0xC0 <= $code) { + return (($code - 0xC0) << 6) + $s[2] - 0x80; + } + + return $code; + } + + public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null): string + { + if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) { + throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH'); + } + + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given'); + } + + if (self::mb_strlen($pad_string, $encoding) <= 0) { + throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string'); + } + + $paddingRequired = $length - self::mb_strlen($string, $encoding); + + if ($paddingRequired < 1) { + return $string; + } + + switch ($pad_type) { + case \STR_PAD_LEFT: + return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string; + case \STR_PAD_RIGHT: + return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding); + default: + $leftPaddingLength = floor($paddingRequired / 2); + $rightPaddingLength = $paddingRequired - $leftPaddingLength; + + return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding); + } + } + + public static function mb_ucfirst(string $string, ?string $encoding = null): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given'); + } + + $firstChar = mb_substr($string, 0, 1, $encoding); + $firstChar = mb_convert_case($firstChar, \MB_CASE_TITLE, $encoding); + + return $firstChar.mb_substr($string, 1, null, $encoding); + } + + public static function mb_lcfirst(string $string, ?string $encoding = null): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given'); + } + + $firstChar = mb_substr($string, 0, 1, $encoding); + $firstChar = mb_convert_case($firstChar, \MB_CASE_LOWER, $encoding); + + return $firstChar.mb_substr($string, 1, null, $encoding); + } + + private static function getSubpart($pos, $part, $haystack, $encoding) + { + if (false === $pos) { + return false; + } + if ($part) { + return self::mb_substr($haystack, 0, $pos, $encoding); + } + + return self::mb_substr($haystack, $pos, null, $encoding); + } + + private static function html_encoding_callback(array $m) + { + $i = 1; + $entities = ''; + $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8')); + + while (isset($m[$i])) { + if (0x80 > $m[$i]) { + $entities .= \chr($m[$i++]); + continue; + } + if (0xF0 <= $m[$i]) { + $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; + } elseif (0xE0 <= $m[$i]) { + $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; + } else { + $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80; + } + + $entities .= '&#'.$c.';'; + } + + return $entities; + } + + private static function title_case(array $s) + { + return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8'); + } + + private static function getData($file) + { + if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) { + return require $file; + } + + return false; + } + + private static function getEncoding($encoding) + { + if (null === $encoding) { + return self::$internalEncoding; + } + + if ('UTF-8' === $encoding) { + return 'UTF-8'; + } + + $encoding = strtoupper($encoding); + + if ('8BIT' === $encoding || 'BINARY' === $encoding) { + return 'CP850'; + } + + if ('UTF8' === $encoding) { + return 'UTF-8'; + } + + return $encoding; + } + + public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__); + } + + public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__); + } + + public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{[%s]+$}D', $string, $characters, $encoding, __FUNCTION__); + } + + private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, $function.'(): Argument #3 ($encoding) must be a valid encoding, "%s" given'); + } + + if ('' === $characters) { + return null === $encoding ? $string : self::mb_convert_encoding($string, $encoding); + } + + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $string)) { + $string = @iconv('UTF-8', 'UTF-8//IGNORE', $string); + } + if (null !== $characters && !preg_match('//u', $characters)) { + $characters = @iconv('UTF-8', 'UTF-8//IGNORE', $characters); + } + } else { + $string = iconv($encoding, 'UTF-8//IGNORE', $string); + + if (null !== $characters) { + $characters = iconv($encoding, 'UTF-8//IGNORE', $characters); + } + } + + if (null === $characters) { + $characters = "\\0 \f\n\r\t\v\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"; + } else { + $characters = preg_quote($characters); + } + + $string = preg_replace(sprintf($regex, $characters), '', $string); + + if (null === $encoding) { + return $string; + } + + return iconv('UTF-8', $encoding.'//IGNORE', $string); + } + + private static function assertEncoding(string $encoding, string $errorFormat): void + { + try { + $validEncoding = @self::mb_check_encoding('', $encoding); + } catch (\ValueError $e) { + throw new \ValueError(sprintf($errorFormat, $encoding)); + } + + // BC for PHP 7.3 and lower + if (!$validEncoding) { + throw new \ValueError(sprintf($errorFormat, $encoding)); + } + } +} diff --git a/tools/mailer/symfony/polyfill-mbstring/README.md b/tools/mailer/symfony/polyfill-mbstring/README.md new file mode 100644 index 000000000..478b40da2 --- /dev/null +++ b/tools/mailer/symfony/polyfill-mbstring/README.md @@ -0,0 +1,13 @@ +Symfony Polyfill / Mbstring +=========================== + +This component provides a partial, native PHP implementation for the +[Mbstring](https://php.net/mbstring) extension. + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/tools/mailer/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php b/tools/mailer/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php new file mode 100644 index 000000000..512bba0bf --- /dev/null +++ b/tools/mailer/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php @@ -0,0 +1,119 @@ + 'i̇', + 'µ' => 'μ', + 'ſ' => 's', + 'ͅ' => 'ι', + 'ς' => 'σ', + 'ϐ' => 'β', + 'ϑ' => 'θ', + 'ϕ' => 'φ', + 'ϖ' => 'π', + 'ϰ' => 'κ', + 'ϱ' => 'ρ', + 'ϵ' => 'ε', + 'ẛ' => 'ṡ', + 'ι' => 'ι', + 'ß' => 'ss', + 'ʼn' => 'ʼn', + 'ǰ' => 'ǰ', + 'ΐ' => 'ΐ', + 'ΰ' => 'ΰ', + 'և' => 'եւ', + 'ẖ' => 'ẖ', + 'ẗ' => 'ẗ', + 'ẘ' => 'ẘ', + 'ẙ' => 'ẙ', + 'ẚ' => 'aʾ', + 'ẞ' => 'ss', + 'ὐ' => 'ὐ', + 'ὒ' => 'ὒ', + 'ὔ' => 'ὔ', + 'ὖ' => 'ὖ', + 'ᾀ' => 'ἀι', + 'ᾁ' => 'ἁι', + 'ᾂ' => 'ἂι', + 'ᾃ' => 'ἃι', + 'ᾄ' => 'ἄι', + 'ᾅ' => 'ἅι', + 'ᾆ' => 'ἆι', + 'ᾇ' => 'ἇι', + 'ᾈ' => 'ἀι', + 'ᾉ' => 'ἁι', + 'ᾊ' => 'ἂι', + 'ᾋ' => 'ἃι', + 'ᾌ' => 'ἄι', + 'ᾍ' => 'ἅι', + 'ᾎ' => 'ἆι', + 'ᾏ' => 'ἇι', + 'ᾐ' => 'ἠι', + 'ᾑ' => 'ἡι', + 'ᾒ' => 'ἢι', + 'ᾓ' => 'ἣι', + 'ᾔ' => 'ἤι', + 'ᾕ' => 'ἥι', + 'ᾖ' => 'ἦι', + 'ᾗ' => 'ἧι', + 'ᾘ' => 'ἠι', + 'ᾙ' => 'ἡι', + 'ᾚ' => 'ἢι', + 'ᾛ' => 'ἣι', + 'ᾜ' => 'ἤι', + 'ᾝ' => 'ἥι', + 'ᾞ' => 'ἦι', + 'ᾟ' => 'ἧι', + 'ᾠ' => 'ὠι', + 'ᾡ' => 'ὡι', + 'ᾢ' => 'ὢι', + 'ᾣ' => 'ὣι', + 'ᾤ' => 'ὤι', + 'ᾥ' => 'ὥι', + 'ᾦ' => 'ὦι', + 'ᾧ' => 'ὧι', + 'ᾨ' => 'ὠι', + 'ᾩ' => 'ὡι', + 'ᾪ' => 'ὢι', + 'ᾫ' => 'ὣι', + 'ᾬ' => 'ὤι', + 'ᾭ' => 'ὥι', + 'ᾮ' => 'ὦι', + 'ᾯ' => 'ὧι', + 'ᾲ' => 'ὰι', + 'ᾳ' => 'αι', + 'ᾴ' => 'άι', + 'ᾶ' => 'ᾶ', + 'ᾷ' => 'ᾶι', + 'ᾼ' => 'αι', + 'ῂ' => 'ὴι', + 'ῃ' => 'ηι', + 'ῄ' => 'ήι', + 'ῆ' => 'ῆ', + 'ῇ' => 'ῆι', + 'ῌ' => 'ηι', + 'ῒ' => 'ῒ', + 'ῖ' => 'ῖ', + 'ῗ' => 'ῗ', + 'ῢ' => 'ῢ', + 'ῤ' => 'ῤ', + 'ῦ' => 'ῦ', + 'ῧ' => 'ῧ', + 'ῲ' => 'ὼι', + 'ῳ' => 'ωι', + 'ῴ' => 'ώι', + 'ῶ' => 'ῶ', + 'ῷ' => 'ῶι', + 'ῼ' => 'ωι', + 'ff' => 'ff', + 'fi' => 'fi', + 'fl' => 'fl', + 'ffi' => 'ffi', + 'ffl' => 'ffl', + 'ſt' => 'st', + 'st' => 'st', + 'ﬓ' => 'մն', + 'ﬔ' => 'մե', + 'ﬕ' => 'մի', + 'ﬖ' => 'վն', + 'ﬗ' => 'մխ', +]; diff --git a/tools/mailer/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php b/tools/mailer/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php new file mode 100644 index 000000000..fac60b081 --- /dev/null +++ b/tools/mailer/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php @@ -0,0 +1,1397 @@ + 'a', + 'B' => 'b', + 'C' => 'c', + 'D' => 'd', + 'E' => 'e', + 'F' => 'f', + 'G' => 'g', + 'H' => 'h', + 'I' => 'i', + 'J' => 'j', + 'K' => 'k', + 'L' => 'l', + 'M' => 'm', + 'N' => 'n', + 'O' => 'o', + 'P' => 'p', + 'Q' => 'q', + 'R' => 'r', + 'S' => 's', + 'T' => 't', + 'U' => 'u', + 'V' => 'v', + 'W' => 'w', + 'X' => 'x', + 'Y' => 'y', + 'Z' => 'z', + 'À' => 'à', + 'Á' => 'á', + 'Â' => 'â', + 'Ã' => 'ã', + 'Ä' => 'ä', + 'Å' => 'å', + 'Æ' => 'æ', + 'Ç' => 'ç', + 'È' => 'è', + 'É' => 'é', + 'Ê' => 'ê', + 'Ë' => 'ë', + 'Ì' => 'ì', + 'Í' => 'í', + 'Î' => 'î', + 'Ï' => 'ï', + 'Ð' => 'ð', + 'Ñ' => 'ñ', + 'Ò' => 'ò', + 'Ó' => 'ó', + 'Ô' => 'ô', + 'Õ' => 'õ', + 'Ö' => 'ö', + 'Ø' => 'ø', + 'Ù' => 'ù', + 'Ú' => 'ú', + 'Û' => 'û', + 'Ü' => 'ü', + 'Ý' => 'ý', + 'Þ' => 'þ', + 'Ā' => 'ā', + 'Ă' => 'ă', + 'Ą' => 'ą', + 'Ć' => 'ć', + 'Ĉ' => 'ĉ', + 'Ċ' => 'ċ', + 'Č' => 'č', + 'Ď' => 'ď', + 'Đ' => 'đ', + 'Ē' => 'ē', + 'Ĕ' => 'ĕ', + 'Ė' => 'ė', + 'Ę' => 'ę', + 'Ě' => 'ě', + 'Ĝ' => 'ĝ', + 'Ğ' => 'ğ', + 'Ġ' => 'ġ', + 'Ģ' => 'ģ', + 'Ĥ' => 'ĥ', + 'Ħ' => 'ħ', + 'Ĩ' => 'ĩ', + 'Ī' => 'ī', + 'Ĭ' => 'ĭ', + 'Į' => 'į', + 'İ' => 'i̇', + 'IJ' => 'ij', + 'Ĵ' => 'ĵ', + 'Ķ' => 'ķ', + 'Ĺ' => 'ĺ', + 'Ļ' => 'ļ', + 'Ľ' => 'ľ', + 'Ŀ' => 'ŀ', + 'Ł' => 'ł', + 'Ń' => 'ń', + 'Ņ' => 'ņ', + 'Ň' => 'ň', + 'Ŋ' => 'ŋ', + 'Ō' => 'ō', + 'Ŏ' => 'ŏ', + 'Ő' => 'ő', + 'Œ' => 'œ', + 'Ŕ' => 'ŕ', + 'Ŗ' => 'ŗ', + 'Ř' => 'ř', + 'Ś' => 'ś', + 'Ŝ' => 'ŝ', + 'Ş' => 'ş', + 'Š' => 'š', + 'Ţ' => 'ţ', + 'Ť' => 'ť', + 'Ŧ' => 'ŧ', + 'Ũ' => 'ũ', + 'Ū' => 'ū', + 'Ŭ' => 'ŭ', + 'Ů' => 'ů', + 'Ű' => 'ű', + 'Ų' => 'ų', + 'Ŵ' => 'ŵ', + 'Ŷ' => 'ŷ', + 'Ÿ' => 'ÿ', + 'Ź' => 'ź', + 'Ż' => 'ż', + 'Ž' => 'ž', + 'Ɓ' => 'ɓ', + 'Ƃ' => 'ƃ', + 'Ƅ' => 'ƅ', + 'Ɔ' => 'ɔ', + 'Ƈ' => 'ƈ', + 'Ɖ' => 'ɖ', + 'Ɗ' => 'ɗ', + 'Ƌ' => 'ƌ', + 'Ǝ' => 'ǝ', + 'Ə' => 'ə', + 'Ɛ' => 'ɛ', + 'Ƒ' => 'ƒ', + 'Ɠ' => 'ɠ', + 'Ɣ' => 'ɣ', + 'Ɩ' => 'ɩ', + 'Ɨ' => 'ɨ', + 'Ƙ' => 'ƙ', + 'Ɯ' => 'ɯ', + 'Ɲ' => 'ɲ', + 'Ɵ' => 'ɵ', + 'Ơ' => 'ơ', + 'Ƣ' => 'ƣ', + 'Ƥ' => 'ƥ', + 'Ʀ' => 'ʀ', + 'Ƨ' => 'ƨ', + 'Ʃ' => 'ʃ', + 'Ƭ' => 'ƭ', + 'Ʈ' => 'ʈ', + 'Ư' => 'ư', + 'Ʊ' => 'ʊ', + 'Ʋ' => 'ʋ', + 'Ƴ' => 'ƴ', + 'Ƶ' => 'ƶ', + 'Ʒ' => 'ʒ', + 'Ƹ' => 'ƹ', + 'Ƽ' => 'ƽ', + 'DŽ' => 'dž', + 'Dž' => 'dž', + 'LJ' => 'lj', + 'Lj' => 'lj', + 'NJ' => 'nj', + 'Nj' => 'nj', + 'Ǎ' => 'ǎ', + 'Ǐ' => 'ǐ', + 'Ǒ' => 'ǒ', + 'Ǔ' => 'ǔ', + 'Ǖ' => 'ǖ', + 'Ǘ' => 'ǘ', + 'Ǚ' => 'ǚ', + 'Ǜ' => 'ǜ', + 'Ǟ' => 'ǟ', + 'Ǡ' => 'ǡ', + 'Ǣ' => 'ǣ', + 'Ǥ' => 'ǥ', + 'Ǧ' => 'ǧ', + 'Ǩ' => 'ǩ', + 'Ǫ' => 'ǫ', + 'Ǭ' => 'ǭ', + 'Ǯ' => 'ǯ', + 'DZ' => 'dz', + 'Dz' => 'dz', + 'Ǵ' => 'ǵ', + 'Ƕ' => 'ƕ', + 'Ƿ' => 'ƿ', + 'Ǹ' => 'ǹ', + 'Ǻ' => 'ǻ', + 'Ǽ' => 'ǽ', + 'Ǿ' => 'ǿ', + 'Ȁ' => 'ȁ', + 'Ȃ' => 'ȃ', + 'Ȅ' => 'ȅ', + 'Ȇ' => 'ȇ', + 'Ȉ' => 'ȉ', + 'Ȋ' => 'ȋ', + 'Ȍ' => 'ȍ', + 'Ȏ' => 'ȏ', + 'Ȑ' => 'ȑ', + 'Ȓ' => 'ȓ', + 'Ȕ' => 'ȕ', + 'Ȗ' => 'ȗ', + 'Ș' => 'ș', + 'Ț' => 'ț', + 'Ȝ' => 'ȝ', + 'Ȟ' => 'ȟ', + 'Ƞ' => 'ƞ', + 'Ȣ' => 'ȣ', + 'Ȥ' => 'ȥ', + 'Ȧ' => 'ȧ', + 'Ȩ' => 'ȩ', + 'Ȫ' => 'ȫ', + 'Ȭ' => 'ȭ', + 'Ȯ' => 'ȯ', + 'Ȱ' => 'ȱ', + 'Ȳ' => 'ȳ', + 'Ⱥ' => 'ⱥ', + 'Ȼ' => 'ȼ', + 'Ƚ' => 'ƚ', + 'Ⱦ' => 'ⱦ', + 'Ɂ' => 'ɂ', + 'Ƀ' => 'ƀ', + 'Ʉ' => 'ʉ', + 'Ʌ' => 'ʌ', + 'Ɇ' => 'ɇ', + 'Ɉ' => 'ɉ', + 'Ɋ' => 'ɋ', + 'Ɍ' => 'ɍ', + 'Ɏ' => 'ɏ', + 'Ͱ' => 'ͱ', + 'Ͳ' => 'ͳ', + 'Ͷ' => 'ͷ', + 'Ϳ' => 'ϳ', + 'Ά' => 'ά', + 'Έ' => 'έ', + 'Ή' => 'ή', + 'Ί' => 'ί', + 'Ό' => 'ό', + 'Ύ' => 'ύ', + 'Ώ' => 'ώ', + 'Α' => 'α', + 'Β' => 'β', + 'Γ' => 'γ', + 'Δ' => 'δ', + 'Ε' => 'ε', + 'Ζ' => 'ζ', + 'Η' => 'η', + 'Θ' => 'θ', + 'Ι' => 'ι', + 'Κ' => 'κ', + 'Λ' => 'λ', + 'Μ' => 'μ', + 'Ν' => 'ν', + 'Ξ' => 'ξ', + 'Ο' => 'ο', + 'Π' => 'π', + 'Ρ' => 'ρ', + 'Σ' => 'σ', + 'Τ' => 'τ', + 'Υ' => 'υ', + 'Φ' => 'φ', + 'Χ' => 'χ', + 'Ψ' => 'ψ', + 'Ω' => 'ω', + 'Ϊ' => 'ϊ', + 'Ϋ' => 'ϋ', + 'Ϗ' => 'ϗ', + 'Ϙ' => 'ϙ', + 'Ϛ' => 'ϛ', + 'Ϝ' => 'ϝ', + 'Ϟ' => 'ϟ', + 'Ϡ' => 'ϡ', + 'Ϣ' => 'ϣ', + 'Ϥ' => 'ϥ', + 'Ϧ' => 'ϧ', + 'Ϩ' => 'ϩ', + 'Ϫ' => 'ϫ', + 'Ϭ' => 'ϭ', + 'Ϯ' => 'ϯ', + 'ϴ' => 'θ', + 'Ϸ' => 'ϸ', + 'Ϲ' => 'ϲ', + 'Ϻ' => 'ϻ', + 'Ͻ' => 'ͻ', + 'Ͼ' => 'ͼ', + 'Ͽ' => 'ͽ', + 'Ѐ' => 'ѐ', + 'Ё' => 'ё', + 'Ђ' => 'ђ', + 'Ѓ' => 'ѓ', + 'Є' => 'є', + 'Ѕ' => 'ѕ', + 'І' => 'і', + 'Ї' => 'ї', + 'Ј' => 'ј', + 'Љ' => 'љ', + 'Њ' => 'њ', + 'Ћ' => 'ћ', + 'Ќ' => 'ќ', + 'Ѝ' => 'ѝ', + 'Ў' => 'ў', + 'Џ' => 'џ', + 'А' => 'а', + 'Б' => 'б', + 'В' => 'в', + 'Г' => 'г', + 'Д' => 'д', + 'Е' => 'е', + 'Ж' => 'ж', + 'З' => 'з', + 'И' => 'и', + 'Й' => 'й', + 'К' => 'к', + 'Л' => 'л', + 'М' => 'м', + 'Н' => 'н', + 'О' => 'о', + 'П' => 'п', + 'Р' => 'р', + 'С' => 'с', + 'Т' => 'т', + 'У' => 'у', + 'Ф' => 'ф', + 'Х' => 'х', + 'Ц' => 'ц', + 'Ч' => 'ч', + 'Ш' => 'ш', + 'Щ' => 'щ', + 'Ъ' => 'ъ', + 'Ы' => 'ы', + 'Ь' => 'ь', + 'Э' => 'э', + 'Ю' => 'ю', + 'Я' => 'я', + 'Ѡ' => 'ѡ', + 'Ѣ' => 'ѣ', + 'Ѥ' => 'ѥ', + 'Ѧ' => 'ѧ', + 'Ѩ' => 'ѩ', + 'Ѫ' => 'ѫ', + 'Ѭ' => 'ѭ', + 'Ѯ' => 'ѯ', + 'Ѱ' => 'ѱ', + 'Ѳ' => 'ѳ', + 'Ѵ' => 'ѵ', + 'Ѷ' => 'ѷ', + 'Ѹ' => 'ѹ', + 'Ѻ' => 'ѻ', + 'Ѽ' => 'ѽ', + 'Ѿ' => 'ѿ', + 'Ҁ' => 'ҁ', + 'Ҋ' => 'ҋ', + 'Ҍ' => 'ҍ', + 'Ҏ' => 'ҏ', + 'Ґ' => 'ґ', + 'Ғ' => 'ғ', + 'Ҕ' => 'ҕ', + 'Җ' => 'җ', + 'Ҙ' => 'ҙ', + 'Қ' => 'қ', + 'Ҝ' => 'ҝ', + 'Ҟ' => 'ҟ', + 'Ҡ' => 'ҡ', + 'Ң' => 'ң', + 'Ҥ' => 'ҥ', + 'Ҧ' => 'ҧ', + 'Ҩ' => 'ҩ', + 'Ҫ' => 'ҫ', + 'Ҭ' => 'ҭ', + 'Ү' => 'ү', + 'Ұ' => 'ұ', + 'Ҳ' => 'ҳ', + 'Ҵ' => 'ҵ', + 'Ҷ' => 'ҷ', + 'Ҹ' => 'ҹ', + 'Һ' => 'һ', + 'Ҽ' => 'ҽ', + 'Ҿ' => 'ҿ', + 'Ӏ' => 'ӏ', + 'Ӂ' => 'ӂ', + 'Ӄ' => 'ӄ', + 'Ӆ' => 'ӆ', + 'Ӈ' => 'ӈ', + 'Ӊ' => 'ӊ', + 'Ӌ' => 'ӌ', + 'Ӎ' => 'ӎ', + 'Ӑ' => 'ӑ', + 'Ӓ' => 'ӓ', + 'Ӕ' => 'ӕ', + 'Ӗ' => 'ӗ', + 'Ә' => 'ә', + 'Ӛ' => 'ӛ', + 'Ӝ' => 'ӝ', + 'Ӟ' => 'ӟ', + 'Ӡ' => 'ӡ', + 'Ӣ' => 'ӣ', + 'Ӥ' => 'ӥ', + 'Ӧ' => 'ӧ', + 'Ө' => 'ө', + 'Ӫ' => 'ӫ', + 'Ӭ' => 'ӭ', + 'Ӯ' => 'ӯ', + 'Ӱ' => 'ӱ', + 'Ӳ' => 'ӳ', + 'Ӵ' => 'ӵ', + 'Ӷ' => 'ӷ', + 'Ӹ' => 'ӹ', + 'Ӻ' => 'ӻ', + 'Ӽ' => 'ӽ', + 'Ӿ' => 'ӿ', + 'Ԁ' => 'ԁ', + 'Ԃ' => 'ԃ', + 'Ԅ' => 'ԅ', + 'Ԇ' => 'ԇ', + 'Ԉ' => 'ԉ', + 'Ԋ' => 'ԋ', + 'Ԍ' => 'ԍ', + 'Ԏ' => 'ԏ', + 'Ԑ' => 'ԑ', + 'Ԓ' => 'ԓ', + 'Ԕ' => 'ԕ', + 'Ԗ' => 'ԗ', + 'Ԙ' => 'ԙ', + 'Ԛ' => 'ԛ', + 'Ԝ' => 'ԝ', + 'Ԟ' => 'ԟ', + 'Ԡ' => 'ԡ', + 'Ԣ' => 'ԣ', + 'Ԥ' => 'ԥ', + 'Ԧ' => 'ԧ', + 'Ԩ' => 'ԩ', + 'Ԫ' => 'ԫ', + 'Ԭ' => 'ԭ', + 'Ԯ' => 'ԯ', + 'Ա' => 'ա', + 'Բ' => 'բ', + 'Գ' => 'գ', + 'Դ' => 'դ', + 'Ե' => 'ե', + 'Զ' => 'զ', + 'Է' => 'է', + 'Ը' => 'ը', + 'Թ' => 'թ', + 'Ժ' => 'ժ', + 'Ի' => 'ի', + 'Լ' => 'լ', + 'Խ' => 'խ', + 'Ծ' => 'ծ', + 'Կ' => 'կ', + 'Հ' => 'հ', + 'Ձ' => 'ձ', + 'Ղ' => 'ղ', + 'Ճ' => 'ճ', + 'Մ' => 'մ', + 'Յ' => 'յ', + 'Ն' => 'ն', + 'Շ' => 'շ', + 'Ո' => 'ո', + 'Չ' => 'չ', + 'Պ' => 'պ', + 'Ջ' => 'ջ', + 'Ռ' => 'ռ', + 'Ս' => 'ս', + 'Վ' => 'վ', + 'Տ' => 'տ', + 'Ր' => 'ր', + 'Ց' => 'ց', + 'Ւ' => 'ւ', + 'Փ' => 'փ', + 'Ք' => 'ք', + 'Օ' => 'օ', + 'Ֆ' => 'ֆ', + 'Ⴀ' => 'ⴀ', + 'Ⴁ' => 'ⴁ', + 'Ⴂ' => 'ⴂ', + 'Ⴃ' => 'ⴃ', + 'Ⴄ' => 'ⴄ', + 'Ⴅ' => 'ⴅ', + 'Ⴆ' => 'ⴆ', + 'Ⴇ' => 'ⴇ', + 'Ⴈ' => 'ⴈ', + 'Ⴉ' => 'ⴉ', + 'Ⴊ' => 'ⴊ', + 'Ⴋ' => 'ⴋ', + 'Ⴌ' => 'ⴌ', + 'Ⴍ' => 'ⴍ', + 'Ⴎ' => 'ⴎ', + 'Ⴏ' => 'ⴏ', + 'Ⴐ' => 'ⴐ', + 'Ⴑ' => 'ⴑ', + 'Ⴒ' => 'ⴒ', + 'Ⴓ' => 'ⴓ', + 'Ⴔ' => 'ⴔ', + 'Ⴕ' => 'ⴕ', + 'Ⴖ' => 'ⴖ', + 'Ⴗ' => 'ⴗ', + 'Ⴘ' => 'ⴘ', + 'Ⴙ' => 'ⴙ', + 'Ⴚ' => 'ⴚ', + 'Ⴛ' => 'ⴛ', + 'Ⴜ' => 'ⴜ', + 'Ⴝ' => 'ⴝ', + 'Ⴞ' => 'ⴞ', + 'Ⴟ' => 'ⴟ', + 'Ⴠ' => 'ⴠ', + 'Ⴡ' => 'ⴡ', + 'Ⴢ' => 'ⴢ', + 'Ⴣ' => 'ⴣ', + 'Ⴤ' => 'ⴤ', + 'Ⴥ' => 'ⴥ', + 'Ⴧ' => 'ⴧ', + 'Ⴭ' => 'ⴭ', + 'Ꭰ' => 'ꭰ', + 'Ꭱ' => 'ꭱ', + 'Ꭲ' => 'ꭲ', + 'Ꭳ' => 'ꭳ', + 'Ꭴ' => 'ꭴ', + 'Ꭵ' => 'ꭵ', + 'Ꭶ' => 'ꭶ', + 'Ꭷ' => 'ꭷ', + 'Ꭸ' => 'ꭸ', + 'Ꭹ' => 'ꭹ', + 'Ꭺ' => 'ꭺ', + 'Ꭻ' => 'ꭻ', + 'Ꭼ' => 'ꭼ', + 'Ꭽ' => 'ꭽ', + 'Ꭾ' => 'ꭾ', + 'Ꭿ' => 'ꭿ', + 'Ꮀ' => 'ꮀ', + 'Ꮁ' => 'ꮁ', + 'Ꮂ' => 'ꮂ', + 'Ꮃ' => 'ꮃ', + 'Ꮄ' => 'ꮄ', + 'Ꮅ' => 'ꮅ', + 'Ꮆ' => 'ꮆ', + 'Ꮇ' => 'ꮇ', + 'Ꮈ' => 'ꮈ', + 'Ꮉ' => 'ꮉ', + 'Ꮊ' => 'ꮊ', + 'Ꮋ' => 'ꮋ', + 'Ꮌ' => 'ꮌ', + 'Ꮍ' => 'ꮍ', + 'Ꮎ' => 'ꮎ', + 'Ꮏ' => 'ꮏ', + 'Ꮐ' => 'ꮐ', + 'Ꮑ' => 'ꮑ', + 'Ꮒ' => 'ꮒ', + 'Ꮓ' => 'ꮓ', + 'Ꮔ' => 'ꮔ', + 'Ꮕ' => 'ꮕ', + 'Ꮖ' => 'ꮖ', + 'Ꮗ' => 'ꮗ', + 'Ꮘ' => 'ꮘ', + 'Ꮙ' => 'ꮙ', + 'Ꮚ' => 'ꮚ', + 'Ꮛ' => 'ꮛ', + 'Ꮜ' => 'ꮜ', + 'Ꮝ' => 'ꮝ', + 'Ꮞ' => 'ꮞ', + 'Ꮟ' => 'ꮟ', + 'Ꮠ' => 'ꮠ', + 'Ꮡ' => 'ꮡ', + 'Ꮢ' => 'ꮢ', + 'Ꮣ' => 'ꮣ', + 'Ꮤ' => 'ꮤ', + 'Ꮥ' => 'ꮥ', + 'Ꮦ' => 'ꮦ', + 'Ꮧ' => 'ꮧ', + 'Ꮨ' => 'ꮨ', + 'Ꮩ' => 'ꮩ', + 'Ꮪ' => 'ꮪ', + 'Ꮫ' => 'ꮫ', + 'Ꮬ' => 'ꮬ', + 'Ꮭ' => 'ꮭ', + 'Ꮮ' => 'ꮮ', + 'Ꮯ' => 'ꮯ', + 'Ꮰ' => 'ꮰ', + 'Ꮱ' => 'ꮱ', + 'Ꮲ' => 'ꮲ', + 'Ꮳ' => 'ꮳ', + 'Ꮴ' => 'ꮴ', + 'Ꮵ' => 'ꮵ', + 'Ꮶ' => 'ꮶ', + 'Ꮷ' => 'ꮷ', + 'Ꮸ' => 'ꮸ', + 'Ꮹ' => 'ꮹ', + 'Ꮺ' => 'ꮺ', + 'Ꮻ' => 'ꮻ', + 'Ꮼ' => 'ꮼ', + 'Ꮽ' => 'ꮽ', + 'Ꮾ' => 'ꮾ', + 'Ꮿ' => 'ꮿ', + 'Ᏸ' => 'ᏸ', + 'Ᏹ' => 'ᏹ', + 'Ᏺ' => 'ᏺ', + 'Ᏻ' => 'ᏻ', + 'Ᏼ' => 'ᏼ', + 'Ᏽ' => 'ᏽ', + 'Ა' => 'ა', + 'Ბ' => 'ბ', + 'Გ' => 'გ', + 'Დ' => 'დ', + 'Ე' => 'ე', + 'Ვ' => 'ვ', + 'Ზ' => 'ზ', + 'Თ' => 'თ', + 'Ი' => 'ი', + 'Კ' => 'კ', + 'Ლ' => 'ლ', + 'Მ' => 'მ', + 'Ნ' => 'ნ', + 'Ო' => 'ო', + 'Პ' => 'პ', + 'Ჟ' => 'ჟ', + 'Რ' => 'რ', + 'Ს' => 'ს', + 'Ტ' => 'ტ', + 'Უ' => 'უ', + 'Ფ' => 'ფ', + 'Ქ' => 'ქ', + 'Ღ' => 'ღ', + 'Ყ' => 'ყ', + 'Შ' => 'შ', + 'Ჩ' => 'ჩ', + 'Ც' => 'ც', + 'Ძ' => 'ძ', + 'Წ' => 'წ', + 'Ჭ' => 'ჭ', + 'Ხ' => 'ხ', + 'Ჯ' => 'ჯ', + 'Ჰ' => 'ჰ', + 'Ჱ' => 'ჱ', + 'Ჲ' => 'ჲ', + 'Ჳ' => 'ჳ', + 'Ჴ' => 'ჴ', + 'Ჵ' => 'ჵ', + 'Ჶ' => 'ჶ', + 'Ჷ' => 'ჷ', + 'Ჸ' => 'ჸ', + 'Ჹ' => 'ჹ', + 'Ჺ' => 'ჺ', + 'Ჽ' => 'ჽ', + 'Ჾ' => 'ჾ', + 'Ჿ' => 'ჿ', + 'Ḁ' => 'ḁ', + 'Ḃ' => 'ḃ', + 'Ḅ' => 'ḅ', + 'Ḇ' => 'ḇ', + 'Ḉ' => 'ḉ', + 'Ḋ' => 'ḋ', + 'Ḍ' => 'ḍ', + 'Ḏ' => 'ḏ', + 'Ḑ' => 'ḑ', + 'Ḓ' => 'ḓ', + 'Ḕ' => 'ḕ', + 'Ḗ' => 'ḗ', + 'Ḙ' => 'ḙ', + 'Ḛ' => 'ḛ', + 'Ḝ' => 'ḝ', + 'Ḟ' => 'ḟ', + 'Ḡ' => 'ḡ', + 'Ḣ' => 'ḣ', + 'Ḥ' => 'ḥ', + 'Ḧ' => 'ḧ', + 'Ḩ' => 'ḩ', + 'Ḫ' => 'ḫ', + 'Ḭ' => 'ḭ', + 'Ḯ' => 'ḯ', + 'Ḱ' => 'ḱ', + 'Ḳ' => 'ḳ', + 'Ḵ' => 'ḵ', + 'Ḷ' => 'ḷ', + 'Ḹ' => 'ḹ', + 'Ḻ' => 'ḻ', + 'Ḽ' => 'ḽ', + 'Ḿ' => 'ḿ', + 'Ṁ' => 'ṁ', + 'Ṃ' => 'ṃ', + 'Ṅ' => 'ṅ', + 'Ṇ' => 'ṇ', + 'Ṉ' => 'ṉ', + 'Ṋ' => 'ṋ', + 'Ṍ' => 'ṍ', + 'Ṏ' => 'ṏ', + 'Ṑ' => 'ṑ', + 'Ṓ' => 'ṓ', + 'Ṕ' => 'ṕ', + 'Ṗ' => 'ṗ', + 'Ṙ' => 'ṙ', + 'Ṛ' => 'ṛ', + 'Ṝ' => 'ṝ', + 'Ṟ' => 'ṟ', + 'Ṡ' => 'ṡ', + 'Ṣ' => 'ṣ', + 'Ṥ' => 'ṥ', + 'Ṧ' => 'ṧ', + 'Ṩ' => 'ṩ', + 'Ṫ' => 'ṫ', + 'Ṭ' => 'ṭ', + 'Ṯ' => 'ṯ', + 'Ṱ' => 'ṱ', + 'Ṳ' => 'ṳ', + 'Ṵ' => 'ṵ', + 'Ṷ' => 'ṷ', + 'Ṹ' => 'ṹ', + 'Ṻ' => 'ṻ', + 'Ṽ' => 'ṽ', + 'Ṿ' => 'ṿ', + 'Ẁ' => 'ẁ', + 'Ẃ' => 'ẃ', + 'Ẅ' => 'ẅ', + 'Ẇ' => 'ẇ', + 'Ẉ' => 'ẉ', + 'Ẋ' => 'ẋ', + 'Ẍ' => 'ẍ', + 'Ẏ' => 'ẏ', + 'Ẑ' => 'ẑ', + 'Ẓ' => 'ẓ', + 'Ẕ' => 'ẕ', + 'ẞ' => 'ß', + 'Ạ' => 'ạ', + 'Ả' => 'ả', + 'Ấ' => 'ấ', + 'Ầ' => 'ầ', + 'Ẩ' => 'ẩ', + 'Ẫ' => 'ẫ', + 'Ậ' => 'ậ', + 'Ắ' => 'ắ', + 'Ằ' => 'ằ', + 'Ẳ' => 'ẳ', + 'Ẵ' => 'ẵ', + 'Ặ' => 'ặ', + 'Ẹ' => 'ẹ', + 'Ẻ' => 'ẻ', + 'Ẽ' => 'ẽ', + 'Ế' => 'ế', + 'Ề' => 'ề', + 'Ể' => 'ể', + 'Ễ' => 'ễ', + 'Ệ' => 'ệ', + 'Ỉ' => 'ỉ', + 'Ị' => 'ị', + 'Ọ' => 'ọ', + 'Ỏ' => 'ỏ', + 'Ố' => 'ố', + 'Ồ' => 'ồ', + 'Ổ' => 'ổ', + 'Ỗ' => 'ỗ', + 'Ộ' => 'ộ', + 'Ớ' => 'ớ', + 'Ờ' => 'ờ', + 'Ở' => 'ở', + 'Ỡ' => 'ỡ', + 'Ợ' => 'ợ', + 'Ụ' => 'ụ', + 'Ủ' => 'ủ', + 'Ứ' => 'ứ', + 'Ừ' => 'ừ', + 'Ử' => 'ử', + 'Ữ' => 'ữ', + 'Ự' => 'ự', + 'Ỳ' => 'ỳ', + 'Ỵ' => 'ỵ', + 'Ỷ' => 'ỷ', + 'Ỹ' => 'ỹ', + 'Ỻ' => 'ỻ', + 'Ỽ' => 'ỽ', + 'Ỿ' => 'ỿ', + 'Ἀ' => 'ἀ', + 'Ἁ' => 'ἁ', + 'Ἂ' => 'ἂ', + 'Ἃ' => 'ἃ', + 'Ἄ' => 'ἄ', + 'Ἅ' => 'ἅ', + 'Ἆ' => 'ἆ', + 'Ἇ' => 'ἇ', + 'Ἐ' => 'ἐ', + 'Ἑ' => 'ἑ', + 'Ἒ' => 'ἒ', + 'Ἓ' => 'ἓ', + 'Ἔ' => 'ἔ', + 'Ἕ' => 'ἕ', + 'Ἠ' => 'ἠ', + 'Ἡ' => 'ἡ', + 'Ἢ' => 'ἢ', + 'Ἣ' => 'ἣ', + 'Ἤ' => 'ἤ', + 'Ἥ' => 'ἥ', + 'Ἦ' => 'ἦ', + 'Ἧ' => 'ἧ', + 'Ἰ' => 'ἰ', + 'Ἱ' => 'ἱ', + 'Ἲ' => 'ἲ', + 'Ἳ' => 'ἳ', + 'Ἴ' => 'ἴ', + 'Ἵ' => 'ἵ', + 'Ἶ' => 'ἶ', + 'Ἷ' => 'ἷ', + 'Ὀ' => 'ὀ', + 'Ὁ' => 'ὁ', + 'Ὂ' => 'ὂ', + 'Ὃ' => 'ὃ', + 'Ὄ' => 'ὄ', + 'Ὅ' => 'ὅ', + 'Ὑ' => 'ὑ', + 'Ὓ' => 'ὓ', + 'Ὕ' => 'ὕ', + 'Ὗ' => 'ὗ', + 'Ὠ' => 'ὠ', + 'Ὡ' => 'ὡ', + 'Ὢ' => 'ὢ', + 'Ὣ' => 'ὣ', + 'Ὤ' => 'ὤ', + 'Ὥ' => 'ὥ', + 'Ὦ' => 'ὦ', + 'Ὧ' => 'ὧ', + 'ᾈ' => 'ᾀ', + 'ᾉ' => 'ᾁ', + 'ᾊ' => 'ᾂ', + 'ᾋ' => 'ᾃ', + 'ᾌ' => 'ᾄ', + 'ᾍ' => 'ᾅ', + 'ᾎ' => 'ᾆ', + 'ᾏ' => 'ᾇ', + 'ᾘ' => 'ᾐ', + 'ᾙ' => 'ᾑ', + 'ᾚ' => 'ᾒ', + 'ᾛ' => 'ᾓ', + 'ᾜ' => 'ᾔ', + 'ᾝ' => 'ᾕ', + 'ᾞ' => 'ᾖ', + 'ᾟ' => 'ᾗ', + 'ᾨ' => 'ᾠ', + 'ᾩ' => 'ᾡ', + 'ᾪ' => 'ᾢ', + 'ᾫ' => 'ᾣ', + 'ᾬ' => 'ᾤ', + 'ᾭ' => 'ᾥ', + 'ᾮ' => 'ᾦ', + 'ᾯ' => 'ᾧ', + 'Ᾰ' => 'ᾰ', + 'Ᾱ' => 'ᾱ', + 'Ὰ' => 'ὰ', + 'Ά' => 'ά', + 'ᾼ' => 'ᾳ', + 'Ὲ' => 'ὲ', + 'Έ' => 'έ', + 'Ὴ' => 'ὴ', + 'Ή' => 'ή', + 'ῌ' => 'ῃ', + 'Ῐ' => 'ῐ', + 'Ῑ' => 'ῑ', + 'Ὶ' => 'ὶ', + 'Ί' => 'ί', + 'Ῠ' => 'ῠ', + 'Ῡ' => 'ῡ', + 'Ὺ' => 'ὺ', + 'Ύ' => 'ύ', + 'Ῥ' => 'ῥ', + 'Ὸ' => 'ὸ', + 'Ό' => 'ό', + 'Ὼ' => 'ὼ', + 'Ώ' => 'ώ', + 'ῼ' => 'ῳ', + 'Ω' => 'ω', + 'K' => 'k', + 'Å' => 'å', + 'Ⅎ' => 'ⅎ', + 'Ⅰ' => 'ⅰ', + 'Ⅱ' => 'ⅱ', + 'Ⅲ' => 'ⅲ', + 'Ⅳ' => 'ⅳ', + 'Ⅴ' => 'ⅴ', + 'Ⅵ' => 'ⅵ', + 'Ⅶ' => 'ⅶ', + 'Ⅷ' => 'ⅷ', + 'Ⅸ' => 'ⅸ', + 'Ⅹ' => 'ⅹ', + 'Ⅺ' => 'ⅺ', + 'Ⅻ' => 'ⅻ', + 'Ⅼ' => 'ⅼ', + 'Ⅽ' => 'ⅽ', + 'Ⅾ' => 'ⅾ', + 'Ⅿ' => 'ⅿ', + 'Ↄ' => 'ↄ', + 'Ⓐ' => 'ⓐ', + 'Ⓑ' => 'ⓑ', + 'Ⓒ' => 'ⓒ', + 'Ⓓ' => 'ⓓ', + 'Ⓔ' => 'ⓔ', + 'Ⓕ' => 'ⓕ', + 'Ⓖ' => 'ⓖ', + 'Ⓗ' => 'ⓗ', + 'Ⓘ' => 'ⓘ', + 'Ⓙ' => 'ⓙ', + 'Ⓚ' => 'ⓚ', + 'Ⓛ' => 'ⓛ', + 'Ⓜ' => 'ⓜ', + 'Ⓝ' => 'ⓝ', + 'Ⓞ' => 'ⓞ', + 'Ⓟ' => 'ⓟ', + 'Ⓠ' => 'ⓠ', + 'Ⓡ' => 'ⓡ', + 'Ⓢ' => 'ⓢ', + 'Ⓣ' => 'ⓣ', + 'Ⓤ' => 'ⓤ', + 'Ⓥ' => 'ⓥ', + 'Ⓦ' => 'ⓦ', + 'Ⓧ' => 'ⓧ', + 'Ⓨ' => 'ⓨ', + 'Ⓩ' => 'ⓩ', + 'Ⰰ' => 'ⰰ', + 'Ⰱ' => 'ⰱ', + 'Ⰲ' => 'ⰲ', + 'Ⰳ' => 'ⰳ', + 'Ⰴ' => 'ⰴ', + 'Ⰵ' => 'ⰵ', + 'Ⰶ' => 'ⰶ', + 'Ⰷ' => 'ⰷ', + 'Ⰸ' => 'ⰸ', + 'Ⰹ' => 'ⰹ', + 'Ⰺ' => 'ⰺ', + 'Ⰻ' => 'ⰻ', + 'Ⰼ' => 'ⰼ', + 'Ⰽ' => 'ⰽ', + 'Ⰾ' => 'ⰾ', + 'Ⰿ' => 'ⰿ', + 'Ⱀ' => 'ⱀ', + 'Ⱁ' => 'ⱁ', + 'Ⱂ' => 'ⱂ', + 'Ⱃ' => 'ⱃ', + 'Ⱄ' => 'ⱄ', + 'Ⱅ' => 'ⱅ', + 'Ⱆ' => 'ⱆ', + 'Ⱇ' => 'ⱇ', + 'Ⱈ' => 'ⱈ', + 'Ⱉ' => 'ⱉ', + 'Ⱊ' => 'ⱊ', + 'Ⱋ' => 'ⱋ', + 'Ⱌ' => 'ⱌ', + 'Ⱍ' => 'ⱍ', + 'Ⱎ' => 'ⱎ', + 'Ⱏ' => 'ⱏ', + 'Ⱐ' => 'ⱐ', + 'Ⱑ' => 'ⱑ', + 'Ⱒ' => 'ⱒ', + 'Ⱓ' => 'ⱓ', + 'Ⱔ' => 'ⱔ', + 'Ⱕ' => 'ⱕ', + 'Ⱖ' => 'ⱖ', + 'Ⱗ' => 'ⱗ', + 'Ⱘ' => 'ⱘ', + 'Ⱙ' => 'ⱙ', + 'Ⱚ' => 'ⱚ', + 'Ⱛ' => 'ⱛ', + 'Ⱜ' => 'ⱜ', + 'Ⱝ' => 'ⱝ', + 'Ⱞ' => 'ⱞ', + 'Ⱡ' => 'ⱡ', + 'Ɫ' => 'ɫ', + 'Ᵽ' => 'ᵽ', + 'Ɽ' => 'ɽ', + 'Ⱨ' => 'ⱨ', + 'Ⱪ' => 'ⱪ', + 'Ⱬ' => 'ⱬ', + 'Ɑ' => 'ɑ', + 'Ɱ' => 'ɱ', + 'Ɐ' => 'ɐ', + 'Ɒ' => 'ɒ', + 'Ⱳ' => 'ⱳ', + 'Ⱶ' => 'ⱶ', + 'Ȿ' => 'ȿ', + 'Ɀ' => 'ɀ', + 'Ⲁ' => 'ⲁ', + 'Ⲃ' => 'ⲃ', + 'Ⲅ' => 'ⲅ', + 'Ⲇ' => 'ⲇ', + 'Ⲉ' => 'ⲉ', + 'Ⲋ' => 'ⲋ', + 'Ⲍ' => 'ⲍ', + 'Ⲏ' => 'ⲏ', + 'Ⲑ' => 'ⲑ', + 'Ⲓ' => 'ⲓ', + 'Ⲕ' => 'ⲕ', + 'Ⲗ' => 'ⲗ', + 'Ⲙ' => 'ⲙ', + 'Ⲛ' => 'ⲛ', + 'Ⲝ' => 'ⲝ', + 'Ⲟ' => 'ⲟ', + 'Ⲡ' => 'ⲡ', + 'Ⲣ' => 'ⲣ', + 'Ⲥ' => 'ⲥ', + 'Ⲧ' => 'ⲧ', + 'Ⲩ' => 'ⲩ', + 'Ⲫ' => 'ⲫ', + 'Ⲭ' => 'ⲭ', + 'Ⲯ' => 'ⲯ', + 'Ⲱ' => 'ⲱ', + 'Ⲳ' => 'ⲳ', + 'Ⲵ' => 'ⲵ', + 'Ⲷ' => 'ⲷ', + 'Ⲹ' => 'ⲹ', + 'Ⲻ' => 'ⲻ', + 'Ⲽ' => 'ⲽ', + 'Ⲿ' => 'ⲿ', + 'Ⳁ' => 'ⳁ', + 'Ⳃ' => 'ⳃ', + 'Ⳅ' => 'ⳅ', + 'Ⳇ' => 'ⳇ', + 'Ⳉ' => 'ⳉ', + 'Ⳋ' => 'ⳋ', + 'Ⳍ' => 'ⳍ', + 'Ⳏ' => 'ⳏ', + 'Ⳑ' => 'ⳑ', + 'Ⳓ' => 'ⳓ', + 'Ⳕ' => 'ⳕ', + 'Ⳗ' => 'ⳗ', + 'Ⳙ' => 'ⳙ', + 'Ⳛ' => 'ⳛ', + 'Ⳝ' => 'ⳝ', + 'Ⳟ' => 'ⳟ', + 'Ⳡ' => 'ⳡ', + 'Ⳣ' => 'ⳣ', + 'Ⳬ' => 'ⳬ', + 'Ⳮ' => 'ⳮ', + 'Ⳳ' => 'ⳳ', + 'Ꙁ' => 'ꙁ', + 'Ꙃ' => 'ꙃ', + 'Ꙅ' => 'ꙅ', + 'Ꙇ' => 'ꙇ', + 'Ꙉ' => 'ꙉ', + 'Ꙋ' => 'ꙋ', + 'Ꙍ' => 'ꙍ', + 'Ꙏ' => 'ꙏ', + 'Ꙑ' => 'ꙑ', + 'Ꙓ' => 'ꙓ', + 'Ꙕ' => 'ꙕ', + 'Ꙗ' => 'ꙗ', + 'Ꙙ' => 'ꙙ', + 'Ꙛ' => 'ꙛ', + 'Ꙝ' => 'ꙝ', + 'Ꙟ' => 'ꙟ', + 'Ꙡ' => 'ꙡ', + 'Ꙣ' => 'ꙣ', + 'Ꙥ' => 'ꙥ', + 'Ꙧ' => 'ꙧ', + 'Ꙩ' => 'ꙩ', + 'Ꙫ' => 'ꙫ', + 'Ꙭ' => 'ꙭ', + 'Ꚁ' => 'ꚁ', + 'Ꚃ' => 'ꚃ', + 'Ꚅ' => 'ꚅ', + 'Ꚇ' => 'ꚇ', + 'Ꚉ' => 'ꚉ', + 'Ꚋ' => 'ꚋ', + 'Ꚍ' => 'ꚍ', + 'Ꚏ' => 'ꚏ', + 'Ꚑ' => 'ꚑ', + 'Ꚓ' => 'ꚓ', + 'Ꚕ' => 'ꚕ', + 'Ꚗ' => 'ꚗ', + 'Ꚙ' => 'ꚙ', + 'Ꚛ' => 'ꚛ', + 'Ꜣ' => 'ꜣ', + 'Ꜥ' => 'ꜥ', + 'Ꜧ' => 'ꜧ', + 'Ꜩ' => 'ꜩ', + 'Ꜫ' => 'ꜫ', + 'Ꜭ' => 'ꜭ', + 'Ꜯ' => 'ꜯ', + 'Ꜳ' => 'ꜳ', + 'Ꜵ' => 'ꜵ', + 'Ꜷ' => 'ꜷ', + 'Ꜹ' => 'ꜹ', + 'Ꜻ' => 'ꜻ', + 'Ꜽ' => 'ꜽ', + 'Ꜿ' => 'ꜿ', + 'Ꝁ' => 'ꝁ', + 'Ꝃ' => 'ꝃ', + 'Ꝅ' => 'ꝅ', + 'Ꝇ' => 'ꝇ', + 'Ꝉ' => 'ꝉ', + 'Ꝋ' => 'ꝋ', + 'Ꝍ' => 'ꝍ', + 'Ꝏ' => 'ꝏ', + 'Ꝑ' => 'ꝑ', + 'Ꝓ' => 'ꝓ', + 'Ꝕ' => 'ꝕ', + 'Ꝗ' => 'ꝗ', + 'Ꝙ' => 'ꝙ', + 'Ꝛ' => 'ꝛ', + 'Ꝝ' => 'ꝝ', + 'Ꝟ' => 'ꝟ', + 'Ꝡ' => 'ꝡ', + 'Ꝣ' => 'ꝣ', + 'Ꝥ' => 'ꝥ', + 'Ꝧ' => 'ꝧ', + 'Ꝩ' => 'ꝩ', + 'Ꝫ' => 'ꝫ', + 'Ꝭ' => 'ꝭ', + 'Ꝯ' => 'ꝯ', + 'Ꝺ' => 'ꝺ', + 'Ꝼ' => 'ꝼ', + 'Ᵹ' => 'ᵹ', + 'Ꝿ' => 'ꝿ', + 'Ꞁ' => 'ꞁ', + 'Ꞃ' => 'ꞃ', + 'Ꞅ' => 'ꞅ', + 'Ꞇ' => 'ꞇ', + 'Ꞌ' => 'ꞌ', + 'Ɥ' => 'ɥ', + 'Ꞑ' => 'ꞑ', + 'Ꞓ' => 'ꞓ', + 'Ꞗ' => 'ꞗ', + 'Ꞙ' => 'ꞙ', + 'Ꞛ' => 'ꞛ', + 'Ꞝ' => 'ꞝ', + 'Ꞟ' => 'ꞟ', + 'Ꞡ' => 'ꞡ', + 'Ꞣ' => 'ꞣ', + 'Ꞥ' => 'ꞥ', + 'Ꞧ' => 'ꞧ', + 'Ꞩ' => 'ꞩ', + 'Ɦ' => 'ɦ', + 'Ɜ' => 'ɜ', + 'Ɡ' => 'ɡ', + 'Ɬ' => 'ɬ', + 'Ɪ' => 'ɪ', + 'Ʞ' => 'ʞ', + 'Ʇ' => 'ʇ', + 'Ʝ' => 'ʝ', + 'Ꭓ' => 'ꭓ', + 'Ꞵ' => 'ꞵ', + 'Ꞷ' => 'ꞷ', + 'Ꞹ' => 'ꞹ', + 'Ꞻ' => 'ꞻ', + 'Ꞽ' => 'ꞽ', + 'Ꞿ' => 'ꞿ', + 'Ꟃ' => 'ꟃ', + 'Ꞔ' => 'ꞔ', + 'Ʂ' => 'ʂ', + 'Ᶎ' => 'ᶎ', + 'Ꟈ' => 'ꟈ', + 'Ꟊ' => 'ꟊ', + 'Ꟶ' => 'ꟶ', + 'A' => 'a', + 'B' => 'b', + 'C' => 'c', + 'D' => 'd', + 'E' => 'e', + 'F' => 'f', + 'G' => 'g', + 'H' => 'h', + 'I' => 'i', + 'J' => 'j', + 'K' => 'k', + 'L' => 'l', + 'M' => 'm', + 'N' => 'n', + 'O' => 'o', + 'P' => 'p', + 'Q' => 'q', + 'R' => 'r', + 'S' => 's', + 'T' => 't', + 'U' => 'u', + 'V' => 'v', + 'W' => 'w', + 'X' => 'x', + 'Y' => 'y', + 'Z' => 'z', + '𐐀' => '𐐨', + '𐐁' => '𐐩', + '𐐂' => '𐐪', + '𐐃' => '𐐫', + '𐐄' => '𐐬', + '𐐅' => '𐐭', + '𐐆' => '𐐮', + '𐐇' => '𐐯', + '𐐈' => '𐐰', + '𐐉' => '𐐱', + '𐐊' => '𐐲', + '𐐋' => '𐐳', + '𐐌' => '𐐴', + '𐐍' => '𐐵', + '𐐎' => '𐐶', + '𐐏' => '𐐷', + '𐐐' => '𐐸', + '𐐑' => '𐐹', + '𐐒' => '𐐺', + '𐐓' => '𐐻', + '𐐔' => '𐐼', + '𐐕' => '𐐽', + '𐐖' => '𐐾', + '𐐗' => '𐐿', + '𐐘' => '𐑀', + '𐐙' => '𐑁', + '𐐚' => '𐑂', + '𐐛' => '𐑃', + '𐐜' => '𐑄', + '𐐝' => '𐑅', + '𐐞' => '𐑆', + '𐐟' => '𐑇', + '𐐠' => '𐑈', + '𐐡' => '𐑉', + '𐐢' => '𐑊', + '𐐣' => '𐑋', + '𐐤' => '𐑌', + '𐐥' => '𐑍', + '𐐦' => '𐑎', + '𐐧' => '𐑏', + '𐒰' => '𐓘', + '𐒱' => '𐓙', + '𐒲' => '𐓚', + '𐒳' => '𐓛', + '𐒴' => '𐓜', + '𐒵' => '𐓝', + '𐒶' => '𐓞', + '𐒷' => '𐓟', + '𐒸' => '𐓠', + '𐒹' => '𐓡', + '𐒺' => '𐓢', + '𐒻' => '𐓣', + '𐒼' => '𐓤', + '𐒽' => '𐓥', + '𐒾' => '𐓦', + '𐒿' => '𐓧', + '𐓀' => '𐓨', + '𐓁' => '𐓩', + '𐓂' => '𐓪', + '𐓃' => '𐓫', + '𐓄' => '𐓬', + '𐓅' => '𐓭', + '𐓆' => '𐓮', + '𐓇' => '𐓯', + '𐓈' => '𐓰', + '𐓉' => '𐓱', + '𐓊' => '𐓲', + '𐓋' => '𐓳', + '𐓌' => '𐓴', + '𐓍' => '𐓵', + '𐓎' => '𐓶', + '𐓏' => '𐓷', + '𐓐' => '𐓸', + '𐓑' => '𐓹', + '𐓒' => '𐓺', + '𐓓' => '𐓻', + '𐲀' => '𐳀', + '𐲁' => '𐳁', + '𐲂' => '𐳂', + '𐲃' => '𐳃', + '𐲄' => '𐳄', + '𐲅' => '𐳅', + '𐲆' => '𐳆', + '𐲇' => '𐳇', + '𐲈' => '𐳈', + '𐲉' => '𐳉', + '𐲊' => '𐳊', + '𐲋' => '𐳋', + '𐲌' => '𐳌', + '𐲍' => '𐳍', + '𐲎' => '𐳎', + '𐲏' => '𐳏', + '𐲐' => '𐳐', + '𐲑' => '𐳑', + '𐲒' => '𐳒', + '𐲓' => '𐳓', + '𐲔' => '𐳔', + '𐲕' => '𐳕', + '𐲖' => '𐳖', + '𐲗' => '𐳗', + '𐲘' => '𐳘', + '𐲙' => '𐳙', + '𐲚' => '𐳚', + '𐲛' => '𐳛', + '𐲜' => '𐳜', + '𐲝' => '𐳝', + '𐲞' => '𐳞', + '𐲟' => '𐳟', + '𐲠' => '𐳠', + '𐲡' => '𐳡', + '𐲢' => '𐳢', + '𐲣' => '𐳣', + '𐲤' => '𐳤', + '𐲥' => '𐳥', + '𐲦' => '𐳦', + '𐲧' => '𐳧', + '𐲨' => '𐳨', + '𐲩' => '𐳩', + '𐲪' => '𐳪', + '𐲫' => '𐳫', + '𐲬' => '𐳬', + '𐲭' => '𐳭', + '𐲮' => '𐳮', + '𐲯' => '𐳯', + '𐲰' => '𐳰', + '𐲱' => '𐳱', + '𐲲' => '𐳲', + '𑢠' => '𑣀', + '𑢡' => '𑣁', + '𑢢' => '𑣂', + '𑢣' => '𑣃', + '𑢤' => '𑣄', + '𑢥' => '𑣅', + '𑢦' => '𑣆', + '𑢧' => '𑣇', + '𑢨' => '𑣈', + '𑢩' => '𑣉', + '𑢪' => '𑣊', + '𑢫' => '𑣋', + '𑢬' => '𑣌', + '𑢭' => '𑣍', + '𑢮' => '𑣎', + '𑢯' => '𑣏', + '𑢰' => '𑣐', + '𑢱' => '𑣑', + '𑢲' => '𑣒', + '𑢳' => '𑣓', + '𑢴' => '𑣔', + '𑢵' => '𑣕', + '𑢶' => '𑣖', + '𑢷' => '𑣗', + '𑢸' => '𑣘', + '𑢹' => '𑣙', + '𑢺' => '𑣚', + '𑢻' => '𑣛', + '𑢼' => '𑣜', + '𑢽' => '𑣝', + '𑢾' => '𑣞', + '𑢿' => '𑣟', + '𖹀' => '𖹠', + '𖹁' => '𖹡', + '𖹂' => '𖹢', + '𖹃' => '𖹣', + '𖹄' => '𖹤', + '𖹅' => '𖹥', + '𖹆' => '𖹦', + '𖹇' => '𖹧', + '𖹈' => '𖹨', + '𖹉' => '𖹩', + '𖹊' => '𖹪', + '𖹋' => '𖹫', + '𖹌' => '𖹬', + '𖹍' => '𖹭', + '𖹎' => '𖹮', + '𖹏' => '𖹯', + '𖹐' => '𖹰', + '𖹑' => '𖹱', + '𖹒' => '𖹲', + '𖹓' => '𖹳', + '𖹔' => '𖹴', + '𖹕' => '𖹵', + '𖹖' => '𖹶', + '𖹗' => '𖹷', + '𖹘' => '𖹸', + '𖹙' => '𖹹', + '𖹚' => '𖹺', + '𖹛' => '𖹻', + '𖹜' => '𖹼', + '𖹝' => '𖹽', + '𖹞' => '𖹾', + '𖹟' => '𖹿', + '𞤀' => '𞤢', + '𞤁' => '𞤣', + '𞤂' => '𞤤', + '𞤃' => '𞤥', + '𞤄' => '𞤦', + '𞤅' => '𞤧', + '𞤆' => '𞤨', + '𞤇' => '𞤩', + '𞤈' => '𞤪', + '𞤉' => '𞤫', + '𞤊' => '𞤬', + '𞤋' => '𞤭', + '𞤌' => '𞤮', + '𞤍' => '𞤯', + '𞤎' => '𞤰', + '𞤏' => '𞤱', + '𞤐' => '𞤲', + '𞤑' => '𞤳', + '𞤒' => '𞤴', + '𞤓' => '𞤵', + '𞤔' => '𞤶', + '𞤕' => '𞤷', + '𞤖' => '𞤸', + '𞤗' => '𞤹', + '𞤘' => '𞤺', + '𞤙' => '𞤻', + '𞤚' => '𞤼', + '𞤛' => '𞤽', + '𞤜' => '𞤾', + '𞤝' => '𞤿', + '𞤞' => '𞥀', + '𞤟' => '𞥁', + '𞤠' => '𞥂', + '𞤡' => '𞥃', +); diff --git a/tools/mailer/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php b/tools/mailer/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php new file mode 100644 index 000000000..2a8f6e73b --- /dev/null +++ b/tools/mailer/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php @@ -0,0 +1,5 @@ + 'A', + 'b' => 'B', + 'c' => 'C', + 'd' => 'D', + 'e' => 'E', + 'f' => 'F', + 'g' => 'G', + 'h' => 'H', + 'i' => 'I', + 'j' => 'J', + 'k' => 'K', + 'l' => 'L', + 'm' => 'M', + 'n' => 'N', + 'o' => 'O', + 'p' => 'P', + 'q' => 'Q', + 'r' => 'R', + 's' => 'S', + 't' => 'T', + 'u' => 'U', + 'v' => 'V', + 'w' => 'W', + 'x' => 'X', + 'y' => 'Y', + 'z' => 'Z', + 'µ' => 'Μ', + 'à' => 'À', + 'á' => 'Á', + 'â' => 'Â', + 'ã' => 'Ã', + 'ä' => 'Ä', + 'å' => 'Å', + 'æ' => 'Æ', + 'ç' => 'Ç', + 'è' => 'È', + 'é' => 'É', + 'ê' => 'Ê', + 'ë' => 'Ë', + 'ì' => 'Ì', + 'í' => 'Í', + 'î' => 'Î', + 'ï' => 'Ï', + 'ð' => 'Ð', + 'ñ' => 'Ñ', + 'ò' => 'Ò', + 'ó' => 'Ó', + 'ô' => 'Ô', + 'õ' => 'Õ', + 'ö' => 'Ö', + 'ø' => 'Ø', + 'ù' => 'Ù', + 'ú' => 'Ú', + 'û' => 'Û', + 'ü' => 'Ü', + 'ý' => 'Ý', + 'þ' => 'Þ', + 'ÿ' => 'Ÿ', + 'ā' => 'Ā', + 'ă' => 'Ă', + 'ą' => 'Ą', + 'ć' => 'Ć', + 'ĉ' => 'Ĉ', + 'ċ' => 'Ċ', + 'č' => 'Č', + 'ď' => 'Ď', + 'đ' => 'Đ', + 'ē' => 'Ē', + 'ĕ' => 'Ĕ', + 'ė' => 'Ė', + 'ę' => 'Ę', + 'ě' => 'Ě', + 'ĝ' => 'Ĝ', + 'ğ' => 'Ğ', + 'ġ' => 'Ġ', + 'ģ' => 'Ģ', + 'ĥ' => 'Ĥ', + 'ħ' => 'Ħ', + 'ĩ' => 'Ĩ', + 'ī' => 'Ī', + 'ĭ' => 'Ĭ', + 'į' => 'Į', + 'ı' => 'I', + 'ij' => 'IJ', + 'ĵ' => 'Ĵ', + 'ķ' => 'Ķ', + 'ĺ' => 'Ĺ', + 'ļ' => 'Ļ', + 'ľ' => 'Ľ', + 'ŀ' => 'Ŀ', + 'ł' => 'Ł', + 'ń' => 'Ń', + 'ņ' => 'Ņ', + 'ň' => 'Ň', + 'ŋ' => 'Ŋ', + 'ō' => 'Ō', + 'ŏ' => 'Ŏ', + 'ő' => 'Ő', + 'œ' => 'Œ', + 'ŕ' => 'Ŕ', + 'ŗ' => 'Ŗ', + 'ř' => 'Ř', + 'ś' => 'Ś', + 'ŝ' => 'Ŝ', + 'ş' => 'Ş', + 'š' => 'Š', + 'ţ' => 'Ţ', + 'ť' => 'Ť', + 'ŧ' => 'Ŧ', + 'ũ' => 'Ũ', + 'ū' => 'Ū', + 'ŭ' => 'Ŭ', + 'ů' => 'Ů', + 'ű' => 'Ű', + 'ų' => 'Ų', + 'ŵ' => 'Ŵ', + 'ŷ' => 'Ŷ', + 'ź' => 'Ź', + 'ż' => 'Ż', + 'ž' => 'Ž', + 'ſ' => 'S', + 'ƀ' => 'Ƀ', + 'ƃ' => 'Ƃ', + 'ƅ' => 'Ƅ', + 'ƈ' => 'Ƈ', + 'ƌ' => 'Ƌ', + 'ƒ' => 'Ƒ', + 'ƕ' => 'Ƕ', + 'ƙ' => 'Ƙ', + 'ƚ' => 'Ƚ', + 'ƞ' => 'Ƞ', + 'ơ' => 'Ơ', + 'ƣ' => 'Ƣ', + 'ƥ' => 'Ƥ', + 'ƨ' => 'Ƨ', + 'ƭ' => 'Ƭ', + 'ư' => 'Ư', + 'ƴ' => 'Ƴ', + 'ƶ' => 'Ƶ', + 'ƹ' => 'Ƹ', + 'ƽ' => 'Ƽ', + 'ƿ' => 'Ƿ', + 'Dž' => 'DŽ', + 'dž' => 'DŽ', + 'Lj' => 'LJ', + 'lj' => 'LJ', + 'Nj' => 'NJ', + 'nj' => 'NJ', + 'ǎ' => 'Ǎ', + 'ǐ' => 'Ǐ', + 'ǒ' => 'Ǒ', + 'ǔ' => 'Ǔ', + 'ǖ' => 'Ǖ', + 'ǘ' => 'Ǘ', + 'ǚ' => 'Ǚ', + 'ǜ' => 'Ǜ', + 'ǝ' => 'Ǝ', + 'ǟ' => 'Ǟ', + 'ǡ' => 'Ǡ', + 'ǣ' => 'Ǣ', + 'ǥ' => 'Ǥ', + 'ǧ' => 'Ǧ', + 'ǩ' => 'Ǩ', + 'ǫ' => 'Ǫ', + 'ǭ' => 'Ǭ', + 'ǯ' => 'Ǯ', + 'Dz' => 'DZ', + 'dz' => 'DZ', + 'ǵ' => 'Ǵ', + 'ǹ' => 'Ǹ', + 'ǻ' => 'Ǻ', + 'ǽ' => 'Ǽ', + 'ǿ' => 'Ǿ', + 'ȁ' => 'Ȁ', + 'ȃ' => 'Ȃ', + 'ȅ' => 'Ȅ', + 'ȇ' => 'Ȇ', + 'ȉ' => 'Ȉ', + 'ȋ' => 'Ȋ', + 'ȍ' => 'Ȍ', + 'ȏ' => 'Ȏ', + 'ȑ' => 'Ȑ', + 'ȓ' => 'Ȓ', + 'ȕ' => 'Ȕ', + 'ȗ' => 'Ȗ', + 'ș' => 'Ș', + 'ț' => 'Ț', + 'ȝ' => 'Ȝ', + 'ȟ' => 'Ȟ', + 'ȣ' => 'Ȣ', + 'ȥ' => 'Ȥ', + 'ȧ' => 'Ȧ', + 'ȩ' => 'Ȩ', + 'ȫ' => 'Ȫ', + 'ȭ' => 'Ȭ', + 'ȯ' => 'Ȯ', + 'ȱ' => 'Ȱ', + 'ȳ' => 'Ȳ', + 'ȼ' => 'Ȼ', + 'ȿ' => 'Ȿ', + 'ɀ' => 'Ɀ', + 'ɂ' => 'Ɂ', + 'ɇ' => 'Ɇ', + 'ɉ' => 'Ɉ', + 'ɋ' => 'Ɋ', + 'ɍ' => 'Ɍ', + 'ɏ' => 'Ɏ', + 'ɐ' => 'Ɐ', + 'ɑ' => 'Ɑ', + 'ɒ' => 'Ɒ', + 'ɓ' => 'Ɓ', + 'ɔ' => 'Ɔ', + 'ɖ' => 'Ɖ', + 'ɗ' => 'Ɗ', + 'ə' => 'Ə', + 'ɛ' => 'Ɛ', + 'ɜ' => 'Ɜ', + 'ɠ' => 'Ɠ', + 'ɡ' => 'Ɡ', + 'ɣ' => 'Ɣ', + 'ɥ' => 'Ɥ', + 'ɦ' => 'Ɦ', + 'ɨ' => 'Ɨ', + 'ɩ' => 'Ɩ', + 'ɪ' => 'Ɪ', + 'ɫ' => 'Ɫ', + 'ɬ' => 'Ɬ', + 'ɯ' => 'Ɯ', + 'ɱ' => 'Ɱ', + 'ɲ' => 'Ɲ', + 'ɵ' => 'Ɵ', + 'ɽ' => 'Ɽ', + 'ʀ' => 'Ʀ', + 'ʂ' => 'Ʂ', + 'ʃ' => 'Ʃ', + 'ʇ' => 'Ʇ', + 'ʈ' => 'Ʈ', + 'ʉ' => 'Ʉ', + 'ʊ' => 'Ʊ', + 'ʋ' => 'Ʋ', + 'ʌ' => 'Ʌ', + 'ʒ' => 'Ʒ', + 'ʝ' => 'Ʝ', + 'ʞ' => 'Ʞ', + 'ͅ' => 'Ι', + 'ͱ' => 'Ͱ', + 'ͳ' => 'Ͳ', + 'ͷ' => 'Ͷ', + 'ͻ' => 'Ͻ', + 'ͼ' => 'Ͼ', + 'ͽ' => 'Ͽ', + 'ά' => 'Ά', + 'έ' => 'Έ', + 'ή' => 'Ή', + 'ί' => 'Ί', + 'α' => 'Α', + 'β' => 'Β', + 'γ' => 'Γ', + 'δ' => 'Δ', + 'ε' => 'Ε', + 'ζ' => 'Ζ', + 'η' => 'Η', + 'θ' => 'Θ', + 'ι' => 'Ι', + 'κ' => 'Κ', + 'λ' => 'Λ', + 'μ' => 'Μ', + 'ν' => 'Ν', + 'ξ' => 'Ξ', + 'ο' => 'Ο', + 'π' => 'Π', + 'ρ' => 'Ρ', + 'ς' => 'Σ', + 'σ' => 'Σ', + 'τ' => 'Τ', + 'υ' => 'Υ', + 'φ' => 'Φ', + 'χ' => 'Χ', + 'ψ' => 'Ψ', + 'ω' => 'Ω', + 'ϊ' => 'Ϊ', + 'ϋ' => 'Ϋ', + 'ό' => 'Ό', + 'ύ' => 'Ύ', + 'ώ' => 'Ώ', + 'ϐ' => 'Β', + 'ϑ' => 'Θ', + 'ϕ' => 'Φ', + 'ϖ' => 'Π', + 'ϗ' => 'Ϗ', + 'ϙ' => 'Ϙ', + 'ϛ' => 'Ϛ', + 'ϝ' => 'Ϝ', + 'ϟ' => 'Ϟ', + 'ϡ' => 'Ϡ', + 'ϣ' => 'Ϣ', + 'ϥ' => 'Ϥ', + 'ϧ' => 'Ϧ', + 'ϩ' => 'Ϩ', + 'ϫ' => 'Ϫ', + 'ϭ' => 'Ϭ', + 'ϯ' => 'Ϯ', + 'ϰ' => 'Κ', + 'ϱ' => 'Ρ', + 'ϲ' => 'Ϲ', + 'ϳ' => 'Ϳ', + 'ϵ' => 'Ε', + 'ϸ' => 'Ϸ', + 'ϻ' => 'Ϻ', + 'а' => 'А', + 'б' => 'Б', + 'в' => 'В', + 'г' => 'Г', + 'д' => 'Д', + 'е' => 'Е', + 'ж' => 'Ж', + 'з' => 'З', + 'и' => 'И', + 'й' => 'Й', + 'к' => 'К', + 'л' => 'Л', + 'м' => 'М', + 'н' => 'Н', + 'о' => 'О', + 'п' => 'П', + 'р' => 'Р', + 'с' => 'С', + 'т' => 'Т', + 'у' => 'У', + 'ф' => 'Ф', + 'х' => 'Х', + 'ц' => 'Ц', + 'ч' => 'Ч', + 'ш' => 'Ш', + 'щ' => 'Щ', + 'ъ' => 'Ъ', + 'ы' => 'Ы', + 'ь' => 'Ь', + 'э' => 'Э', + 'ю' => 'Ю', + 'я' => 'Я', + 'ѐ' => 'Ѐ', + 'ё' => 'Ё', + 'ђ' => 'Ђ', + 'ѓ' => 'Ѓ', + 'є' => 'Є', + 'ѕ' => 'Ѕ', + 'і' => 'І', + 'ї' => 'Ї', + 'ј' => 'Ј', + 'љ' => 'Љ', + 'њ' => 'Њ', + 'ћ' => 'Ћ', + 'ќ' => 'Ќ', + 'ѝ' => 'Ѝ', + 'ў' => 'Ў', + 'џ' => 'Џ', + 'ѡ' => 'Ѡ', + 'ѣ' => 'Ѣ', + 'ѥ' => 'Ѥ', + 'ѧ' => 'Ѧ', + 'ѩ' => 'Ѩ', + 'ѫ' => 'Ѫ', + 'ѭ' => 'Ѭ', + 'ѯ' => 'Ѯ', + 'ѱ' => 'Ѱ', + 'ѳ' => 'Ѳ', + 'ѵ' => 'Ѵ', + 'ѷ' => 'Ѷ', + 'ѹ' => 'Ѹ', + 'ѻ' => 'Ѻ', + 'ѽ' => 'Ѽ', + 'ѿ' => 'Ѿ', + 'ҁ' => 'Ҁ', + 'ҋ' => 'Ҋ', + 'ҍ' => 'Ҍ', + 'ҏ' => 'Ҏ', + 'ґ' => 'Ґ', + 'ғ' => 'Ғ', + 'ҕ' => 'Ҕ', + 'җ' => 'Җ', + 'ҙ' => 'Ҙ', + 'қ' => 'Қ', + 'ҝ' => 'Ҝ', + 'ҟ' => 'Ҟ', + 'ҡ' => 'Ҡ', + 'ң' => 'Ң', + 'ҥ' => 'Ҥ', + 'ҧ' => 'Ҧ', + 'ҩ' => 'Ҩ', + 'ҫ' => 'Ҫ', + 'ҭ' => 'Ҭ', + 'ү' => 'Ү', + 'ұ' => 'Ұ', + 'ҳ' => 'Ҳ', + 'ҵ' => 'Ҵ', + 'ҷ' => 'Ҷ', + 'ҹ' => 'Ҹ', + 'һ' => 'Һ', + 'ҽ' => 'Ҽ', + 'ҿ' => 'Ҿ', + 'ӂ' => 'Ӂ', + 'ӄ' => 'Ӄ', + 'ӆ' => 'Ӆ', + 'ӈ' => 'Ӈ', + 'ӊ' => 'Ӊ', + 'ӌ' => 'Ӌ', + 'ӎ' => 'Ӎ', + 'ӏ' => 'Ӏ', + 'ӑ' => 'Ӑ', + 'ӓ' => 'Ӓ', + 'ӕ' => 'Ӕ', + 'ӗ' => 'Ӗ', + 'ә' => 'Ә', + 'ӛ' => 'Ӛ', + 'ӝ' => 'Ӝ', + 'ӟ' => 'Ӟ', + 'ӡ' => 'Ӡ', + 'ӣ' => 'Ӣ', + 'ӥ' => 'Ӥ', + 'ӧ' => 'Ӧ', + 'ө' => 'Ө', + 'ӫ' => 'Ӫ', + 'ӭ' => 'Ӭ', + 'ӯ' => 'Ӯ', + 'ӱ' => 'Ӱ', + 'ӳ' => 'Ӳ', + 'ӵ' => 'Ӵ', + 'ӷ' => 'Ӷ', + 'ӹ' => 'Ӹ', + 'ӻ' => 'Ӻ', + 'ӽ' => 'Ӽ', + 'ӿ' => 'Ӿ', + 'ԁ' => 'Ԁ', + 'ԃ' => 'Ԃ', + 'ԅ' => 'Ԅ', + 'ԇ' => 'Ԇ', + 'ԉ' => 'Ԉ', + 'ԋ' => 'Ԋ', + 'ԍ' => 'Ԍ', + 'ԏ' => 'Ԏ', + 'ԑ' => 'Ԑ', + 'ԓ' => 'Ԓ', + 'ԕ' => 'Ԕ', + 'ԗ' => 'Ԗ', + 'ԙ' => 'Ԙ', + 'ԛ' => 'Ԛ', + 'ԝ' => 'Ԝ', + 'ԟ' => 'Ԟ', + 'ԡ' => 'Ԡ', + 'ԣ' => 'Ԣ', + 'ԥ' => 'Ԥ', + 'ԧ' => 'Ԧ', + 'ԩ' => 'Ԩ', + 'ԫ' => 'Ԫ', + 'ԭ' => 'Ԭ', + 'ԯ' => 'Ԯ', + 'ա' => 'Ա', + 'բ' => 'Բ', + 'գ' => 'Գ', + 'դ' => 'Դ', + 'ե' => 'Ե', + 'զ' => 'Զ', + 'է' => 'Է', + 'ը' => 'Ը', + 'թ' => 'Թ', + 'ժ' => 'Ժ', + 'ի' => 'Ի', + 'լ' => 'Լ', + 'խ' => 'Խ', + 'ծ' => 'Ծ', + 'կ' => 'Կ', + 'հ' => 'Հ', + 'ձ' => 'Ձ', + 'ղ' => 'Ղ', + 'ճ' => 'Ճ', + 'մ' => 'Մ', + 'յ' => 'Յ', + 'ն' => 'Ն', + 'շ' => 'Շ', + 'ո' => 'Ո', + 'չ' => 'Չ', + 'պ' => 'Պ', + 'ջ' => 'Ջ', + 'ռ' => 'Ռ', + 'ս' => 'Ս', + 'վ' => 'Վ', + 'տ' => 'Տ', + 'ր' => 'Ր', + 'ց' => 'Ց', + 'ւ' => 'Ւ', + 'փ' => 'Փ', + 'ք' => 'Ք', + 'օ' => 'Օ', + 'ֆ' => 'Ֆ', + 'ა' => 'Ა', + 'ბ' => 'Ბ', + 'გ' => 'Გ', + 'დ' => 'Დ', + 'ე' => 'Ე', + 'ვ' => 'Ვ', + 'ზ' => 'Ზ', + 'თ' => 'Თ', + 'ი' => 'Ი', + 'კ' => 'Კ', + 'ლ' => 'Ლ', + 'მ' => 'Მ', + 'ნ' => 'Ნ', + 'ო' => 'Ო', + 'პ' => 'Პ', + 'ჟ' => 'Ჟ', + 'რ' => 'Რ', + 'ს' => 'Ს', + 'ტ' => 'Ტ', + 'უ' => 'Უ', + 'ფ' => 'Ფ', + 'ქ' => 'Ქ', + 'ღ' => 'Ღ', + 'ყ' => 'Ყ', + 'შ' => 'Შ', + 'ჩ' => 'Ჩ', + 'ც' => 'Ც', + 'ძ' => 'Ძ', + 'წ' => 'Წ', + 'ჭ' => 'Ჭ', + 'ხ' => 'Ხ', + 'ჯ' => 'Ჯ', + 'ჰ' => 'Ჰ', + 'ჱ' => 'Ჱ', + 'ჲ' => 'Ჲ', + 'ჳ' => 'Ჳ', + 'ჴ' => 'Ჴ', + 'ჵ' => 'Ჵ', + 'ჶ' => 'Ჶ', + 'ჷ' => 'Ჷ', + 'ჸ' => 'Ჸ', + 'ჹ' => 'Ჹ', + 'ჺ' => 'Ჺ', + 'ჽ' => 'Ჽ', + 'ჾ' => 'Ჾ', + 'ჿ' => 'Ჿ', + 'ᏸ' => 'Ᏸ', + 'ᏹ' => 'Ᏹ', + 'ᏺ' => 'Ᏺ', + 'ᏻ' => 'Ᏻ', + 'ᏼ' => 'Ᏼ', + 'ᏽ' => 'Ᏽ', + 'ᲀ' => 'В', + 'ᲁ' => 'Д', + 'ᲂ' => 'О', + 'ᲃ' => 'С', + 'ᲄ' => 'Т', + 'ᲅ' => 'Т', + 'ᲆ' => 'Ъ', + 'ᲇ' => 'Ѣ', + 'ᲈ' => 'Ꙋ', + 'ᵹ' => 'Ᵹ', + 'ᵽ' => 'Ᵽ', + 'ᶎ' => 'Ᶎ', + 'ḁ' => 'Ḁ', + 'ḃ' => 'Ḃ', + 'ḅ' => 'Ḅ', + 'ḇ' => 'Ḇ', + 'ḉ' => 'Ḉ', + 'ḋ' => 'Ḋ', + 'ḍ' => 'Ḍ', + 'ḏ' => 'Ḏ', + 'ḑ' => 'Ḑ', + 'ḓ' => 'Ḓ', + 'ḕ' => 'Ḕ', + 'ḗ' => 'Ḗ', + 'ḙ' => 'Ḙ', + 'ḛ' => 'Ḛ', + 'ḝ' => 'Ḝ', + 'ḟ' => 'Ḟ', + 'ḡ' => 'Ḡ', + 'ḣ' => 'Ḣ', + 'ḥ' => 'Ḥ', + 'ḧ' => 'Ḧ', + 'ḩ' => 'Ḩ', + 'ḫ' => 'Ḫ', + 'ḭ' => 'Ḭ', + 'ḯ' => 'Ḯ', + 'ḱ' => 'Ḱ', + 'ḳ' => 'Ḳ', + 'ḵ' => 'Ḵ', + 'ḷ' => 'Ḷ', + 'ḹ' => 'Ḹ', + 'ḻ' => 'Ḻ', + 'ḽ' => 'Ḽ', + 'ḿ' => 'Ḿ', + 'ṁ' => 'Ṁ', + 'ṃ' => 'Ṃ', + 'ṅ' => 'Ṅ', + 'ṇ' => 'Ṇ', + 'ṉ' => 'Ṉ', + 'ṋ' => 'Ṋ', + 'ṍ' => 'Ṍ', + 'ṏ' => 'Ṏ', + 'ṑ' => 'Ṑ', + 'ṓ' => 'Ṓ', + 'ṕ' => 'Ṕ', + 'ṗ' => 'Ṗ', + 'ṙ' => 'Ṙ', + 'ṛ' => 'Ṛ', + 'ṝ' => 'Ṝ', + 'ṟ' => 'Ṟ', + 'ṡ' => 'Ṡ', + 'ṣ' => 'Ṣ', + 'ṥ' => 'Ṥ', + 'ṧ' => 'Ṧ', + 'ṩ' => 'Ṩ', + 'ṫ' => 'Ṫ', + 'ṭ' => 'Ṭ', + 'ṯ' => 'Ṯ', + 'ṱ' => 'Ṱ', + 'ṳ' => 'Ṳ', + 'ṵ' => 'Ṵ', + 'ṷ' => 'Ṷ', + 'ṹ' => 'Ṹ', + 'ṻ' => 'Ṻ', + 'ṽ' => 'Ṽ', + 'ṿ' => 'Ṿ', + 'ẁ' => 'Ẁ', + 'ẃ' => 'Ẃ', + 'ẅ' => 'Ẅ', + 'ẇ' => 'Ẇ', + 'ẉ' => 'Ẉ', + 'ẋ' => 'Ẋ', + 'ẍ' => 'Ẍ', + 'ẏ' => 'Ẏ', + 'ẑ' => 'Ẑ', + 'ẓ' => 'Ẓ', + 'ẕ' => 'Ẕ', + 'ẛ' => 'Ṡ', + 'ạ' => 'Ạ', + 'ả' => 'Ả', + 'ấ' => 'Ấ', + 'ầ' => 'Ầ', + 'ẩ' => 'Ẩ', + 'ẫ' => 'Ẫ', + 'ậ' => 'Ậ', + 'ắ' => 'Ắ', + 'ằ' => 'Ằ', + 'ẳ' => 'Ẳ', + 'ẵ' => 'Ẵ', + 'ặ' => 'Ặ', + 'ẹ' => 'Ẹ', + 'ẻ' => 'Ẻ', + 'ẽ' => 'Ẽ', + 'ế' => 'Ế', + 'ề' => 'Ề', + 'ể' => 'Ể', + 'ễ' => 'Ễ', + 'ệ' => 'Ệ', + 'ỉ' => 'Ỉ', + 'ị' => 'Ị', + 'ọ' => 'Ọ', + 'ỏ' => 'Ỏ', + 'ố' => 'Ố', + 'ồ' => 'Ồ', + 'ổ' => 'Ổ', + 'ỗ' => 'Ỗ', + 'ộ' => 'Ộ', + 'ớ' => 'Ớ', + 'ờ' => 'Ờ', + 'ở' => 'Ở', + 'ỡ' => 'Ỡ', + 'ợ' => 'Ợ', + 'ụ' => 'Ụ', + 'ủ' => 'Ủ', + 'ứ' => 'Ứ', + 'ừ' => 'Ừ', + 'ử' => 'Ử', + 'ữ' => 'Ữ', + 'ự' => 'Ự', + 'ỳ' => 'Ỳ', + 'ỵ' => 'Ỵ', + 'ỷ' => 'Ỷ', + 'ỹ' => 'Ỹ', + 'ỻ' => 'Ỻ', + 'ỽ' => 'Ỽ', + 'ỿ' => 'Ỿ', + 'ἀ' => 'Ἀ', + 'ἁ' => 'Ἁ', + 'ἂ' => 'Ἂ', + 'ἃ' => 'Ἃ', + 'ἄ' => 'Ἄ', + 'ἅ' => 'Ἅ', + 'ἆ' => 'Ἆ', + 'ἇ' => 'Ἇ', + 'ἐ' => 'Ἐ', + 'ἑ' => 'Ἑ', + 'ἒ' => 'Ἒ', + 'ἓ' => 'Ἓ', + 'ἔ' => 'Ἔ', + 'ἕ' => 'Ἕ', + 'ἠ' => 'Ἠ', + 'ἡ' => 'Ἡ', + 'ἢ' => 'Ἢ', + 'ἣ' => 'Ἣ', + 'ἤ' => 'Ἤ', + 'ἥ' => 'Ἥ', + 'ἦ' => 'Ἦ', + 'ἧ' => 'Ἧ', + 'ἰ' => 'Ἰ', + 'ἱ' => 'Ἱ', + 'ἲ' => 'Ἲ', + 'ἳ' => 'Ἳ', + 'ἴ' => 'Ἴ', + 'ἵ' => 'Ἵ', + 'ἶ' => 'Ἶ', + 'ἷ' => 'Ἷ', + 'ὀ' => 'Ὀ', + 'ὁ' => 'Ὁ', + 'ὂ' => 'Ὂ', + 'ὃ' => 'Ὃ', + 'ὄ' => 'Ὄ', + 'ὅ' => 'Ὅ', + 'ὑ' => 'Ὑ', + 'ὓ' => 'Ὓ', + 'ὕ' => 'Ὕ', + 'ὗ' => 'Ὗ', + 'ὠ' => 'Ὠ', + 'ὡ' => 'Ὡ', + 'ὢ' => 'Ὢ', + 'ὣ' => 'Ὣ', + 'ὤ' => 'Ὤ', + 'ὥ' => 'Ὥ', + 'ὦ' => 'Ὦ', + 'ὧ' => 'Ὧ', + 'ὰ' => 'Ὰ', + 'ά' => 'Ά', + 'ὲ' => 'Ὲ', + 'έ' => 'Έ', + 'ὴ' => 'Ὴ', + 'ή' => 'Ή', + 'ὶ' => 'Ὶ', + 'ί' => 'Ί', + 'ὸ' => 'Ὸ', + 'ό' => 'Ό', + 'ὺ' => 'Ὺ', + 'ύ' => 'Ύ', + 'ὼ' => 'Ὼ', + 'ώ' => 'Ώ', + 'ᾀ' => 'ἈΙ', + 'ᾁ' => 'ἉΙ', + 'ᾂ' => 'ἊΙ', + 'ᾃ' => 'ἋΙ', + 'ᾄ' => 'ἌΙ', + 'ᾅ' => 'ἍΙ', + 'ᾆ' => 'ἎΙ', + 'ᾇ' => 'ἏΙ', + 'ᾐ' => 'ἨΙ', + 'ᾑ' => 'ἩΙ', + 'ᾒ' => 'ἪΙ', + 'ᾓ' => 'ἫΙ', + 'ᾔ' => 'ἬΙ', + 'ᾕ' => 'ἭΙ', + 'ᾖ' => 'ἮΙ', + 'ᾗ' => 'ἯΙ', + 'ᾠ' => 'ὨΙ', + 'ᾡ' => 'ὩΙ', + 'ᾢ' => 'ὪΙ', + 'ᾣ' => 'ὫΙ', + 'ᾤ' => 'ὬΙ', + 'ᾥ' => 'ὭΙ', + 'ᾦ' => 'ὮΙ', + 'ᾧ' => 'ὯΙ', + 'ᾰ' => 'Ᾰ', + 'ᾱ' => 'Ᾱ', + 'ᾳ' => 'ΑΙ', + 'ι' => 'Ι', + 'ῃ' => 'ΗΙ', + 'ῐ' => 'Ῐ', + 'ῑ' => 'Ῑ', + 'ῠ' => 'Ῠ', + 'ῡ' => 'Ῡ', + 'ῥ' => 'Ῥ', + 'ῳ' => 'ΩΙ', + 'ⅎ' => 'Ⅎ', + 'ⅰ' => 'Ⅰ', + 'ⅱ' => 'Ⅱ', + 'ⅲ' => 'Ⅲ', + 'ⅳ' => 'Ⅳ', + 'ⅴ' => 'Ⅴ', + 'ⅵ' => 'Ⅵ', + 'ⅶ' => 'Ⅶ', + 'ⅷ' => 'Ⅷ', + 'ⅸ' => 'Ⅸ', + 'ⅹ' => 'Ⅹ', + 'ⅺ' => 'Ⅺ', + 'ⅻ' => 'Ⅻ', + 'ⅼ' => 'Ⅼ', + 'ⅽ' => 'Ⅽ', + 'ⅾ' => 'Ⅾ', + 'ⅿ' => 'Ⅿ', + 'ↄ' => 'Ↄ', + 'ⓐ' => 'Ⓐ', + 'ⓑ' => 'Ⓑ', + 'ⓒ' => 'Ⓒ', + 'ⓓ' => 'Ⓓ', + 'ⓔ' => 'Ⓔ', + 'ⓕ' => 'Ⓕ', + 'ⓖ' => 'Ⓖ', + 'ⓗ' => 'Ⓗ', + 'ⓘ' => 'Ⓘ', + 'ⓙ' => 'Ⓙ', + 'ⓚ' => 'Ⓚ', + 'ⓛ' => 'Ⓛ', + 'ⓜ' => 'Ⓜ', + 'ⓝ' => 'Ⓝ', + 'ⓞ' => 'Ⓞ', + 'ⓟ' => 'Ⓟ', + 'ⓠ' => 'Ⓠ', + 'ⓡ' => 'Ⓡ', + 'ⓢ' => 'Ⓢ', + 'ⓣ' => 'Ⓣ', + 'ⓤ' => 'Ⓤ', + 'ⓥ' => 'Ⓥ', + 'ⓦ' => 'Ⓦ', + 'ⓧ' => 'Ⓧ', + 'ⓨ' => 'Ⓨ', + 'ⓩ' => 'Ⓩ', + 'ⰰ' => 'Ⰰ', + 'ⰱ' => 'Ⰱ', + 'ⰲ' => 'Ⰲ', + 'ⰳ' => 'Ⰳ', + 'ⰴ' => 'Ⰴ', + 'ⰵ' => 'Ⰵ', + 'ⰶ' => 'Ⰶ', + 'ⰷ' => 'Ⰷ', + 'ⰸ' => 'Ⰸ', + 'ⰹ' => 'Ⰹ', + 'ⰺ' => 'Ⰺ', + 'ⰻ' => 'Ⰻ', + 'ⰼ' => 'Ⰼ', + 'ⰽ' => 'Ⰽ', + 'ⰾ' => 'Ⰾ', + 'ⰿ' => 'Ⰿ', + 'ⱀ' => 'Ⱀ', + 'ⱁ' => 'Ⱁ', + 'ⱂ' => 'Ⱂ', + 'ⱃ' => 'Ⱃ', + 'ⱄ' => 'Ⱄ', + 'ⱅ' => 'Ⱅ', + 'ⱆ' => 'Ⱆ', + 'ⱇ' => 'Ⱇ', + 'ⱈ' => 'Ⱈ', + 'ⱉ' => 'Ⱉ', + 'ⱊ' => 'Ⱊ', + 'ⱋ' => 'Ⱋ', + 'ⱌ' => 'Ⱌ', + 'ⱍ' => 'Ⱍ', + 'ⱎ' => 'Ⱎ', + 'ⱏ' => 'Ⱏ', + 'ⱐ' => 'Ⱐ', + 'ⱑ' => 'Ⱑ', + 'ⱒ' => 'Ⱒ', + 'ⱓ' => 'Ⱓ', + 'ⱔ' => 'Ⱔ', + 'ⱕ' => 'Ⱕ', + 'ⱖ' => 'Ⱖ', + 'ⱗ' => 'Ⱗ', + 'ⱘ' => 'Ⱘ', + 'ⱙ' => 'Ⱙ', + 'ⱚ' => 'Ⱚ', + 'ⱛ' => 'Ⱛ', + 'ⱜ' => 'Ⱜ', + 'ⱝ' => 'Ⱝ', + 'ⱞ' => 'Ⱞ', + 'ⱡ' => 'Ⱡ', + 'ⱥ' => 'Ⱥ', + 'ⱦ' => 'Ⱦ', + 'ⱨ' => 'Ⱨ', + 'ⱪ' => 'Ⱪ', + 'ⱬ' => 'Ⱬ', + 'ⱳ' => 'Ⱳ', + 'ⱶ' => 'Ⱶ', + 'ⲁ' => 'Ⲁ', + 'ⲃ' => 'Ⲃ', + 'ⲅ' => 'Ⲅ', + 'ⲇ' => 'Ⲇ', + 'ⲉ' => 'Ⲉ', + 'ⲋ' => 'Ⲋ', + 'ⲍ' => 'Ⲍ', + 'ⲏ' => 'Ⲏ', + 'ⲑ' => 'Ⲑ', + 'ⲓ' => 'Ⲓ', + 'ⲕ' => 'Ⲕ', + 'ⲗ' => 'Ⲗ', + 'ⲙ' => 'Ⲙ', + 'ⲛ' => 'Ⲛ', + 'ⲝ' => 'Ⲝ', + 'ⲟ' => 'Ⲟ', + 'ⲡ' => 'Ⲡ', + 'ⲣ' => 'Ⲣ', + 'ⲥ' => 'Ⲥ', + 'ⲧ' => 'Ⲧ', + 'ⲩ' => 'Ⲩ', + 'ⲫ' => 'Ⲫ', + 'ⲭ' => 'Ⲭ', + 'ⲯ' => 'Ⲯ', + 'ⲱ' => 'Ⲱ', + 'ⲳ' => 'Ⲳ', + 'ⲵ' => 'Ⲵ', + 'ⲷ' => 'Ⲷ', + 'ⲹ' => 'Ⲹ', + 'ⲻ' => 'Ⲻ', + 'ⲽ' => 'Ⲽ', + 'ⲿ' => 'Ⲿ', + 'ⳁ' => 'Ⳁ', + 'ⳃ' => 'Ⳃ', + 'ⳅ' => 'Ⳅ', + 'ⳇ' => 'Ⳇ', + 'ⳉ' => 'Ⳉ', + 'ⳋ' => 'Ⳋ', + 'ⳍ' => 'Ⳍ', + 'ⳏ' => 'Ⳏ', + 'ⳑ' => 'Ⳑ', + 'ⳓ' => 'Ⳓ', + 'ⳕ' => 'Ⳕ', + 'ⳗ' => 'Ⳗ', + 'ⳙ' => 'Ⳙ', + 'ⳛ' => 'Ⳛ', + 'ⳝ' => 'Ⳝ', + 'ⳟ' => 'Ⳟ', + 'ⳡ' => 'Ⳡ', + 'ⳣ' => 'Ⳣ', + 'ⳬ' => 'Ⳬ', + 'ⳮ' => 'Ⳮ', + 'ⳳ' => 'Ⳳ', + 'ⴀ' => 'Ⴀ', + 'ⴁ' => 'Ⴁ', + 'ⴂ' => 'Ⴂ', + 'ⴃ' => 'Ⴃ', + 'ⴄ' => 'Ⴄ', + 'ⴅ' => 'Ⴅ', + 'ⴆ' => 'Ⴆ', + 'ⴇ' => 'Ⴇ', + 'ⴈ' => 'Ⴈ', + 'ⴉ' => 'Ⴉ', + 'ⴊ' => 'Ⴊ', + 'ⴋ' => 'Ⴋ', + 'ⴌ' => 'Ⴌ', + 'ⴍ' => 'Ⴍ', + 'ⴎ' => 'Ⴎ', + 'ⴏ' => 'Ⴏ', + 'ⴐ' => 'Ⴐ', + 'ⴑ' => 'Ⴑ', + 'ⴒ' => 'Ⴒ', + 'ⴓ' => 'Ⴓ', + 'ⴔ' => 'Ⴔ', + 'ⴕ' => 'Ⴕ', + 'ⴖ' => 'Ⴖ', + 'ⴗ' => 'Ⴗ', + 'ⴘ' => 'Ⴘ', + 'ⴙ' => 'Ⴙ', + 'ⴚ' => 'Ⴚ', + 'ⴛ' => 'Ⴛ', + 'ⴜ' => 'Ⴜ', + 'ⴝ' => 'Ⴝ', + 'ⴞ' => 'Ⴞ', + 'ⴟ' => 'Ⴟ', + 'ⴠ' => 'Ⴠ', + 'ⴡ' => 'Ⴡ', + 'ⴢ' => 'Ⴢ', + 'ⴣ' => 'Ⴣ', + 'ⴤ' => 'Ⴤ', + 'ⴥ' => 'Ⴥ', + 'ⴧ' => 'Ⴧ', + 'ⴭ' => 'Ⴭ', + 'ꙁ' => 'Ꙁ', + 'ꙃ' => 'Ꙃ', + 'ꙅ' => 'Ꙅ', + 'ꙇ' => 'Ꙇ', + 'ꙉ' => 'Ꙉ', + 'ꙋ' => 'Ꙋ', + 'ꙍ' => 'Ꙍ', + 'ꙏ' => 'Ꙏ', + 'ꙑ' => 'Ꙑ', + 'ꙓ' => 'Ꙓ', + 'ꙕ' => 'Ꙕ', + 'ꙗ' => 'Ꙗ', + 'ꙙ' => 'Ꙙ', + 'ꙛ' => 'Ꙛ', + 'ꙝ' => 'Ꙝ', + 'ꙟ' => 'Ꙟ', + 'ꙡ' => 'Ꙡ', + 'ꙣ' => 'Ꙣ', + 'ꙥ' => 'Ꙥ', + 'ꙧ' => 'Ꙧ', + 'ꙩ' => 'Ꙩ', + 'ꙫ' => 'Ꙫ', + 'ꙭ' => 'Ꙭ', + 'ꚁ' => 'Ꚁ', + 'ꚃ' => 'Ꚃ', + 'ꚅ' => 'Ꚅ', + 'ꚇ' => 'Ꚇ', + 'ꚉ' => 'Ꚉ', + 'ꚋ' => 'Ꚋ', + 'ꚍ' => 'Ꚍ', + 'ꚏ' => 'Ꚏ', + 'ꚑ' => 'Ꚑ', + 'ꚓ' => 'Ꚓ', + 'ꚕ' => 'Ꚕ', + 'ꚗ' => 'Ꚗ', + 'ꚙ' => 'Ꚙ', + 'ꚛ' => 'Ꚛ', + 'ꜣ' => 'Ꜣ', + 'ꜥ' => 'Ꜥ', + 'ꜧ' => 'Ꜧ', + 'ꜩ' => 'Ꜩ', + 'ꜫ' => 'Ꜫ', + 'ꜭ' => 'Ꜭ', + 'ꜯ' => 'Ꜯ', + 'ꜳ' => 'Ꜳ', + 'ꜵ' => 'Ꜵ', + 'ꜷ' => 'Ꜷ', + 'ꜹ' => 'Ꜹ', + 'ꜻ' => 'Ꜻ', + 'ꜽ' => 'Ꜽ', + 'ꜿ' => 'Ꜿ', + 'ꝁ' => 'Ꝁ', + 'ꝃ' => 'Ꝃ', + 'ꝅ' => 'Ꝅ', + 'ꝇ' => 'Ꝇ', + 'ꝉ' => 'Ꝉ', + 'ꝋ' => 'Ꝋ', + 'ꝍ' => 'Ꝍ', + 'ꝏ' => 'Ꝏ', + 'ꝑ' => 'Ꝑ', + 'ꝓ' => 'Ꝓ', + 'ꝕ' => 'Ꝕ', + 'ꝗ' => 'Ꝗ', + 'ꝙ' => 'Ꝙ', + 'ꝛ' => 'Ꝛ', + 'ꝝ' => 'Ꝝ', + 'ꝟ' => 'Ꝟ', + 'ꝡ' => 'Ꝡ', + 'ꝣ' => 'Ꝣ', + 'ꝥ' => 'Ꝥ', + 'ꝧ' => 'Ꝧ', + 'ꝩ' => 'Ꝩ', + 'ꝫ' => 'Ꝫ', + 'ꝭ' => 'Ꝭ', + 'ꝯ' => 'Ꝯ', + 'ꝺ' => 'Ꝺ', + 'ꝼ' => 'Ꝼ', + 'ꝿ' => 'Ꝿ', + 'ꞁ' => 'Ꞁ', + 'ꞃ' => 'Ꞃ', + 'ꞅ' => 'Ꞅ', + 'ꞇ' => 'Ꞇ', + 'ꞌ' => 'Ꞌ', + 'ꞑ' => 'Ꞑ', + 'ꞓ' => 'Ꞓ', + 'ꞔ' => 'Ꞔ', + 'ꞗ' => 'Ꞗ', + 'ꞙ' => 'Ꞙ', + 'ꞛ' => 'Ꞛ', + 'ꞝ' => 'Ꞝ', + 'ꞟ' => 'Ꞟ', + 'ꞡ' => 'Ꞡ', + 'ꞣ' => 'Ꞣ', + 'ꞥ' => 'Ꞥ', + 'ꞧ' => 'Ꞧ', + 'ꞩ' => 'Ꞩ', + 'ꞵ' => 'Ꞵ', + 'ꞷ' => 'Ꞷ', + 'ꞹ' => 'Ꞹ', + 'ꞻ' => 'Ꞻ', + 'ꞽ' => 'Ꞽ', + 'ꞿ' => 'Ꞿ', + 'ꟃ' => 'Ꟃ', + 'ꟈ' => 'Ꟈ', + 'ꟊ' => 'Ꟊ', + 'ꟶ' => 'Ꟶ', + 'ꭓ' => 'Ꭓ', + 'ꭰ' => 'Ꭰ', + 'ꭱ' => 'Ꭱ', + 'ꭲ' => 'Ꭲ', + 'ꭳ' => 'Ꭳ', + 'ꭴ' => 'Ꭴ', + 'ꭵ' => 'Ꭵ', + 'ꭶ' => 'Ꭶ', + 'ꭷ' => 'Ꭷ', + 'ꭸ' => 'Ꭸ', + 'ꭹ' => 'Ꭹ', + 'ꭺ' => 'Ꭺ', + 'ꭻ' => 'Ꭻ', + 'ꭼ' => 'Ꭼ', + 'ꭽ' => 'Ꭽ', + 'ꭾ' => 'Ꭾ', + 'ꭿ' => 'Ꭿ', + 'ꮀ' => 'Ꮀ', + 'ꮁ' => 'Ꮁ', + 'ꮂ' => 'Ꮂ', + 'ꮃ' => 'Ꮃ', + 'ꮄ' => 'Ꮄ', + 'ꮅ' => 'Ꮅ', + 'ꮆ' => 'Ꮆ', + 'ꮇ' => 'Ꮇ', + 'ꮈ' => 'Ꮈ', + 'ꮉ' => 'Ꮉ', + 'ꮊ' => 'Ꮊ', + 'ꮋ' => 'Ꮋ', + 'ꮌ' => 'Ꮌ', + 'ꮍ' => 'Ꮍ', + 'ꮎ' => 'Ꮎ', + 'ꮏ' => 'Ꮏ', + 'ꮐ' => 'Ꮐ', + 'ꮑ' => 'Ꮑ', + 'ꮒ' => 'Ꮒ', + 'ꮓ' => 'Ꮓ', + 'ꮔ' => 'Ꮔ', + 'ꮕ' => 'Ꮕ', + 'ꮖ' => 'Ꮖ', + 'ꮗ' => 'Ꮗ', + 'ꮘ' => 'Ꮘ', + 'ꮙ' => 'Ꮙ', + 'ꮚ' => 'Ꮚ', + 'ꮛ' => 'Ꮛ', + 'ꮜ' => 'Ꮜ', + 'ꮝ' => 'Ꮝ', + 'ꮞ' => 'Ꮞ', + 'ꮟ' => 'Ꮟ', + 'ꮠ' => 'Ꮠ', + 'ꮡ' => 'Ꮡ', + 'ꮢ' => 'Ꮢ', + 'ꮣ' => 'Ꮣ', + 'ꮤ' => 'Ꮤ', + 'ꮥ' => 'Ꮥ', + 'ꮦ' => 'Ꮦ', + 'ꮧ' => 'Ꮧ', + 'ꮨ' => 'Ꮨ', + 'ꮩ' => 'Ꮩ', + 'ꮪ' => 'Ꮪ', + 'ꮫ' => 'Ꮫ', + 'ꮬ' => 'Ꮬ', + 'ꮭ' => 'Ꮭ', + 'ꮮ' => 'Ꮮ', + 'ꮯ' => 'Ꮯ', + 'ꮰ' => 'Ꮰ', + 'ꮱ' => 'Ꮱ', + 'ꮲ' => 'Ꮲ', + 'ꮳ' => 'Ꮳ', + 'ꮴ' => 'Ꮴ', + 'ꮵ' => 'Ꮵ', + 'ꮶ' => 'Ꮶ', + 'ꮷ' => 'Ꮷ', + 'ꮸ' => 'Ꮸ', + 'ꮹ' => 'Ꮹ', + 'ꮺ' => 'Ꮺ', + 'ꮻ' => 'Ꮻ', + 'ꮼ' => 'Ꮼ', + 'ꮽ' => 'Ꮽ', + 'ꮾ' => 'Ꮾ', + 'ꮿ' => 'Ꮿ', + 'a' => 'A', + 'b' => 'B', + 'c' => 'C', + 'd' => 'D', + 'e' => 'E', + 'f' => 'F', + 'g' => 'G', + 'h' => 'H', + 'i' => 'I', + 'j' => 'J', + 'k' => 'K', + 'l' => 'L', + 'm' => 'M', + 'n' => 'N', + 'o' => 'O', + 'p' => 'P', + 'q' => 'Q', + 'r' => 'R', + 's' => 'S', + 't' => 'T', + 'u' => 'U', + 'v' => 'V', + 'w' => 'W', + 'x' => 'X', + 'y' => 'Y', + 'z' => 'Z', + '𐐨' => '𐐀', + '𐐩' => '𐐁', + '𐐪' => '𐐂', + '𐐫' => '𐐃', + '𐐬' => '𐐄', + '𐐭' => '𐐅', + '𐐮' => '𐐆', + '𐐯' => '𐐇', + '𐐰' => '𐐈', + '𐐱' => '𐐉', + '𐐲' => '𐐊', + '𐐳' => '𐐋', + '𐐴' => '𐐌', + '𐐵' => '𐐍', + '𐐶' => '𐐎', + '𐐷' => '𐐏', + '𐐸' => '𐐐', + '𐐹' => '𐐑', + '𐐺' => '𐐒', + '𐐻' => '𐐓', + '𐐼' => '𐐔', + '𐐽' => '𐐕', + '𐐾' => '𐐖', + '𐐿' => '𐐗', + '𐑀' => '𐐘', + '𐑁' => '𐐙', + '𐑂' => '𐐚', + '𐑃' => '𐐛', + '𐑄' => '𐐜', + '𐑅' => '𐐝', + '𐑆' => '𐐞', + '𐑇' => '𐐟', + '𐑈' => '𐐠', + '𐑉' => '𐐡', + '𐑊' => '𐐢', + '𐑋' => '𐐣', + '𐑌' => '𐐤', + '𐑍' => '𐐥', + '𐑎' => '𐐦', + '𐑏' => '𐐧', + '𐓘' => '𐒰', + '𐓙' => '𐒱', + '𐓚' => '𐒲', + '𐓛' => '𐒳', + '𐓜' => '𐒴', + '𐓝' => '𐒵', + '𐓞' => '𐒶', + '𐓟' => '𐒷', + '𐓠' => '𐒸', + '𐓡' => '𐒹', + '𐓢' => '𐒺', + '𐓣' => '𐒻', + '𐓤' => '𐒼', + '𐓥' => '𐒽', + '𐓦' => '𐒾', + '𐓧' => '𐒿', + '𐓨' => '𐓀', + '𐓩' => '𐓁', + '𐓪' => '𐓂', + '𐓫' => '𐓃', + '𐓬' => '𐓄', + '𐓭' => '𐓅', + '𐓮' => '𐓆', + '𐓯' => '𐓇', + '𐓰' => '𐓈', + '𐓱' => '𐓉', + '𐓲' => '𐓊', + '𐓳' => '𐓋', + '𐓴' => '𐓌', + '𐓵' => '𐓍', + '𐓶' => '𐓎', + '𐓷' => '𐓏', + '𐓸' => '𐓐', + '𐓹' => '𐓑', + '𐓺' => '𐓒', + '𐓻' => '𐓓', + '𐳀' => '𐲀', + '𐳁' => '𐲁', + '𐳂' => '𐲂', + '𐳃' => '𐲃', + '𐳄' => '𐲄', + '𐳅' => '𐲅', + '𐳆' => '𐲆', + '𐳇' => '𐲇', + '𐳈' => '𐲈', + '𐳉' => '𐲉', + '𐳊' => '𐲊', + '𐳋' => '𐲋', + '𐳌' => '𐲌', + '𐳍' => '𐲍', + '𐳎' => '𐲎', + '𐳏' => '𐲏', + '𐳐' => '𐲐', + '𐳑' => '𐲑', + '𐳒' => '𐲒', + '𐳓' => '𐲓', + '𐳔' => '𐲔', + '𐳕' => '𐲕', + '𐳖' => '𐲖', + '𐳗' => '𐲗', + '𐳘' => '𐲘', + '𐳙' => '𐲙', + '𐳚' => '𐲚', + '𐳛' => '𐲛', + '𐳜' => '𐲜', + '𐳝' => '𐲝', + '𐳞' => '𐲞', + '𐳟' => '𐲟', + '𐳠' => '𐲠', + '𐳡' => '𐲡', + '𐳢' => '𐲢', + '𐳣' => '𐲣', + '𐳤' => '𐲤', + '𐳥' => '𐲥', + '𐳦' => '𐲦', + '𐳧' => '𐲧', + '𐳨' => '𐲨', + '𐳩' => '𐲩', + '𐳪' => '𐲪', + '𐳫' => '𐲫', + '𐳬' => '𐲬', + '𐳭' => '𐲭', + '𐳮' => '𐲮', + '𐳯' => '𐲯', + '𐳰' => '𐲰', + '𐳱' => '𐲱', + '𐳲' => '𐲲', + '𑣀' => '𑢠', + '𑣁' => '𑢡', + '𑣂' => '𑢢', + '𑣃' => '𑢣', + '𑣄' => '𑢤', + '𑣅' => '𑢥', + '𑣆' => '𑢦', + '𑣇' => '𑢧', + '𑣈' => '𑢨', + '𑣉' => '𑢩', + '𑣊' => '𑢪', + '𑣋' => '𑢫', + '𑣌' => '𑢬', + '𑣍' => '𑢭', + '𑣎' => '𑢮', + '𑣏' => '𑢯', + '𑣐' => '𑢰', + '𑣑' => '𑢱', + '𑣒' => '𑢲', + '𑣓' => '𑢳', + '𑣔' => '𑢴', + '𑣕' => '𑢵', + '𑣖' => '𑢶', + '𑣗' => '𑢷', + '𑣘' => '𑢸', + '𑣙' => '𑢹', + '𑣚' => '𑢺', + '𑣛' => '𑢻', + '𑣜' => '𑢼', + '𑣝' => '𑢽', + '𑣞' => '𑢾', + '𑣟' => '𑢿', + '𖹠' => '𖹀', + '𖹡' => '𖹁', + '𖹢' => '𖹂', + '𖹣' => '𖹃', + '𖹤' => '𖹄', + '𖹥' => '𖹅', + '𖹦' => '𖹆', + '𖹧' => '𖹇', + '𖹨' => '𖹈', + '𖹩' => '𖹉', + '𖹪' => '𖹊', + '𖹫' => '𖹋', + '𖹬' => '𖹌', + '𖹭' => '𖹍', + '𖹮' => '𖹎', + '𖹯' => '𖹏', + '𖹰' => '𖹐', + '𖹱' => '𖹑', + '𖹲' => '𖹒', + '𖹳' => '𖹓', + '𖹴' => '𖹔', + '𖹵' => '𖹕', + '𖹶' => '𖹖', + '𖹷' => '𖹗', + '𖹸' => '𖹘', + '𖹹' => '𖹙', + '𖹺' => '𖹚', + '𖹻' => '𖹛', + '𖹼' => '𖹜', + '𖹽' => '𖹝', + '𖹾' => '𖹞', + '𖹿' => '𖹟', + '𞤢' => '𞤀', + '𞤣' => '𞤁', + '𞤤' => '𞤂', + '𞤥' => '𞤃', + '𞤦' => '𞤄', + '𞤧' => '𞤅', + '𞤨' => '𞤆', + '𞤩' => '𞤇', + '𞤪' => '𞤈', + '𞤫' => '𞤉', + '𞤬' => '𞤊', + '𞤭' => '𞤋', + '𞤮' => '𞤌', + '𞤯' => '𞤍', + '𞤰' => '𞤎', + '𞤱' => '𞤏', + '𞤲' => '𞤐', + '𞤳' => '𞤑', + '𞤴' => '𞤒', + '𞤵' => '𞤓', + '𞤶' => '𞤔', + '𞤷' => '𞤕', + '𞤸' => '𞤖', + '𞤹' => '𞤗', + '𞤺' => '𞤘', + '𞤻' => '𞤙', + '𞤼' => '𞤚', + '𞤽' => '𞤛', + '𞤾' => '𞤜', + '𞤿' => '𞤝', + '𞥀' => '𞤞', + '𞥁' => '𞤟', + '𞥂' => '𞤠', + '𞥃' => '𞤡', + 'ß' => 'SS', + 'ff' => 'FF', + 'fi' => 'FI', + 'fl' => 'FL', + 'ffi' => 'FFI', + 'ffl' => 'FFL', + 'ſt' => 'ST', + 'st' => 'ST', + 'և' => 'ԵՒ', + 'ﬓ' => 'ՄՆ', + 'ﬔ' => 'ՄԵ', + 'ﬕ' => 'ՄԻ', + 'ﬖ' => 'ՎՆ', + 'ﬗ' => 'ՄԽ', + 'ʼn' => 'ʼN', + 'ΐ' => 'Ϊ́', + 'ΰ' => 'Ϋ́', + 'ǰ' => 'J̌', + 'ẖ' => 'H̱', + 'ẗ' => 'T̈', + 'ẘ' => 'W̊', + 'ẙ' => 'Y̊', + 'ẚ' => 'Aʾ', + 'ὐ' => 'Υ̓', + 'ὒ' => 'Υ̓̀', + 'ὔ' => 'Υ̓́', + 'ὖ' => 'Υ̓͂', + 'ᾶ' => 'Α͂', + 'ῆ' => 'Η͂', + 'ῒ' => 'Ϊ̀', + 'ΐ' => 'Ϊ́', + 'ῖ' => 'Ι͂', + 'ῗ' => 'Ϊ͂', + 'ῢ' => 'Ϋ̀', + 'ΰ' => 'Ϋ́', + 'ῤ' => 'Ρ̓', + 'ῦ' => 'Υ͂', + 'ῧ' => 'Ϋ͂', + 'ῶ' => 'Ω͂', + 'ᾈ' => 'ἈΙ', + 'ᾉ' => 'ἉΙ', + 'ᾊ' => 'ἊΙ', + 'ᾋ' => 'ἋΙ', + 'ᾌ' => 'ἌΙ', + 'ᾍ' => 'ἍΙ', + 'ᾎ' => 'ἎΙ', + 'ᾏ' => 'ἏΙ', + 'ᾘ' => 'ἨΙ', + 'ᾙ' => 'ἩΙ', + 'ᾚ' => 'ἪΙ', + 'ᾛ' => 'ἫΙ', + 'ᾜ' => 'ἬΙ', + 'ᾝ' => 'ἭΙ', + 'ᾞ' => 'ἮΙ', + 'ᾟ' => 'ἯΙ', + 'ᾨ' => 'ὨΙ', + 'ᾩ' => 'ὩΙ', + 'ᾪ' => 'ὪΙ', + 'ᾫ' => 'ὫΙ', + 'ᾬ' => 'ὬΙ', + 'ᾭ' => 'ὭΙ', + 'ᾮ' => 'ὮΙ', + 'ᾯ' => 'ὯΙ', + 'ᾼ' => 'ΑΙ', + 'ῌ' => 'ΗΙ', + 'ῼ' => 'ΩΙ', + 'ᾲ' => 'ᾺΙ', + 'ᾴ' => 'ΆΙ', + 'ῂ' => 'ῊΙ', + 'ῄ' => 'ΉΙ', + 'ῲ' => 'ῺΙ', + 'ῴ' => 'ΏΙ', + 'ᾷ' => 'Α͂Ι', + 'ῇ' => 'Η͂Ι', + 'ῷ' => 'Ω͂Ι', +); diff --git a/tools/mailer/symfony/polyfill-mbstring/bootstrap.php b/tools/mailer/symfony/polyfill-mbstring/bootstrap.php new file mode 100644 index 000000000..ff51ae079 --- /dev/null +++ b/tools/mailer/symfony/polyfill-mbstring/bootstrap.php @@ -0,0 +1,172 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Mbstring as p; + +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__.'/bootstrap80.php'; +} + +if (!function_exists('mb_convert_encoding')) { + function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); } +} +if (!function_exists('mb_decode_mimeheader')) { + function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); } +} +if (!function_exists('mb_encode_mimeheader')) { + function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); } +} +if (!function_exists('mb_decode_numericentity')) { + function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); } +} +if (!function_exists('mb_encode_numericentity')) { + function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); } +} +if (!function_exists('mb_convert_case')) { + function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); } +} +if (!function_exists('mb_internal_encoding')) { + function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); } +} +if (!function_exists('mb_language')) { + function mb_language($language = null) { return p\Mbstring::mb_language($language); } +} +if (!function_exists('mb_list_encodings')) { + function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); } +} +if (!function_exists('mb_encoding_aliases')) { + function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); } +} +if (!function_exists('mb_check_encoding')) { + function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); } +} +if (!function_exists('mb_detect_encoding')) { + function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); } +} +if (!function_exists('mb_detect_order')) { + function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); } +} +if (!function_exists('mb_parse_str')) { + function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; } +} +if (!function_exists('mb_strlen')) { + function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); } +} +if (!function_exists('mb_strpos')) { + function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_strtolower')) { + function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); } +} +if (!function_exists('mb_strtoupper')) { + function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); } +} +if (!function_exists('mb_substitute_character')) { + function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); } +} +if (!function_exists('mb_substr')) { + function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); } +} +if (!function_exists('mb_stripos')) { + function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_stristr')) { + function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_strrchr')) { + function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_strrichr')) { + function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_strripos')) { + function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_strrpos')) { + function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_strstr')) { + function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_get_info')) { + function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); } +} +if (!function_exists('mb_http_output')) { + function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); } +} +if (!function_exists('mb_strwidth')) { + function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); } +} +if (!function_exists('mb_substr_count')) { + function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); } +} +if (!function_exists('mb_output_handler')) { + function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); } +} +if (!function_exists('mb_http_input')) { + function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); } +} + +if (!function_exists('mb_convert_variables')) { + function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); } +} + +if (!function_exists('mb_ord')) { + function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); } +} +if (!function_exists('mb_chr')) { + function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); } +} +if (!function_exists('mb_scrub')) { + function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); } +} +if (!function_exists('mb_str_split')) { + function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); } +} + +if (!function_exists('mb_str_pad')) { + function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } +} + +if (!function_exists('mb_ucfirst')) { + function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } +} + +if (!function_exists('mb_lcfirst')) { + function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } +} + +if (!function_exists('mb_trim')) { + function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); } +} + +if (!function_exists('mb_ltrim')) { + function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); } +} + +if (!function_exists('mb_rtrim')) { + function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); } +} + + +if (extension_loaded('mbstring')) { + return; +} + +if (!defined('MB_CASE_UPPER')) { + define('MB_CASE_UPPER', 0); +} +if (!defined('MB_CASE_LOWER')) { + define('MB_CASE_LOWER', 1); +} +if (!defined('MB_CASE_TITLE')) { + define('MB_CASE_TITLE', 2); +} diff --git a/tools/mailer/symfony/polyfill-mbstring/bootstrap80.php b/tools/mailer/symfony/polyfill-mbstring/bootstrap80.php new file mode 100644 index 000000000..5be7d2018 --- /dev/null +++ b/tools/mailer/symfony/polyfill-mbstring/bootstrap80.php @@ -0,0 +1,167 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Mbstring as p; + +if (!function_exists('mb_convert_encoding')) { + function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); } +} +if (!function_exists('mb_decode_mimeheader')) { + function mb_decode_mimeheader(?string $string): string { return p\Mbstring::mb_decode_mimeheader((string) $string); } +} +if (!function_exists('mb_encode_mimeheader')) { + function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0): string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); } +} +if (!function_exists('mb_decode_numericentity')) { + function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); } +} +if (!function_exists('mb_encode_numericentity')) { + function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); } +} +if (!function_exists('mb_convert_case')) { + function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); } +} +if (!function_exists('mb_internal_encoding')) { + function mb_internal_encoding(?string $encoding = null): string|bool { return p\Mbstring::mb_internal_encoding($encoding); } +} +if (!function_exists('mb_language')) { + function mb_language(?string $language = null): string|bool { return p\Mbstring::mb_language($language); } +} +if (!function_exists('mb_list_encodings')) { + function mb_list_encodings(): array { return p\Mbstring::mb_list_encodings(); } +} +if (!function_exists('mb_encoding_aliases')) { + function mb_encoding_aliases(?string $encoding): array { return p\Mbstring::mb_encoding_aliases((string) $encoding); } +} +if (!function_exists('mb_check_encoding')) { + function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\Mbstring::mb_check_encoding($value, $encoding); } +} +if (!function_exists('mb_detect_encoding')) { + function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); } +} +if (!function_exists('mb_detect_order')) { + function mb_detect_order(array|string|null $encoding = null): array|bool { return p\Mbstring::mb_detect_order($encoding); } +} +if (!function_exists('mb_parse_str')) { + function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; } +} +if (!function_exists('mb_strlen')) { + function mb_strlen(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strlen((string) $string, $encoding); } +} +if (!function_exists('mb_strpos')) { + function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_strtolower')) { + function mb_strtolower(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtolower((string) $string, $encoding); } +} +if (!function_exists('mb_strtoupper')) { + function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); } +} +if (!function_exists('mb_substitute_character')) { + function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); } +} +if (!function_exists('mb_substr')) { + function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); } +} +if (!function_exists('mb_stripos')) { + function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_stristr')) { + function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_strrchr')) { + function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_strrichr')) { + function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_strripos')) { + function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_strrpos')) { + function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_strstr')) { + function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_get_info')) { + function mb_get_info(?string $type = 'all'): array|string|int|false|null { return p\Mbstring::mb_get_info((string) $type); } +} +if (!function_exists('mb_http_output')) { + function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); } +} +if (!function_exists('mb_strwidth')) { + function mb_strwidth(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strwidth((string) $string, $encoding); } +} +if (!function_exists('mb_substr_count')) { + function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); } +} +if (!function_exists('mb_output_handler')) { + function mb_output_handler(?string $string, ?int $status): string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); } +} +if (!function_exists('mb_http_input')) { + function mb_http_input(?string $type = null): array|string|false { return p\Mbstring::mb_http_input($type); } +} + +if (!function_exists('mb_convert_variables')) { + function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); } +} + +if (!function_exists('mb_ord')) { + function mb_ord(?string $string, ?string $encoding = null): int|false { return p\Mbstring::mb_ord((string) $string, $encoding); } +} +if (!function_exists('mb_chr')) { + function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); } +} +if (!function_exists('mb_scrub')) { + function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); } +} +if (!function_exists('mb_str_split')) { + function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); } +} + +if (!function_exists('mb_str_pad')) { + function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } +} + +if (!function_exists('mb_ucfirst')) { + function mb_ucfirst($string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } +} + +if (!function_exists('mb_lcfirst')) { + function mb_lcfirst($string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } +} + +if (!function_exists('mb_trim')) { + function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); } +} + +if (!function_exists('mb_ltrim')) { + function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); } +} + +if (!function_exists('mb_rtrim')) { + function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); } +} + +if (extension_loaded('mbstring')) { + return; +} + +if (!defined('MB_CASE_UPPER')) { + define('MB_CASE_UPPER', 0); +} +if (!defined('MB_CASE_LOWER')) { + define('MB_CASE_LOWER', 1); +} +if (!defined('MB_CASE_TITLE')) { + define('MB_CASE_TITLE', 2); +} diff --git a/tools/mailer/symfony/polyfill-mbstring/composer.json b/tools/mailer/symfony/polyfill-mbstring/composer.json new file mode 100644 index 000000000..4ed241a33 --- /dev/null +++ b/tools/mailer/symfony/polyfill-mbstring/composer.json @@ -0,0 +1,38 @@ +{ + "name": "symfony/polyfill-mbstring", + "type": "library", + "description": "Symfony polyfill for the Mbstring extension", + "keywords": ["polyfill", "shim", "compatibility", "portable", "mbstring"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Mbstring\\": "" }, + "files": [ "bootstrap.php" ] + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/tools/mailer/symfony/service-contracts/Attribute/Required.php b/tools/mailer/symfony/service-contracts/Attribute/Required.php new file mode 100644 index 000000000..9df851189 --- /dev/null +++ b/tools/mailer/symfony/service-contracts/Attribute/Required.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Attribute; + +/** + * A required dependency. + * + * This attribute indicates that a property holds a required dependency. The annotated property or method should be + * considered during the instantiation process of the containing class. + * + * @author Alexander M. Turek + */ +#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] +final class Required +{ +} diff --git a/tools/mailer/symfony/service-contracts/Attribute/SubscribedService.php b/tools/mailer/symfony/service-contracts/Attribute/SubscribedService.php new file mode 100644 index 000000000..f850b8401 --- /dev/null +++ b/tools/mailer/symfony/service-contracts/Attribute/SubscribedService.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Attribute; + +use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait; +use Symfony\Contracts\Service\ServiceSubscriberInterface; + +/** + * For use as the return value for {@see ServiceSubscriberInterface}. + * + * @example new SubscribedService('http_client', HttpClientInterface::class, false, new Target('githubApi')) + * + * Use with {@see ServiceMethodsSubscriberTrait} to mark a method's return type + * as a subscribed service. + * + * @author Kevin Bond + */ +#[\Attribute(\Attribute::TARGET_METHOD)] +final class SubscribedService +{ + /** @var object[] */ + public array $attributes; + + /** + * @param string|null $key The key to use for the service + * @param class-string|null $type The service class + * @param bool $nullable Whether the service is optional + * @param object|object[] $attributes One or more dependency injection attributes to use + */ + public function __construct( + public ?string $key = null, + public ?string $type = null, + public bool $nullable = false, + array|object $attributes = [], + ) { + $this->attributes = \is_array($attributes) ? $attributes : [$attributes]; + } +} diff --git a/tools/mailer/symfony/service-contracts/CHANGELOG.md b/tools/mailer/symfony/service-contracts/CHANGELOG.md new file mode 100644 index 000000000..7932e2613 --- /dev/null +++ b/tools/mailer/symfony/service-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/tools/mailer/symfony/service-contracts/LICENSE b/tools/mailer/symfony/service-contracts/LICENSE new file mode 100644 index 000000000..7536caeae --- /dev/null +++ b/tools/mailer/symfony/service-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-present Fabien Potencier + +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/tools/mailer/symfony/service-contracts/README.md b/tools/mailer/symfony/service-contracts/README.md new file mode 100644 index 000000000..42841a57d --- /dev/null +++ b/tools/mailer/symfony/service-contracts/README.md @@ -0,0 +1,9 @@ +Symfony Service Contracts +========================= + +A set of abstractions extracted out of the Symfony components. + +Can be used to build on semantics that the Symfony components proved useful and +that already have battle tested implementations. + +See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/tools/mailer/symfony/service-contracts/ResetInterface.php b/tools/mailer/symfony/service-contracts/ResetInterface.php new file mode 100644 index 000000000..a4f389b01 --- /dev/null +++ b/tools/mailer/symfony/service-contracts/ResetInterface.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +/** + * Provides a way to reset an object to its initial state. + * + * When calling the "reset()" method on an object, it should be put back to its + * initial state. This usually means clearing any internal buffers and forwarding + * the call to internal dependencies. All properties of the object should be put + * back to the same state it had when it was first ready to use. + * + * This method could be called, for example, to recycle objects that are used as + * services, so that they can be used to handle several requests in the same + * process loop (note that we advise making your services stateless instead of + * implementing this interface when possible.) + */ +interface ResetInterface +{ + /** + * @return void + */ + public function reset(); +} diff --git a/tools/mailer/symfony/service-contracts/ServiceCollectionInterface.php b/tools/mailer/symfony/service-contracts/ServiceCollectionInterface.php new file mode 100644 index 000000000..2333139ce --- /dev/null +++ b/tools/mailer/symfony/service-contracts/ServiceCollectionInterface.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +/** + * A ServiceProviderInterface that is also countable and iterable. + * + * @author Kevin Bond + * + * @template-covariant T of mixed + * + * @extends ServiceProviderInterface + * @extends \IteratorAggregate + */ +interface ServiceCollectionInterface extends ServiceProviderInterface, \Countable, \IteratorAggregate +{ +} diff --git a/tools/mailer/symfony/service-contracts/ServiceLocatorTrait.php b/tools/mailer/symfony/service-contracts/ServiceLocatorTrait.php new file mode 100644 index 000000000..b62ec3e53 --- /dev/null +++ b/tools/mailer/symfony/service-contracts/ServiceLocatorTrait.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; + +// Help opcache.preload discover always-needed symbols +class_exists(ContainerExceptionInterface::class); +class_exists(NotFoundExceptionInterface::class); + +/** + * A trait to help implement ServiceProviderInterface. + * + * @author Robin Chalas + * @author Nicolas Grekas + */ +trait ServiceLocatorTrait +{ + private array $factories; + private array $loading = []; + private array $providedTypes; + + /** + * @param array $factories + */ + public function __construct(array $factories) + { + $this->factories = $factories; + } + + public function has(string $id): bool + { + return isset($this->factories[$id]); + } + + public function get(string $id): mixed + { + if (!isset($this->factories[$id])) { + throw $this->createNotFoundException($id); + } + + if (isset($this->loading[$id])) { + $ids = array_values($this->loading); + $ids = \array_slice($this->loading, array_search($id, $ids)); + $ids[] = $id; + + throw $this->createCircularReferenceException($id, $ids); + } + + $this->loading[$id] = $id; + try { + return $this->factories[$id]($this); + } finally { + unset($this->loading[$id]); + } + } + + public function getProvidedServices(): array + { + if (!isset($this->providedTypes)) { + $this->providedTypes = []; + + foreach ($this->factories as $name => $factory) { + if (!\is_callable($factory)) { + $this->providedTypes[$name] = '?'; + } else { + $type = (new \ReflectionFunction($factory))->getReturnType(); + + $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?'; + } + } + } + + return $this->providedTypes; + } + + private function createNotFoundException(string $id): NotFoundExceptionInterface + { + if (!$alternatives = array_keys($this->factories)) { + $message = 'is empty...'; + } else { + $last = array_pop($alternatives); + if ($alternatives) { + $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); + } else { + $message = sprintf('only knows about the "%s" service.', $last); + } + } + + if ($this->loading) { + $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); + } else { + $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); + } + + return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { + }; + } + + private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface + { + return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { + }; + } +} diff --git a/tools/mailer/symfony/service-contracts/ServiceMethodsSubscriberTrait.php b/tools/mailer/symfony/service-contracts/ServiceMethodsSubscriberTrait.php new file mode 100644 index 000000000..0d89d9f25 --- /dev/null +++ b/tools/mailer/symfony/service-contracts/ServiceMethodsSubscriberTrait.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\Attribute\Required; +use Symfony\Contracts\Service\Attribute\SubscribedService; + +/** + * Implementation of ServiceSubscriberInterface that determines subscribed services + * from methods that have the #[SubscribedService] attribute. + * + * Service ids are available as "ClassName::methodName" so that the implementation + * of subscriber methods can be just `return $this->container->get(__METHOD__);`. + * + * @author Kevin Bond + */ +trait ServiceMethodsSubscriberTrait +{ + protected ContainerInterface $container; + + public static function getSubscribedServices(): array + { + $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; + + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if (self::class !== $method->getDeclaringClass()->name) { + continue; + } + + if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) { + continue; + } + + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + } + + if (!$returnType = $method->getReturnType()) { + throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + } + + /* @var SubscribedService $attribute */ + $attribute = $attribute->newInstance(); + $attribute->key ??= self::class.'::'.$method->name; + $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; + $attribute->nullable = $returnType->allowsNull(); + + if ($attribute->attributes) { + $services[] = $attribute; + } else { + $services[$attribute->key] = ($attribute->nullable ? '?' : '').$attribute->type; + } + } + + return $services; + } + + #[Required] + public function setContainer(ContainerInterface $container): ?ContainerInterface + { + $ret = null; + if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) { + $ret = parent::setContainer($container); + } + + $this->container = $container; + + return $ret; + } +} diff --git a/tools/mailer/symfony/service-contracts/ServiceProviderInterface.php b/tools/mailer/symfony/service-contracts/ServiceProviderInterface.php new file mode 100644 index 000000000..2e71f00c6 --- /dev/null +++ b/tools/mailer/symfony/service-contracts/ServiceProviderInterface.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerInterface; + +/** + * A ServiceProviderInterface exposes the identifiers and the types of services provided by a container. + * + * @author Nicolas Grekas + * @author Mateusz Sip + * + * @template-covariant T of mixed + */ +interface ServiceProviderInterface extends ContainerInterface +{ + /** + * @return T + */ + public function get(string $id): mixed; + + public function has(string $id): bool; + + /** + * Returns an associative array of service types keyed by the identifiers provided by the current container. + * + * Examples: + * + * * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface + * * ['foo' => '?'] means the container provides service name "foo" of unspecified type + * * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null + * + * @return array The provided service types, keyed by service names + */ + public function getProvidedServices(): array; +} diff --git a/tools/mailer/symfony/service-contracts/ServiceSubscriberInterface.php b/tools/mailer/symfony/service-contracts/ServiceSubscriberInterface.php new file mode 100644 index 000000000..3da19169b --- /dev/null +++ b/tools/mailer/symfony/service-contracts/ServiceSubscriberInterface.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Symfony\Contracts\Service\Attribute\SubscribedService; + +/** + * A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method. + * + * The getSubscribedServices method returns an array of service types required by such instances, + * optionally keyed by the service names used internally. Service types that start with an interrogation + * mark "?" are optional, while the other ones are mandatory service dependencies. + * + * The injected service locators SHOULD NOT allow access to any other services not specified by the method. + * + * It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally. + * This interface does not dictate any injection method for these service locators, although constructor + * injection is recommended. + * + * @author Nicolas Grekas + */ +interface ServiceSubscriberInterface +{ + /** + * Returns an array of service types (or {@see SubscribedService} objects) required + * by such instances, optionally keyed by the service names used internally. + * + * For mandatory dependencies: + * + * * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name + * internally to fetch a service which must implement Psr\Log\LoggerInterface. + * * ['loggers' => 'Psr\Log\LoggerInterface[]'] means the objects use the "loggers" name + * internally to fetch an iterable of Psr\Log\LoggerInterface instances. + * * ['Psr\Log\LoggerInterface'] is a shortcut for + * * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface'] + * + * otherwise: + * + * * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency + * * ['loggers' => '?Psr\Log\LoggerInterface[]'] denotes an optional iterable dependency + * * ['?Psr\Log\LoggerInterface'] is a shortcut for + * * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface'] + * + * additionally, an array of {@see SubscribedService}'s can be returned: + * + * * [new SubscribedService('logger', Psr\Log\LoggerInterface::class)] + * * [new SubscribedService(type: Psr\Log\LoggerInterface::class, nullable: true)] + * * [new SubscribedService('http_client', HttpClientInterface::class, attributes: new Target('githubApi'))] + * + * @return string[]|SubscribedService[] The required service types, optionally keyed by service names + */ + public static function getSubscribedServices(): array; +} diff --git a/tools/mailer/symfony/service-contracts/ServiceSubscriberTrait.php b/tools/mailer/symfony/service-contracts/ServiceSubscriberTrait.php new file mode 100644 index 000000000..cc3bc321a --- /dev/null +++ b/tools/mailer/symfony/service-contracts/ServiceSubscriberTrait.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\Attribute\Required; +use Symfony\Contracts\Service\Attribute\SubscribedService; + +trigger_deprecation('symfony/contracts', 'v3.5', '"%s" is deprecated, use "ServiceMethodsSubscriberTrait" instead.', ServiceSubscriberTrait::class); + +/** + * Implementation of ServiceSubscriberInterface that determines subscribed services + * from methods that have the #[SubscribedService] attribute. + * + * Service ids are available as "ClassName::methodName" so that the implementation + * of subscriber methods can be just `return $this->container->get(__METHOD__);`. + * + * @property ContainerInterface $container + * + * @author Kevin Bond + * + * @deprecated since symfony/contracts v3.5, use ServiceMethodsSubscriberTrait instead + */ +trait ServiceSubscriberTrait +{ + public static function getSubscribedServices(): array + { + $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; + + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if (self::class !== $method->getDeclaringClass()->name) { + continue; + } + + if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) { + continue; + } + + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + } + + if (!$returnType = $method->getReturnType()) { + throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + } + + /* @var SubscribedService $attribute */ + $attribute = $attribute->newInstance(); + $attribute->key ??= self::class.'::'.$method->name; + $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; + $attribute->nullable = $returnType->allowsNull(); + + if ($attribute->attributes) { + $services[] = $attribute; + } else { + $services[$attribute->key] = ($attribute->nullable ? '?' : '').$attribute->type; + } + } + + return $services; + } + + #[Required] + public function setContainer(ContainerInterface $container): ?ContainerInterface + { + $ret = null; + if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) { + $ret = parent::setContainer($container); + } + + $this->container = $container; + + return $ret; + } +} diff --git a/tools/mailer/symfony/service-contracts/Test/ServiceLocatorTest.php b/tools/mailer/symfony/service-contracts/Test/ServiceLocatorTest.php new file mode 100644 index 000000000..07d12b4a5 --- /dev/null +++ b/tools/mailer/symfony/service-contracts/Test/ServiceLocatorTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Test; + +class_alias(ServiceLocatorTestCase::class, ServiceLocatorTest::class); + +if (false) { + /** + * @deprecated since PHPUnit 9.6 + */ + class ServiceLocatorTest + { + } +} diff --git a/tools/mailer/symfony/service-contracts/Test/ServiceLocatorTestCase.php b/tools/mailer/symfony/service-contracts/Test/ServiceLocatorTestCase.php new file mode 100644 index 000000000..65a3fe337 --- /dev/null +++ b/tools/mailer/symfony/service-contracts/Test/ServiceLocatorTestCase.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Test; + +use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\ContainerInterface; +use Psr\Container\NotFoundExceptionInterface; +use Symfony\Contracts\Service\ServiceLocatorTrait; + +abstract class ServiceLocatorTestCase extends TestCase +{ + protected function getServiceLocator(array $factories): ContainerInterface + { + return new class($factories) implements ContainerInterface { + use ServiceLocatorTrait; + }; + } + + public function testHas() + { + $locator = $this->getServiceLocator([ + 'foo' => fn () => 'bar', + 'bar' => fn () => 'baz', + fn () => 'dummy', + ]); + + $this->assertTrue($locator->has('foo')); + $this->assertTrue($locator->has('bar')); + $this->assertFalse($locator->has('dummy')); + } + + public function testGet() + { + $locator = $this->getServiceLocator([ + 'foo' => fn () => 'bar', + 'bar' => fn () => 'baz', + ]); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('baz', $locator->get('bar')); + } + + public function testGetDoesNotMemoize() + { + $i = 0; + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$i) { + ++$i; + + return 'bar'; + }, + ]); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame(2, $i); + } + + public function testThrowsOnUndefinedInternalService() + { + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, + ]); + + if (!$this->getExpectedException()) { + $this->expectException(NotFoundExceptionInterface::class); + $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); + } + + $locator->get('foo'); + } + + public function testThrowsOnCircularReference() + { + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, + 'bar' => function () use (&$locator) { return $locator->get('baz'); }, + 'baz' => function () use (&$locator) { return $locator->get('bar'); }, + ]); + + $this->expectException(ContainerExceptionInterface::class); + $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); + + $locator->get('foo'); + } +} diff --git a/tools/mailer/symfony/service-contracts/composer.json b/tools/mailer/symfony/service-contracts/composer.json new file mode 100644 index 000000000..fc8674a72 --- /dev/null +++ b/tools/mailer/symfony/service-contracts/composer.json @@ -0,0 +1,42 @@ +{ + "name": "symfony/service-contracts", + "type": "library", + "description": "Generic abstractions related to writing services", + "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "autoload": { + "psr-4": { "Symfony\\Contracts\\Service\\": "" }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/tools/minify_html/LICENSE b/tools/minify_html/LICENSE new file mode 100644 index 000000000..8f008adb5 --- /dev/null +++ b/tools/minify_html/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2008 Ryan Grove +Copyright (c) 2008 Steve Clay +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. + * Neither the name of this project nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +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/tools/minify_html/minify_html.class.php b/tools/minify_html/minify_html.class.php index dfd668bf9..b475d27b6 100644 --- a/tools/minify_html/minify_html.class.php +++ b/tools/minify_html/minify_html.class.php @@ -16,12 +16,22 @@ * @package Minify * @author Stephen Clay */ -class Minify_HTML { + +/* QloApps + * added a limit for all preg_replace_callback +*/ +class Minify_HTML +{ /** * @var boolean */ protected $_jsCleanComments = true; + /** + * @var string + */ + protected $_html; + /** * "Minify" an HTML page * @@ -40,17 +50,13 @@ class Minify_HTML { * * @return string */ - - /* PrestaShop - * added a limit for all preg_replace_callback - */ - - public static function minify($html, $options = array()) { + public static function minify($html, $options = array()) + { $min = new self($html, $options); + return $min->process(); } - /** * Create a minifier object * @@ -68,8 +74,6 @@ class Minify_HTML { * * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If * unset, minify will sniff for an XHTML doctype. - * - * @return null */ public function __construct($html, $options = array()) { @@ -88,7 +92,6 @@ class Minify_HTML { } } - /** * Minify the markeup given in the constructor * @@ -105,56 +108,85 @@ class Minify_HTML { // replace SCRIPTs (and minify) with placeholders $this->_html = preg_replace_callback( - '/(\\s*)]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i', array($this, '_removeScriptCB'), $this->_html, Media::getBackTrackLimit()); + '/(\\s*)]*?>)([\\s\\S]*?)<\\/script>(\\s*)/iu', + array($this, '_removeScriptCB'), + is_null($this->_html) ? '' : $this->_html, + Media::getBackTrackLimit() + ); // replace STYLEs (and minify) with placeholders $this->_html = preg_replace_callback( - '/\\s*]*>)([\\s\\S]*?)<\\/style>\\s*/i', array($this, '_removeStyleCB'), $this->_html, Media::getBackTrackLimit()); + '/\\s*]*>)([\\s\\S]*?)<\\/style>\\s*/iu', + array($this, '_removeStyleCB'), + is_null($this->_html) ? '' : $this->_html, + Media::getBackTrackLimit() + ); // remove HTML comments (not containing IE conditional comments). $this->_html = preg_replace_callback( - '//', array($this, '_commentCB'), $this->_html, Media::getBackTrackLimit()); + '//u', + array($this, '_commentCB'), + is_null($this->_html) ? '' : $this->_html, + Media::getBackTrackLimit() + ); // replace PREs with placeholders - $this->_html = preg_replace_callback('/\\s*]*?>[\\s\\S]*?<\\/pre>)\\s*/i', array($this, '_removePreCB'), $this->_html, Media::getBackTrackLimit()); + $this->_html = preg_replace_callback( + '/\\s*]*?>[\\s\\S]*?<\\/pre>)\\s*/iu', + array($this, '_removePreCB'), + is_null($this->_html) ? '' : $this->_html, + Media::getBackTrackLimit() + ); // replace TEXTAREAs with placeholders $this->_html = preg_replace_callback( - '/\\s*]*?>[\\s\\S]*?<\\/textarea>)\\s*/i', array($this, '_removeTextareaCB'), $this->_html, Media::getBackTrackLimit()); + '/\\s*]*?>[\\s\\S]*?<\\/textarea>)\\s*/iu', + array($this, '_removeTextareaCB'), + is_null($this->_html) ? '' : $this->_html, + Media::getBackTrackLimit() + ); // trim each line. // @todo take into account attribute values that span multiple lines. $this->_html = preg_replace(Tools::cleanNonUnicodeSupport('/^\\s+|\\s+$/mu'), '', $this->_html); // remove ws around block/undisplayed elements - $this->_html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body' - .'|caption|center|cite|col(?:group)?|dd|dir|div|dl|dt|fieldset|form' - .'|frame(?:set)?|h[1-6]|head|hr|html|legend|li|link|map|menu|meta' - .'|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h||r|foot|itle)' - .'|ul)\\b[^>]*>)/i', '$1', $this->_html); + $this->_html = preg_replace('/\\s+(<\\/?(?:area|article|aside|base(?:font)?|blockquote|body' + .'|canvas|caption|center|col(?:group)?|dd|dir|div|dl|dt|fieldset|figcaption|figure|footer|form' + .'|frame(?:set)?|h[1-6]|head|header|hgroup|hr|html|legend|li|link|main|map|menu|meta|nav' + .'|ol|opt(?:group|ion)|output|p|param|section|t(?:able|body|head|d|h||r|foot|itle)' + .'|ul|video)\\b[^>]*>)/iu', '$1', $this->_html); // remove ws outside of all elements $this->_html = preg_replace( - '/>(\\s(?:\\s*))?([^<]+)(\\s(?:\s*))?$1$2$3<', $this->_html); + '/>(\\s(?:\\s*))?([^<]+)(\\s(?:\s*))?$1$2$3<', + $this->_html + ); // use newlines before 1st attribute in open tags (to limit line lengths) - // $this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $this->_html); - $this->_html = preg_replace(Tools::cleanNonUnicodeSupport('/\s+/mu'), ' ', $this->_html); + // $this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/iu', "$1\n$2", $this->_html); + $this->_html = preg_replace(Tools::cleanNonUnicodeSupport('/\s+/mu'), ' ', $this->_html); // fill placeholders $this->_html = str_replace( - array_keys($this->_placeholders), array_values($this->_placeholders), $this->_html + array_keys($this->_placeholders), + array_values($this->_placeholders), + $this->_html ); // issue 229: multi-pass to catch scripts that didn't get replaced in textareas $this->_html = str_replace( - array_keys($this->_placeholders), array_values($this->_placeholders), $this->_html + array_keys($this->_placeholders), + array_values($this->_placeholders), + $this->_html ); + return $this->_html; } protected function _commentCB($m) { - return (0 === strpos($m[1], '[') || false !== strpos($m[1], '_replacementHash . count($this->_placeholders) . '%'; $this->_placeholders[$placeholder] = $content; + return $placeholder; } - protected $_isXhtml = null; - protected $_replacementHash = null; + protected $_isXhtml; + protected $_replacementHash; protected $_placeholders = array(); - protected $_cssMinifier = null; - protected $_jsMinifier = null; + protected $_cssMinifier; + protected $_jsMinifier; protected function _removePreCB($m) { @@ -187,7 +220,7 @@ class Minify_HTML { $openStyle = "\\s*$)/', '', $css); + $css = preg_replace('/(?:^\\s*\\s*$)/u', '', $css); // remove CDATA section markers $css = $this->_removeCdata($css); @@ -198,7 +231,8 @@ class Minify_HTML { : 'trim'; $css = call_user_func($minifier, $css); - return $this->_reservePlace($this->_needsCdata($css) + return $this->_reservePlace( + $this->_needsCdata($css) ? "{$openStyle}/**/" : "{$openStyle}{$css}" ); @@ -215,7 +249,7 @@ class Minify_HTML { // remove HTML comments (and ending "//" if present) if ($this->_jsCleanComments) { - $js = preg_replace('/(?:^\\s*\\s*$)/', '', $js); + $js = preg_replace('/(?:^\\s*\\s*$)/u', '', $js); } // remove CDATA section markers @@ -227,7 +261,8 @@ class Minify_HTML { : 'trim'; $js = call_user_func($minifier, $js); - return $this->_reservePlace($this->_needsCdata($js) + return $this->_reservePlace( + $this->_needsCdata($js) ? "{$ws1}{$openScript}/**/{$ws2}" : "{$ws1}{$openScript}{$js}{$ws2}" ); @@ -242,6 +277,6 @@ class Minify_HTML { protected function _needsCdata($str) { - return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str)); + return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/u', $str)); } } diff --git a/tools/mobile_Detect/LICENSE b/tools/mobile_Detect/LICENSE deleted file mode 100644 index 90e632a78..000000000 --- a/tools/mobile_Detect/LICENSE +++ /dev/null @@ -1,48 +0,0 @@ -MIT License - -Copyright (c) <2011-2015> Serban Ghita, Nick Ilyin and contributors. - -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. - -Developer’s Certificate of Origin 1.1 - -By making a contribution to this project, I certify that: - -(a) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - -(b) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - -(c) The contribution was provided directly to me by some other - person who certified (a), (b) or (c) and I have not modified - it. - -(d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. diff --git a/tools/mobile_Detect/Mobile_Detect.php b/tools/mobile_Detect/Mobile_Detect.php deleted file mode 100644 index 4f6982913..000000000 --- a/tools/mobile_Detect/Mobile_Detect.php +++ /dev/null @@ -1,1290 +0,0 @@ -, Nick Ilyin - * Original author: Victor Stanciu - * - * @license Code and contributions have 'MIT License' - * More details: https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt - * - * @link Homepage: http://mobiledetect.net - * GitHub Repo: https://github.com/serbanghita/Mobile-Detect - * Google Code: http://code.google.com/p/php-mobile-detect/ - * README: https://github.com/serbanghita/Mobile-Detect/blob/master/README.md - * HOWTO: https://github.com/serbanghita/Mobile-Detect/wiki/Code-examples - * - * @version 2.8.5 - */ - -class Mobile_Detect -{ - /** - * Mobile detection type. - * - * @deprecated since version 2.6.9 - */ - const DETECTION_TYPE_MOBILE = 'mobile'; - - /** - * Extended detection type. - * - * @deprecated since version 2.6.9 - */ - const DETECTION_TYPE_EXTENDED = 'extended'; - - /** - * A frequently used regular expression to extract version #s. - * - * @deprecated since version 2.6.9 - */ - const VER = '([\w._\+]+)'; - - /** - * Top-level device. - */ - const MOBILE_GRADE_A = 'A'; - - /** - * Mid-level device. - */ - const MOBILE_GRADE_B = 'B'; - - /** - * Low-level device. - */ - const MOBILE_GRADE_C = 'C'; - - /** - * Stores the version number of the current release. - */ - const VERSION = '2.8.5'; - - /** - * A type for the version() method indicating a string return value. - */ - const VERSION_TYPE_STRING = 'text'; - - /** - * A type for the version() method indicating a float return value. - */ - const VERSION_TYPE_FLOAT = 'float'; - - /** - * The User-Agent HTTP header is stored in here. - * @var string - */ - protected $userAgent = null; - - /** - * HTTP headers in the PHP-flavor. So HTTP_USER_AGENT and SERVER_SOFTWARE. - * @var array - */ - protected $httpHeaders = array(); - - /** - * The detection type, using self::DETECTION_TYPE_MOBILE or self::DETECTION_TYPE_EXTENDED. - * - * @deprecated since version 2.6.9 - * - * @var string - */ - protected $detectionType = self::DETECTION_TYPE_MOBILE; - - /** - * HTTP headers that trigger the 'isMobile' detection - * to be true. - * - * @var array - */ - protected static $mobileHeaders = array( - - 'HTTP_ACCEPT' => array('matches' => array( - // Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/ - 'application/x-obml2d', - // BlackBerry devices. - 'application/vnd.rim.html', - 'text/vnd.wap.wml', - 'application/vnd.wap.xhtml+xml' - )), - 'HTTP_X_WAP_PROFILE' => null, - 'HTTP_X_WAP_CLIENTID' => null, - 'HTTP_WAP_CONNECTION' => null, - 'HTTP_PROFILE' => null, - // Reported by Opera on Nokia devices (eg. C3). - 'HTTP_X_OPERAMINI_PHONE_UA' => null, - 'HTTP_X_NOKIA_GATEWAY_ID' => null, - 'HTTP_X_ORANGE_ID' => null, - 'HTTP_X_VODAFONE_3GPDPCONTEXT' => null, - 'HTTP_X_HUAWEI_USERID' => null, - // Reported by Windows Smartphones. - 'HTTP_UA_OS' => null, - // Reported by Verizon, Vodafone proxy system. - 'HTTP_X_MOBILE_GATEWAY' => null, - // Seen this on HTC Sensation. SensationXE_Beats_Z715e. - 'HTTP_X_ATT_DEVICEID' => null, - // Seen this on a HTC. - 'HTTP_UA_CPU' => array('matches' => array('ARM')), - ); - - /** - * List of mobile devices (phones). - * - * @var array - */ - protected static $phoneDevices = array( - 'iPhone' => '\biPhone\b|\biPod\b', // |\biTunes - 'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+', - 'HTC' => 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b|T-Mobile G1|Z520m', - 'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6', - // @todo: Is 'Dell Streak' a tablet or a phone? ;) - 'Dell' => 'Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b', - 'Motorola' => 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925', - 'Samsung' => 'Samsung|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750', - 'LG' => '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802)', - 'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C6902|C6903|C6906|C6943|D2533', - 'Asus' => 'Asus.*Galaxy|PadFone.*Mobile', - // http://www.micromaxinfo.com/mobiles/smartphones - // Added because the codes might conflict with Acer Tablets. - 'Micromax' => 'Micromax.*\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\b', - // @todo Complete the regex. - 'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ; - 'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun ;) - // http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH) - // Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android. - 'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790', - // http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones. - 'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250', - 'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)', - // Added simvalley mobile just for fun. They have some interesting devices. - // http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html - 'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b', - // Wolfgang - a brand that is sold by Aldi supermarkets. - // http://www.wolfgangmobile.com/ - 'Wolfgang' => 'AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q', - 'Alcatel' => 'Alcatel', - 'Nintendo' => 'Nintendo 3DS', - // http://en.wikipedia.org/wiki/Amoi - 'Amoi' => 'Amoi', - // http://en.wikipedia.org/wiki/INQ - 'INQ' => 'INQ', - // @Tapatalk is a mobile app; http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039 - 'GenericPhone' => 'Tapatalk|PDA;|SAGEM|\bmmp\b|pocket|\bpsp\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\bwap\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser', - ); - - /** - * List of tablet devices. - * - * @var array - */ - protected static $tabletDevices = array( - 'iPad' => 'iPad|iPad.*Mobile', // @todo: check for mobile friendly emails topic. - 'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)|^.*Android.*Nexus(?:(?!Mobile).)*$', - 'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-I9205|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700', // SCH-P709|SCH-P729|SM-T2558 - Samsung Mega - treat them like a regular phone. - // http://www.labnol.org/software/kindle-user-agent-string/20378/ - 'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE)\b', - // Only the Surface tablets with Windows RT are considered mobile. - // http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx - 'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)', - // http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT - 'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10', - // Watch out for PadFone, see #132. - // http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/ - 'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG', - 'BlackBerryTablet' => 'PlayBook|RIM Tablet', - 'HTCtablet' => 'HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410', - 'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617', - 'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2', - // http://www.acer.ro/ac/ro/RO/content/drivers - // http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer) - // http://us.acer.com/ac/en/US/content/group/tablets - // Can conflict with Micromax and Motorola phones codes. - 'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b|W3-810|\bA3-A10\b', - // http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/ - // http://us.toshiba.com/tablets/tablet-finder - // http://www.toshiba.co.jp/regza/tablet/ - 'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO', - // http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html - // http://www.lg.com/us/tablets - 'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b', - 'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b', - // Prestigio Tablets http://www.prestigio.com/support - 'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD', - // http://support.lenovo.com/en_GB/downloads/default.page?# - 'LenovoTablet' => 'Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)', - // http://www.dell.com/support/home/us/en/04/Products/tab_mob/tablets - 'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7', - // http://www.yarvik.com/en/matrix/tablets/ - 'YarvikTablet' => 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b', - 'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB', - 'ArnovaTablet' => 'AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT', - // http://www.intenso.de/kategorie_en.php?kategorie=33 - // @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate - 'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004', - // IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/ - 'IRUTablet' => 'M702pro', - 'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b', - // http://www.e-boda.ro/tablete-pc.html - 'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)', - // http://www.allview.ro/produse/droseries/lista-tablete-pc/ - 'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)', - // http://wiki.archosfans.com/index.php?title=Main_Page - 'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b', - // http://www.ainol.com/plugin.php?identifier=ainol&module=product - 'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark', - // @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER - // Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser - // http://www.sony.jp/support/tablet/ - 'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551', - // http://www.support.philips.com/support/catalog/worldproducts.jsp?userLanguage=en&userCountry=cn&categoryid=3G_LTE_TABLET_SU_CN_CARE&title=3G%20tablets%20/%20LTE%20range&_dyncharset=UTF-8 - 'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b', - // db + http://www.cube-tablet.com/buy-products.html - 'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT', - // http://www.cobyusa.com/?p=pcat&pcat_id=3001 - 'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010', - // http://www.match.net.cn/products.asp - 'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733', - // http://www.msi.com/support - // @todo Research the Windows Tablets. - 'MSITablet' => 'MSI \b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\b', - // http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets) - // http://www.imp3.net/14/show.php?itemid=20454 - 'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)', - // http://www.rock-chips.com/index.php?do=prod&pid=2 - 'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A', - // http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/ - 'FlyTablet' => 'IQ310|Fly Vision', - // http://www.bqreaders.com/gb/tablets-prices-sale.html - 'bqTablet' => 'bq.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant)|Maxwell.*Lite|Maxwell.*Plus', - // http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290 - // http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets) - 'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim', - // Nec or Medias Tab - 'NecTablet' => '\bN-06D|\bN-08D', - // Pantech Tablets: http://www.pantechusa.com/phones/ - 'PantechTablet' => 'Pantech.*P4100', - // Broncho Tablets: http://www.broncho.cn/ (hard to find) - 'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)', - // http://versusuk.com/support.html - 'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b', - // http://www.zync.in/index.php/our-products/tablet-phablets - 'ZyncTablet' => 'z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900', - // http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/ - 'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA', - // https://www.nabitablet.com/ - 'NabiTablet' => 'Android.*\bNabi', - 'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build', - // French Danew Tablets http://www.danew.com/produits-tablette.php - 'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b', - // Texet Tablets and Readers http://www.texet.ru/tablet/ - 'TexetTablet' => 'NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE', - // Avoid detecting 'PLAYSTATION 3' as mobile. - 'PlaystationTablet' => 'Playstation.*(Portable|Vita)', - // http://www.trekstor.de/surftabs.html - 'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab', - // http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets - 'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b', - // http://www.advandigital.com/index.php?link=content-product&jns=JP001 - // because of the short codenames we have to include whitespaces to reduce the possible conflicts. - 'AdvanTablet' => 'Android.* \b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\b ', - // http://www.danytech.com/category/tablet-pc - 'DanyTechTablet' => 'Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1', - // http://www.galapad.net/product.html - 'GalapadTablet' => 'Android.*\bG1\b', - // http://www.micromaxinfo.com/tablet/funbook - 'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b', - // http://www.karbonnmobiles.com/products_tablet.php - 'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b', - // http://www.myallfine.com/Products.asp - 'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide', - // http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr= - 'PROSCANTablet' => '\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\b', - // http://www.yonesnav.com/products/products.php - 'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026', - // http://www.cjshowroom.com/eproducts.aspx?classcode=004001001 - // China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html) - 'ChangJiaTablet' => 'TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503', - // http://www.gloryunion.cn/products.asp - // http://www.allwinnertech.com/en/apply/mobile.html - // http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB) - // @todo: Softwiner tablets? - // aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions. - 'GUTablet' => 'TX-A1301|TX-M9002|Q702|kf026', // A12R|D75A|D77|D79|R83|A95|A106C|R15|A75|A76|D71|D72|R71|R73|R77|D82|R85|D92|A97|D92|R91|A10F|A77F|W71F|A78F|W78F|W81F|A97F|W91F|W97F|R16G|C72|C73E|K72|K73|R96G - // http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118 - 'PointOfViewTablet' => 'TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10', - // http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/ - // @todo: add more tests. - 'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)', - // http://hclmetablet.com/India/index.php - 'HCLTablet' => 'HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync', - // http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html - 'DPSTablet' => 'DPS Dream 9|DPS Dual 7', - // http://www.visture.com/index.asp - 'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10', - // http://www.mijncresta.nl/tablet - 'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989', - // MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309 - 'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b', - // Concorde tab - 'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan', - // GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/ - 'GoCleverTablet' => 'GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042', - // Modecom Tablets - http://www.modecom.eu/tablets/portal/ - 'ModecomTablet' => 'FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003', - // Vonino Tablets - http://www.vonino.eu/tablets - 'VoninoTablet' => '\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\bQ8\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\b', - // ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0 - 'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1', - // Storex Tablets - http://storex.fr/espace_client/support.html - // @note: no need to add all the tablet codes since they are guided by the first regex. - 'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab', - // Generic Vodafone tablets. - 'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7', - // French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb - // Aka: http://www.essentielb.fr/ - 'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2', - // Ross & Moor - http://ross-moor.ru/ - 'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711', - // i-mobile http://product.i-mobilephone.com/Mobile_Device - 'iMobileTablet' => 'i-mobile i-note', - // http://www.tolino.de/de/vergleichen/ - 'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine', - // AudioSonic - a Kmart brand - // http://www.kmart.com.au/webapp/wcs/stores/servlet/Search?langId=-1&storeId=10701&catalogId=10001&categoryId=193001&pageSize=72¤tPage=1&searchCategory=193001%2b4294965664&sortBy=p_MaxPrice%7c1 - 'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b', - // AMPE Tablets - http://www.ampe.com.my/product-category/tablets/ - // @todo: add them gradually to avoid conflicts. - 'AMPETablet' => 'Android.* A78 ', - // Skk Mobile - http://skkmobile.com.ph/product_tablets.php - 'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)', - // Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1 - 'TecnoTablet' => 'TECNO P9', - // JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3 - 'JXDTablet' => 'Android.*\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b', - // i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/ - 'iJoyTablet' => 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)', - // http://www.intracon.eu/tablet - 'FX2Tablet' => 'FX2 PAD7|FX2 PAD10', - // http://www.xoro.de/produkte/ - // @note: Might be the same brand with 'Simply tablets' - 'XoroTablet' => 'KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151', - // http://www1.viewsonic.com/products/computing/tablets/ - 'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a', - // http://www.odys.de/web/internet-tablet_en.html - 'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10', - // http://www.captiva-power.de/products.html#tablets-en - 'CaptivaTablet' => 'CAPTIVA PAD', - // IconBIT - http://www.iconbit.com/products/tablets/ - 'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S', - // http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63 - 'TeclastTablet' => '\(Linux;\sAndroid\s[\d\.]+;\s[PXGAT]\d{2,}.*\sBuild/.*?\)', - 'JaytechTablet' => 'TPC-PA762', - 'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010', - // http://www.digma.ru/support/download/ - // @todo: Ebooks also (if requested) - 'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b', - // http://www.evolioshop.com/ro/tablete-pc.html - // http://www.evolio.ro/support/downloads_static.html?cat=2 - // @todo: Research some more - 'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b', - // http://navroad.com/products/produkty/tablety/ - 'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI', - // http://www.datawind.com/ubislate/ - 'UbislateTablet' => 'UbiSlate[\s]?7C', - // http://www.pocketbook-int.com/ru/support - 'PocketBookTablet' => 'Pocketbook', - // http://www.tesco.com/direct/hudl/ - 'Hudl' => 'Hudl HT7S3', - // http://www.telstra.com.au/home-phone/thub-2/ - 'TelstraTablet' => 'T-Hub2', - 'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\bM6pro\b|CT1020W|arc 10HD' - ); - - /** - * List of mobile Operating Systems. - * - * @var array - */ - protected static $operatingSystems = array( - 'AndroidOS' => 'Android', - 'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os', - 'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino', - 'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b', - // @reference: http://en.wikipedia.org/wiki/Windows_Mobile - 'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;', - // @reference: http://en.wikipedia.org/wiki/Windows_Phone - // http://wifeng.cn/?r=blog&a=view&id=106 - // http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx - // http://msdn.microsoft.com/library/ms537503.aspx - 'WindowsPhoneOS' => 'Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;', - 'iOS' => '\biPhone.*Mobile|\biPod|\biPad', - // http://en.wikipedia.org/wiki/MeeGo - // @todo: research MeeGo in UAs - 'MeeGoOS' => 'MeeGo', - // http://en.wikipedia.org/wiki/Maemo - // @todo: research Maemo in UAs - 'MaemoOS' => 'Maemo', - 'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135 - 'webOS' => 'webOS|hpwOS', - 'badaOS' => '\bBada\b', - 'BREWOS' => 'BREW', - ); - - /** - * List of mobile User Agents. - * - * @var array - */ - protected static $browsers = array( - // @reference: https://developers.google.com/chrome/mobile/docs/user-agent - 'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?', - 'Dolfin' => '\bDolfin\b', - 'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+|Coast/[0-9.]+', - 'Skyfire' => 'Skyfire', - 'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+ - 'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile', - 'Bolt' => 'bolt', - 'TeaShark' => 'teashark', - 'Blazer' => 'Blazer', - // @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3 - 'Safari' => 'Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari', - // http://en.wikipedia.org/wiki/Midori_(web_browser) - //'Midori' => 'midori', - 'Tizen' => 'Tizen', - 'UCBrowser' => 'UC.*Browser|UCWEB', - 'baiduboxapp' => 'baiduboxapp', - 'baidubrowser' => 'baidubrowser', - // https://github.com/serbanghita/Mobile-Detect/issues/7 - 'DiigoBrowser' => 'DiigoBrowser', - // http://www.puffinbrowser.com/index.php - 'Puffin' => 'Puffin', - // http://mercury-browser.com/index.html - 'Mercury' => '\bMercury\b', - // http://en.wikipedia.org/wiki/Obigo_Browser - 'ObigoBrowser' => 'Obigo', - // http://en.wikipedia.org/wiki/NetFront - 'NetFront' => 'NF-Browser', - // @reference: http://en.wikipedia.org/wiki/Minimo - // http://en.wikipedia.org/wiki/Vision_Mobile_Browser - 'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger', - ); - - /** - * Utilities. - * - * @var array - */ - protected static $utilities = array( - // Experimental. When a mobile device wants to switch to 'Desktop Mode'. - // http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/ - // https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011 - 'DesktopMode' => 'WPDesktop', - 'TV' => 'SonyDTV|HbbTV', // experimental - 'WebKit' => '(webkit)[ /]([\w.]+)', - 'Bot' => 'Googlebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|facebookexternalhit', - 'MobileBot' => 'Googlebot-Mobile|YahooSeeker/M1A1-R2D2', - // @todo: Include JXD consoles. - 'Console' => '\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\b', - 'Watch' => 'SM-V700', - ); - - /** - * All possible HTTP headers that represent the - * User-Agent string. - * - * @var array - */ - protected static $uaHttpHeaders = array( - // The default User-Agent string. - 'HTTP_USER_AGENT', - // Header can occur on devices using Opera Mini. - 'HTTP_X_OPERAMINI_PHONE_UA', - // Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/ - 'HTTP_X_DEVICE_USER_AGENT', - 'HTTP_X_ORIGINAL_USER_AGENT', - 'HTTP_X_SKYFIRE_PHONE', - 'HTTP_X_BOLT_PHONE_UA', - 'HTTP_DEVICE_STOCK_UA', - 'HTTP_X_UCBROWSER_DEVICE_UA' - ); - - /** - * The individual segments that could exist in a User-Agent string. VER refers to the regular - * expression defined in the constant self::VER. - * - * @var array - */ - protected static $properties = array( - - // Build - 'Mobile' => 'Mobile/[VER]', - 'Build' => 'Build/[VER]', - 'Version' => 'Version/[VER]', - 'VendorID' => 'VendorID/[VER]', - - // Devices - 'iPad' => 'iPad.*CPU[a-z ]+[VER]', - 'iPhone' => 'iPhone.*CPU[a-z ]+[VER]', - 'iPod' => 'iPod.*CPU[a-z ]+[VER]', - //'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'), - 'Kindle' => 'Kindle/[VER]', - - // Browser - 'Chrome' => array('Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'), - 'Coast' => array('Coast/[VER]'), - 'Dolfin' => 'Dolfin/[VER]', - // @reference: https://developer.mozilla.org/en-US/docs/User_Agent_Strings_Reference - 'Firefox' => 'Firefox/[VER]', - 'Fennec' => 'Fennec/[VER]', - // @reference: http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx - 'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];'), - // http://en.wikipedia.org/wiki/NetFront - 'NetFront' => 'NetFront/[VER]', - 'NokiaBrowser' => 'NokiaBrowser/[VER]', - 'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ), - 'Opera Mini' => 'Opera Mini/[VER]', - 'Opera Mobi' => 'Version/[VER]', - 'UC Browser' => 'UC Browser[VER]', - 'MQQBrowser' => 'MQQBrowser/[VER]', - 'MicroMessenger' => 'MicroMessenger/[VER]', - 'baiduboxapp' => 'baiduboxapp/[VER]', - 'baidubrowser' => 'baidubrowser/[VER]', - // @note: Safari 7534.48.3 is actually Version 5.1. - // @note: On BlackBerry the Version is overwriten by the OS. - 'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ), - 'Skyfire' => 'Skyfire/[VER]', - 'Tizen' => 'Tizen/[VER]', - 'Webkit' => 'webkit[ /][VER]', - - // Engine - 'Gecko' => 'Gecko/[VER]', - 'Trident' => 'Trident/[VER]', - 'Presto' => 'Presto/[VER]', - - // OS - 'iOS' => ' \bOS\b [VER] ', - 'Android' => 'Android [VER]', - 'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'), - 'BREW' => 'BREW [VER]', - 'Java' => 'Java/[VER]', - // @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx - // @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases - 'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]'), - 'Windows Phone' => 'Windows Phone [VER]', - 'Windows CE' => 'Windows CE/[VER]', - // http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd - 'Windows NT' => 'Windows NT [VER]', - 'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'), - 'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'), - ); - - /** - * Construct an instance of this class. - * - * @param array $headers Specify the headers as injection. Should be PHP _SERVER flavored. - * If left empty, will use the global _SERVER['HTTP_*'] vars instead. - * @param string $userAgent Inject the User-Agent header. If null, will use HTTP_USER_AGENT - * from the $headers array instead. - */ - public function __construct( - array $headers = null, - $userAgent = null - ) { - $this->setHttpHeaders($headers); - $this->setUserAgent($userAgent); - } - - /** - * Get the current script version. - * This is useful for the demo.php file, - * so people can check on what version they are testing - * for mobile devices. - * - * @return string The version number in semantic version format. - */ - public static function getScriptVersion() - { - return self::VERSION; - } - - /** - * Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers. - * - * @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract - * the headers. The default null is left for backwards compatibilty. - */ - public function setHttpHeaders($httpHeaders = null) - { - //use global _SERVER if $httpHeaders aren't defined - if (!is_array($httpHeaders) || !count($httpHeaders)) { - $httpHeaders = $_SERVER; - } - - //clear existing headers - $this->httpHeaders = array(); - - //Only save HTTP headers. In PHP land, that means only _SERVER vars that - //start with HTTP_. - foreach ($httpHeaders as $key => $value) { - if (substr($key, 0, 5) == 'HTTP_') { - $this->httpHeaders[$key] = $value; - } - } - } - - /** - * Retrieves the HTTP headers. - * - * @return array - */ - public function getHttpHeaders() - { - return $this->httpHeaders; - } - - /** - * Retrieves a particular header. If it doesn't exist, no exception/error is caused. - * Simply null is returned. - * - * @param string $header The name of the header to retrieve. Can be HTTP compliant such as - * "User-Agent" or "X-Device-User-Agent" or can be php-esque with the - * all-caps, HTTP_ prefixed, underscore seperated awesomeness. - * - * @return string|null The value of the header. - */ - public function getHttpHeader($header) - { - //are we using PHP-flavored headers? - if (strpos($header, '_') === false) { - $header = str_replace('-', '_', $header); - $header = strtoupper($header); - } - - //test the alternate, too - $altHeader = 'HTTP_' . $header; - - //Test both the regular and the HTTP_ prefix - if (isset($this->httpHeaders[$header])) { - return $this->httpHeaders[$header]; - } elseif (isset($this->httpHeaders[$altHeader])) { - return $this->httpHeaders[$altHeader]; - } - - return null; - } - - public function getMobileHeaders() - { - return self::$mobileHeaders; - } - - /** - * Get all possible HTTP headers that - * can contain the User-Agent string. - * - * @return array List of HTTP headers. - */ - public function getUaHttpHeaders() - { - return self::$uaHttpHeaders; - } - - /** - * Set the User-Agent to be used. - * - * @param string $userAgent The user agent string to set. - * - * @return string|null - */ - public function setUserAgent($userAgent = null) - { - if (!empty($userAgent)) { - return $this->userAgent = $userAgent; - } else { - - $this->userAgent = null; - - foreach ($this->getUaHttpHeaders() as $altHeader) { - if (!empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban) - $this->userAgent .= $this->httpHeaders[$altHeader] . " "; - } - } - - return $this->userAgent = (!empty($this->userAgent) ? trim($this->userAgent) : null); - - } - } - - /** - * Retrieve the User-Agent. - * - * @return string|null The user agent if it's set. - */ - public function getUserAgent() - { - return $this->userAgent; - } - - /** - * Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or - * self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set. - * - * @deprecated since version 2.6.9 - * - * @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default - * parameter is null which will default to self::DETECTION_TYPE_MOBILE. - */ - public function setDetectionType($type = null) - { - if ($type === null) { - $type = self::DETECTION_TYPE_MOBILE; - } - - if ($type != self::DETECTION_TYPE_MOBILE && $type != self::DETECTION_TYPE_EXTENDED) { - return; - } - - $this->detectionType = $type; - } - - /** - * Retrieve the list of known phone devices. - * - * @return array List of phone devices. - */ - public static function getPhoneDevices() - { - return self::$phoneDevices; - } - - /** - * Retrieve the list of known tablet devices. - * - * @return array List of tablet devices. - */ - public static function getTabletDevices() - { - return self::$tabletDevices; - } - - /** - * Alias for getBrowsers() method. - * - * @return array List of user agents. - */ - public static function getUserAgents() - { - return self::getBrowsers(); - } - - /** - * Retrieve the list of known browsers. Specifically, the user agents. - * - * @return array List of browsers / user agents. - */ - public static function getBrowsers() - { - return self::$browsers; - } - - /** - * Retrieve the list of known utilities. - * - * @return array List of utilities. - */ - public static function getUtilities() - { - return self::$utilities; - } - - /** - * Method gets the mobile detection rules. This method is used for the magic methods $detect->is*(). - * - * @deprecated since version 2.6.9 - * - * @return array All the rules (but not extended). - */ - public static function getMobileDetectionRules() - { - static $rules; - - if (!$rules) { - $rules = array_merge( - self::$phoneDevices, - self::$tabletDevices, - self::$operatingSystems, - self::$browsers - ); - } - - return $rules; - - } - - /** - * Method gets the mobile detection rules + utilities. - * The reason this is separate is because utilities rules - * don't necessary imply mobile. This method is used inside - * the new $detect->is('stuff') method. - * - * @deprecated since version 2.6.9 - * - * @return array All the rules + extended. - */ - public function getMobileDetectionRulesExtended() - { - static $rules; - - if (!$rules) { - // Merge all rules together. - $rules = array_merge( - self::$phoneDevices, - self::$tabletDevices, - self::$operatingSystems, - self::$browsers, - self::$utilities - ); - } - - return $rules; - } - - /** - * Retrieve the current set of rules. - * - * @deprecated since version 2.6.9 - * - * @return array - */ - public function getRules() - { - if ($this->detectionType == self::DETECTION_TYPE_EXTENDED) { - return self::getMobileDetectionRulesExtended(); - } else { - return self::getMobileDetectionRules(); - } - } - - /** - * Retrieve the list of mobile operating systems. - * - * @return array The list of mobile operating systems. - */ - public static function getOperatingSystems() - { - return self::$operatingSystems; - } - - /** - * Check the HTTP headers for signs of mobile. - * This is the fastest mobile check possible; it's used - * inside isMobile() method. - * - * @return bool - */ - public function checkHttpHeadersForMobile() - { - - foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) { - if (isset($this->httpHeaders[$mobileHeader])) { - if (is_array($matchType['matches'])) { - foreach ($matchType['matches'] as $_match) { - if (strpos($this->httpHeaders[$mobileHeader], $_match) !== false) { - return true; - } - } - - return false; - } else { - return true; - } - } - } - - return false; - - } - - /** - * Magic overloading method. - * - * @method boolean is[...]() - * @param string $name - * @param array $arguments - * @return mixed - * @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is' - */ - public function __call($name, $arguments) - { - //make sure the name starts with 'is', otherwise - if (substr($name, 0, 2) != 'is') { - throw new BadMethodCallException("No such method exists: $name"); - } - - $this->setDetectionType(self::DETECTION_TYPE_MOBILE); - - $key = substr($name, 2); - - return $this->matchUAAgainstKey($key); - } - - /** - * Find a detection rule that matches the current User-agent. - * - * @param null $userAgent deprecated - * @return boolean - */ - protected function matchDetectionRulesAgainstUA($userAgent = null) - { - // Begin general search. - foreach ($this->getRules() as $_regex) { - if (empty($_regex)) { - continue; - } - if ($this->match($_regex, $userAgent)) { - return true; - } - } - - return false; - } - - /** - * Search for a certain key in the rules array. - * If the key is found the try to match the corresponding - * regex agains the User-Agent. - * - * @param string $key - * @param null $userAgent deprecated - * @return mixed - */ - protected function matchUAAgainstKey($key, $userAgent = null) - { - // Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc. - $key = strtolower($key); - - //change the keys to lower case - $_rules = array_change_key_case($this->getRules()); - - if (array_key_exists($key, $_rules)) { - if (empty($_rules[$key])) { - return null; - } - - return $this->match($_rules[$key], $userAgent); - } - - return false; - } - - /** - * Check if the device is mobile. - * Returns true if any type of mobile device detected, including special ones - * @param null $userAgent deprecated - * @param null $httpHeaders deprecated - * @return bool - */ - public function isMobile($userAgent = null, $httpHeaders = null) - { - - if ($httpHeaders) { - $this->setHttpHeaders($httpHeaders); - } - - if ($userAgent) { - $this->setUserAgent($userAgent); - } - - $this->setDetectionType(self::DETECTION_TYPE_MOBILE); - - if ($this->checkHttpHeadersForMobile()) { - return true; - } else { - return $this->matchDetectionRulesAgainstUA(); - } - - } - - /** - * Check if the device is a tablet. - * Return true if any type of tablet device is detected. - * - * @param string $userAgent deprecated - * @param array $httpHeaders deprecated - * @return bool - */ - public function isTablet($userAgent = null, $httpHeaders = null) - { - $this->setDetectionType(self::DETECTION_TYPE_MOBILE); - - foreach (self::$tabletDevices as $_regex) { - if ($this->match($_regex, $userAgent)) { - return true; - } - } - - return false; - } - - /** - * This method checks for a certain property in the - * userAgent. - * @todo: The httpHeaders part is not yet used. - * - * @param string $key - * @param string $userAgent deprecated - * @param string $httpHeaders deprecated - * @return bool|int|null - */ - public function is($key, $userAgent = null, $httpHeaders = null) - { - // Set the UA and HTTP headers only if needed (eg. batch mode). - if ($httpHeaders) { - $this->setHttpHeaders($httpHeaders); - } - - if ($userAgent) { - $this->setUserAgent($userAgent); - } - - $this->setDetectionType(self::DETECTION_TYPE_EXTENDED); - - return $this->matchUAAgainstKey($key); - } - - /** - * Some detection rules are relative (not standard), - * because of the diversity of devices, vendors and - * their conventions in representing the User-Agent or - * the HTTP headers. - * - * This method will be used to check custom regexes against - * the User-Agent string. - * - * @param $regex - * @param string $userAgent - * @return bool - * - * @todo: search in the HTTP headers too. - */ - public function match($regex, $userAgent = null) - { - return (bool) preg_match('%'.$regex.'%is', (!empty($userAgent) ? $userAgent : $this->userAgent)); - } - - /** - * Get the properties array. - * - * @return array - */ - public static function getProperties() - { - return self::$properties; - } - - /** - * Prepare the version number. - * - * @todo Remove the error supression from str_replace() call. - * - * @param string $ver The string version, like "2.6.21.2152"; - * - * @return float - */ - public function prepareVersionNo($ver) - { - $ver = str_replace(array('_', ' ', '/'), '.', $ver); - $arrVer = explode('.', $ver, 2); - - if (isset($arrVer[1])) { - $arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions. - } - - return (float) implode('.', $arrVer); - } - - /** - * Check the version of the given property in the User-Agent. - * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) - * - * @param string $propertyName The name of the property. See self::getProperties() array - * keys for all possible properties. - * @param string $type Either self::VERSION_TYPE_STRING to get a string value or - * self::VERSION_TYPE_FLOAT indicating a float value. This parameter - * is optional and defaults to self::VERSION_TYPE_STRING. Passing an - * invalid parameter will default to the this type as well. - * - * @return string|float The version of the property we are trying to extract. - */ - public function version($propertyName, $type = self::VERSION_TYPE_STRING) - { - if (empty($propertyName)) { - return false; - } - - //set the $type to the default if we don't recognize the type - if ($type != self::VERSION_TYPE_STRING && $type != self::VERSION_TYPE_FLOAT) { - $type = self::VERSION_TYPE_STRING; - } - - $properties = self::getProperties(); - - // Check if the property exists in the properties array. - if (array_key_exists($propertyName, $properties)) { - - // Prepare the pattern to be matched. - // Make sure we always deal with an array (string is converted). - $properties[$propertyName] = (array) $properties[$propertyName]; - - foreach ($properties[$propertyName] as $propertyMatchString) { - - $propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString); - - // Escape the special character which is the delimiter. - $propertyPattern = str_replace('/', '\/', $propertyPattern); - - // Identify and extract the version. - preg_match('/'.$propertyPattern.'/is', $this->userAgent, $match); - - if (!empty($match[1])) { - $version = ($type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1]); - - return $version; - } - - } - - } - - return false; - } - - /** - * Retrieve the mobile grading, using self::MOBILE_GRADE_* constants. - * - * @return string One of the self::MOBILE_GRADE_* constants. - */ - public function mobileGrade() - { - $isMobile = $this->isMobile(); - - if ( - // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1) - $this->isIOS() && $this->version('iPad', self::VERSION_TYPE_FLOAT)>=4.3 || - $this->isIOS() && $this->version('iPhone', self::VERSION_TYPE_FLOAT)>=3.1 || - $this->isIOS() && $this->version('iPod', self::VERSION_TYPE_FLOAT)>=3.1 || - - // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) - // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM - // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices - // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 - ($this->version('Android', self::VERSION_TYPE_FLOAT)>2.1 && $this->is('Webkit')) || - - // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800 - $this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT)>=7.0 || - - // Blackberry 7 - Tested on BlackBerry Torch 9810 - // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 - $this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)>=6.0 || - // Blackberry Playbook (1.0-2.0) - Tested on PlayBook - $this->match('Playbook.*Tablet') || - - // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0) - ($this->version('webOS', self::VERSION_TYPE_FLOAT)>=1.4 && $this->match('Palm|Pre|Pixi')) || - // Palm WebOS 3.0 - Tested on HP TouchPad - $this->match('hp.*TouchPad') || - - // Firefox Mobile (12 Beta) - Tested on Android 2.3 device - ($this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT)>=12) || - - // Chrome for Android - Tested on Android 4.0, 4.1 device - ($this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT)>=4.0) || - - // Skyfire 4.1 - Tested on Android 2.3 device - ($this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT)>=4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3) || - - // Opera Mobile 11.5-12: Tested on Android 2.3 - ($this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT)>11 && $this->is('AndroidOS')) || - - // Meego 1.2 - Tested on Nokia 950 and N9 - $this->is('MeeGoOS') || - - // Tizen (pre-release) - Tested on early hardware - $this->is('Tizen') || - - // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser - // @todo: more tests here! - $this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT)>=2.0 || - - // UC Browser - Tested on Android 2.3 device - (($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3) || - - // Kindle 3 and Fire - Tested on the built-in WebKit browser for each - ($this->match('Kindle Fire') || - $this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT)>=3.0) || - - // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet - $this->is('AndroidOS') && $this->is('NookTablet') || - - // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7 - $this->version('Chrome', self::VERSION_TYPE_FLOAT)>=11 && !$isMobile || - - // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 - $this->version('Safari', self::VERSION_TYPE_FLOAT)>=5.0 && !$isMobile || - - // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 - $this->version('Firefox', self::VERSION_TYPE_FLOAT)>=4.0 && !$isMobile || - - // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 - $this->version('MSIE', self::VERSION_TYPE_FLOAT)>=7.0 && !$isMobile || - - // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 - // @reference: http://my.opera.com/community/openweb/idopera/ - $this->version('Opera', self::VERSION_TYPE_FLOAT)>=10 && !$isMobile - - ){ - return self::MOBILE_GRADE_A; - } - - if ( - $this->isIOS() && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 || - $this->isIOS() && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<3.1 || - $this->isIOS() && $this->version('iPod', self::VERSION_TYPE_FLOAT)<3.1 || - - // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 - $this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)>=5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 || - - //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 - ($this->version('Opera Mini', self::VERSION_TYPE_FLOAT)>=5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT)<=6.5 && - ($this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3 || $this->is('iOS'))) || - - // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) - $this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || - - // @todo: report this (tested on Nokia N71) - $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT)>=11 && $this->is('SymbianOS') - ){ - return self::MOBILE_GRADE_B; - } - - if ( - // Blackberry 4.x - Tested on the Curve 8330 - $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<5.0 || - // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) - $this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT)<=5.2 - - ){ - return self::MOBILE_GRADE_C; - } - - //All older smartphone platforms and featurephones - Any device that doesn't support media queries - //will receive the basic, C grade experience. - return self::MOBILE_GRADE_C; - } -} diff --git a/tools/mobile_Detect/index.php b/tools/mobile_Detect/index.php deleted file mode 100644 index aca71cfae..000000000 --- a/tools/mobile_Detect/index.php +++ /dev/null @@ -1,35 +0,0 @@ - -* @copyright 2007-2017 PrestaShop SA -* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) -* International Registered Trademark & Property of PrestaShop SA -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../'); -exit; diff --git a/tools/mobile_Detect/.htaccess b/tools/mobile_detect/.htaccess similarity index 100% rename from tools/mobile_Detect/.htaccess rename to tools/mobile_detect/.htaccess diff --git a/tools/mobile_detect/autoload.php b/tools/mobile_detect/autoload.php new file mode 100644 index 000000000..fcc99b43e --- /dev/null +++ b/tools/mobile_detect/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @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', 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 string[] $classMap Class to filename map + * @psalm-param array $classMap + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $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 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) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * 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 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) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * 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 string[]|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $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 string[]|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * 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') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * 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 true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + 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 + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + * @private + */ +function includeFile($file) +{ + include $file; +} diff --git a/tools/mobile_detect/composer/InstalledVersions.php b/tools/mobile_detect/composer/InstalledVersions.php new file mode 100644 index 000000000..d50e0c9fc --- /dev/null +++ b/tools/mobile_detect/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/tools/mobile_detect/composer/LICENSE b/tools/mobile_detect/composer/LICENSE new file mode 100644 index 000000000..f27399a04 --- /dev/null +++ b/tools/mobile_detect/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +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/tools/mobile_detect/composer/autoload_classmap.php b/tools/mobile_detect/composer/autoload_classmap.php new file mode 100644 index 000000000..b26f1b13b --- /dev/null +++ b/tools/mobile_detect/composer/autoload_classmap.php @@ -0,0 +1,10 @@ + $vendorDir . '/composer/InstalledVersions.php', +); diff --git a/tools/mobile_detect/composer/autoload_namespaces.php b/tools/mobile_detect/composer/autoload_namespaces.php new file mode 100644 index 000000000..b7fc0125d --- /dev/null +++ b/tools/mobile_detect/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/psr/simple-cache/src'), + 'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'), + 'Detection\\' => array($vendorDir . '/mobiledetect/mobiledetectlib/src'), +); diff --git a/tools/mobile_detect/composer/autoload_real.php b/tools/mobile_detect/composer/autoload_real.php new file mode 100644 index 000000000..6f65c4edc --- /dev/null +++ b/tools/mobile_detect/composer/autoload_real.php @@ -0,0 +1,57 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInita08d71f03337ee7858b0d26c24ffd06c::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + return $loader; + } +} diff --git a/tools/mobile_detect/composer/autoload_static.php b/tools/mobile_detect/composer/autoload_static.php new file mode 100644 index 000000000..2fbe672a9 --- /dev/null +++ b/tools/mobile_detect/composer/autoload_static.php @@ -0,0 +1,49 @@ + + array ( + 'Psr\\SimpleCache\\' => 16, + 'Psr\\Cache\\' => 10, + ), + 'D' => + array ( + 'Detection\\' => 10, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Psr\\SimpleCache\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/simple-cache/src', + ), + 'Psr\\Cache\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/cache/src', + ), + 'Detection\\' => + array ( + 0 => __DIR__ . '/..' . '/mobiledetect/mobiledetectlib/src', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInita08d71f03337ee7858b0d26c24ffd06c::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInita08d71f03337ee7858b0d26c24ffd06c::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInita08d71f03337ee7858b0d26c24ffd06c::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/tools/mobile_detect/composer/installed.json b/tools/mobile_detect/composer/installed.json new file mode 100644 index 000000000..0e07c1833 --- /dev/null +++ b/tools/mobile_detect/composer/installed.json @@ -0,0 +1,180 @@ +{ + "packages": [ + { + "name": "mobiledetect/mobiledetectlib", + "version": "4.8.09", + "version_normalized": "4.8.09.0", + "source": { + "type": "git", + "url": "https://github.com/serbanghita/Mobile-Detect.git", + "reference": "a06fe2e546a06bb8c2639d6823d5250b2efb3209" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/a06fe2e546a06bb8c2639d6823d5250b2efb3209", + "reference": "a06fe2e546a06bb8c2639d6823d5250b2efb3209", + "shasum": "" + }, + "require": { + "php": ">=8.0", + "psr/cache": "^3.0", + "psr/simple-cache": "^3" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^v3.65.0", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.12.x-dev", + "phpunit/phpunit": "^9.6.18", + "squizlabs/php_codesniffer": "^3.11.1" + }, + "time": "2024-12-10T15:32:06+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Detection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Serban Ghita", + "email": "serbanghita@gmail.com", + "homepage": "http://mobiledetect.net", + "role": "Developer" + } + ], + "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.", + "homepage": "https://github.com/serbanghita/Mobile-Detect", + "keywords": [ + "detect mobile devices", + "mobile", + "mobile detect", + "mobile detector", + "php mobile detect" + ], + "support": { + "issues": "https://github.com/serbanghita/Mobile-Detect/issues", + "source": "https://github.com/serbanghita/Mobile-Detect/tree/4.8.09" + }, + "funding": [ + { + "url": "https://github.com/serbanghita", + "type": "github" + } + ], + "install-path": "../mobiledetect/mobiledetectlib" + }, + { + "name": "psr/cache", + "version": "3.0.0", + "version_normalized": "3.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "time": "2021-02-03T23:26:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "install-path": "../psr/cache" + }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "version_normalized": "3.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "time": "2021-10-29T13:26:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "install-path": "../psr/simple-cache" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/tools/mobile_detect/composer/installed.php b/tools/mobile_detect/composer/installed.php new file mode 100644 index 000000000..2aabf4d82 --- /dev/null +++ b/tools/mobile_detect/composer/installed.php @@ -0,0 +1,50 @@ + array( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => NULL, + 'name' => '__root__', + 'dev' => true, + ), + 'versions' => array( + '__root__' => array( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => NULL, + 'dev_requirement' => false, + ), + 'mobiledetect/mobiledetectlib' => array( + 'pretty_version' => '4.8.09', + 'version' => '4.8.09.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../mobiledetect/mobiledetectlib', + 'aliases' => array(), + 'reference' => 'a06fe2e546a06bb8c2639d6823d5250b2efb3209', + 'dev_requirement' => false, + ), + 'psr/cache' => array( + 'pretty_version' => '3.0.0', + 'version' => '3.0.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/cache', + 'aliases' => array(), + 'reference' => 'aa5030cfa5405eccfdcb1083ce040c2cb8d253bf', + 'dev_requirement' => false, + ), + 'psr/simple-cache' => array( + 'pretty_version' => '3.0.0', + 'version' => '3.0.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/simple-cache', + 'aliases' => array(), + 'reference' => '764e0b3939f5ca87cb904f570ef9be2d78a07865', + 'dev_requirement' => false, + ), + ), +); diff --git a/tools/mobile_detect/composer/platform_check.php b/tools/mobile_detect/composer/platform_check.php new file mode 100644 index 000000000..adfb472fb --- /dev/null +++ b/tools/mobile_detect/composer/platform_check.php @@ -0,0 +1,26 @@ += 80000)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 8.0.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/tools/mobile_detect/mobiledetect/mobiledetectlib/CHANGELOG.md b/tools/mobile_detect/mobiledetect/mobiledetectlib/CHANGELOG.md new file mode 100644 index 000000000..8cfc36480 --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/CHANGELOG.md @@ -0,0 +1,72 @@ +# Change log + +# 4.8.09 + +- [x] `sha1` is now the default fn for encoding cache keys. Using `base64` [was causing problems](https://github.com/serbanghita/Mobile-Detect/issues/974#issuecomment-2531597903) in Laravel. + +# 4.8.08 + +- [x] fix for missing psr/cache prod dependency +- [bug] latest 4.8.07 cause site error Call to a member function get() on false #974 +- [x] fix for Docker build not installing dev dependencies + +# 4.8.07 (broken in composer, please skip) + +- [x] fix cache and generate short cache key (#971) +- [x] Added configuration cacheKeyFn which allows for using a custom cache key creation fn. +- [x] Use Client Hints Sec-CH-UA-Mobile header to detect mobile (#962) +- [x] added Huawei (phone, OS - HarmonyOS, browser) detection (#952) +- [x] Bugfix: Allow Injection of Any PSR Cache Interface (#966) +- [x] PHP 8.4 - implicit nulls are deprecated (#960) + + +# 4.8.03 +- [x] added optional `$config` to MobileDetect constructor. +- [x] added `autoInitOfHttpHeaders` configuration which is by default `true`. This enabled the old behavior from `3.x` and `2.x` that allows automatic detection of HTTP headers and User Agent from $_SERVER. +- [x] refactored internal CloudFront related methods and the way `setHttpHeaders` work. It no longer falls back on `$_SERVER`. The method still calls `setUserAgent` in case `HTTP_USER_AGENT` and friends are present. +- [x] added `maximumUserAgentLength` to the `$config`, by default the limit is `500`. + +# 4.8.02 +- [x] new user agents +- [x] Samsung Galaxy Tab S6 Lite #919 +- [x] Samsung Galaxy Tab S8 series #912 + +# 4.8.01 + +- [x] PHP 8.x only. +- [x] PSR-16 cache support. +- [x] Constructor accepts `CacheFactory` class where you can inject your own PSR-6 Cache interfaces. +- [x] You need to explicitly `setUserAgent("...")` or `setUserAgentHeaders([...])` otherwise an exception is being thrown. +- [x] `scripts/` folder no longer included in the git tag release archive. +- [x] added performance tests +- [x] regexes can be arrays of strings or strings + + +# 2023 + +Launched 4.8.xx which contains PHP 8.x support, refactorings and external Cache support. + +## 2022 + +In December 2022 we released the version for PHP7. +Mobile Detect was split into two dev branches: `2.8.x` which will support PHP5, but is deprecated and +`3.74.x` which supports PHP >= 7.3 + +## 2013 + +In August 2013 the library has 1800+ stargazers and support for: composer, PHPUnit tests, PSR standards and a new webpage http://mobiledetect.net + +# 2012 + +Throughout 2012 the script has been updated constantly, and we have received tons of feedback and requests. +In July 2012 we moved the repository from Google Code to GitHub in order to quickly accommodate the frequent updates and to involve more people. + +## 2011 + +In December 2011 it received a major update from the first version, an important number of issues were fixed, then 2.0 was launched. +The new version marks a new mindset and also featuring tablet detection. + +## 2009 + +The first version of the script was developed in 2009, and it was hosted at https://code.google.com/p/php-mobile-detect/, it was a small project with around 30 stars. +(Original blog post by Victor: http://victorstanciu.ro/detectarea-platformelor-mobile-in-php/) diff --git a/tools/mobile_detect/mobiledetect/mobiledetectlib/CNAME b/tools/mobile_detect/mobiledetect/mobiledetectlib/CNAME new file mode 100644 index 000000000..95a789d19 --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/CNAME @@ -0,0 +1 @@ +mobiledetect.net \ No newline at end of file diff --git a/tools/mobile_detect/mobiledetect/mobiledetectlib/CONTRIBUTING.md b/tools/mobile_detect/mobiledetect/mobiledetectlib/CONTRIBUTING.md new file mode 100644 index 000000000..ea1b59512 --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/CONTRIBUTING.md @@ -0,0 +1,149 @@ +# Contributing +Step-by-step guide to contributing to Mobile Detect library. \ +By contributing to Mobile Detect library you agree with the [MIT License](LICENSE). + +## Contribute by developing code + +### 1. [Fork](https://help.github.com/articles/fork-a-repo/#fork-an-example-repository) the repo + +```bash +git clone https://github.com/[yourname]/Mobile-Detect.git +git add remote serbanghita https://github.com/serbanghita/Mobile-Detect.git +git remote -v +... +origin git@github.com:serbanghita/Mobile-Detect.git +serbanghita https://github.com/serbanghita/Mobile-Detect.git +``` + +### 2. Create local branch + +Next create your own git working branch from one of the existing branches `4.x`, `3.x` or `2.x` +depending on your PHP version: + +```bash +git checkout -b my-new-patch origin/x.x.x +``` + +### 3. Build + +#### Local + +```shell +composer install +``` + +#### With Docker CLI + +```shell +DOCKER_BUILDKIT=0 docker build -f ./docker/Dockerfile -t build . +``` + +#### With `docker-compose.yml` (recommended) + +```shell +docker compose build setup +``` + +### 3. Lint the code + +Ensure the code is clean, just run the linters: + +#### Local + +```bash +./vendor/bin/phpcs +./vendor/bin/phpcbf +``` + +#### With `docker-compose.yml` (recommended) + +```shell +docker compose build runLinting +``` + +### 4. Run unit and integration tests + +If you add new methods or make structural changes to the library then you need to add unit tests +otherwise your PR will not be accepted. +If you add new regexes make sure you commit the User-Agents in [`tests/providers/vendors`](https://github.com/serbanghita/Mobile-Detect/tree/master/tests/providers/vendors). +Now that your changes are done, **run the unit tests**: + +#### Locally + +```bash +vendor/bin/phpunit -v -c tests/phpunit.xml --coverage-html .coverage +``` + +#### With `docker-compose.yml` (recommended) + +```shell +docker compose run runUnitTests +``` + +Make sure you check the `.coverage` folder and open the report. \ +The coverage should be just like you first started (close to 100%). + +### 5. Run performance tests + +#### Local + +```bash +./vendor/bin/phpbench run tests/Benchmark/MobileDetectBench.php --ref=baseline --retry-threshold=1 --iterations=10 --revs=1000 --report=aggregate +``` + +#### With `docker-compose.yml` (recommended) + +```shell +docker compose run runPerfTests +``` + +Baseline re-creation: + +```bash +./vendor/bin/phpbench run tests/Benchmark/ --retry-threshold=1 --iterations=10 --revs=1000 --report=aggregate --tag=baseline --dump-file=phpbench-baseline.xml +``` + + +### 6. Commit + +If no errors left, then proceed to committing your changes: + +```bash +git status +git stage +git commit -m "your commit message here" +git push +``` + +### 7. Submit PR + +Now go to your repo on GitHub and ["Submit the PR"](https://help.github.com/articles/about-pull-requests/). + +## Other ways of contributing + +### 1. Report issues + +1. Specify the User-agent by visiting [http://demo.mobiledetect.net](http://demo.mobiledetect.net). +2. Specify the expected behaviour. + +### 2. Add new module, plugin, plugin or port + +[Submit new module, plugin, port](../../issues/new?title=New%203rd%20party%20module&body=Name,%20Link%20and%20Description%20of%20the%20module.) + including the following information: +* Module name +* Description +* Link +* Author + +Or you can submit a PR against `README.md`. + +### 3. Website updates + +1. Our official website is hosted at [http://mobiledetect.net](http://mobiledetect.net). +2. The files are found on the `gh-pages` branch. +3. `git checkout gh-pages` +4. `npm install -g browser-sync` +5. `browser-sync start --s . --f . --port 3000 --reload-debounce 1500 --no-ui` +6. Go to `http://localhost:3000` and make changes. +7. Commit, push and submit the PR against `serbanghita:gh-pages`. + diff --git a/tools/mobile_detect/mobiledetect/mobiledetectlib/KNOWN_LIMITATIONS.md b/tools/mobile_detect/mobiledetect/mobiledetectlib/KNOWN_LIMITATIONS.md new file mode 100644 index 000000000..0f9666e14 --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/KNOWN_LIMITATIONS.md @@ -0,0 +1,15 @@ +**Known limitations** + +* Mobile Detect script was designed to detect `mobile` devices. Implicitly other devices are considered to be `desktop`. +* User-Agent and HTTP headers sniffing is a non-reliable method of detecting a mobile device. +* If the mobile browser is set on `Desktop mode`, the Mobile Detect script has no indicator (eg. a group of strings) that would allow it to detect that the device is `mobile`. +* Ipad 2019 is being recognized as a desktop because of Safari's default `Request Desktop Website` setting. See details and possible workaround [#820](https://github.com/serbanghita/Mobile-Detect/issues/820) + * Also see [#886](https://github.com/serbanghita/Mobile-Detect/issues/886#issuecomment-1047187763) +* Some touchscreen devices (eg. Microsoft Surface) are tough to detect as mobile since they can be used in a laptop mode. See: [#32](https://github.com/serbanghita/Mobile-Detect/issues/32), [#461](https://github.com/serbanghita/Mobile-Detect/issues/461), [#667](https://github.com/serbanghita/Mobile-Detect/issues/667) +* Some mobile devices (eg. IPadOS, Google Pixel Slate). See: [#795](https://github.com/serbanghita/Mobile-Detect/issues/795), [#788](https://github.com/serbanghita/Mobile-Detect/issues/788) +* Detecting the device brand (eg. Apple, Samsung, HTC) is not 100% reliable. +* We don't monitor the quality of the 3rd party tools based on Mobile Detect script. +We cannot guarantee that they are using the class properly or if they provide the latest version. +* Version `2.x` is made to be PHP 5.3 compatible because of the backward compatibility changes of PHP. +* There are hundreds of devices launched every month, we cannot keep a 100% up-to-date detection rate. +* The script cannot detect the viewport, pixel density or resolution of the screen since it's running server-side. diff --git a/tools/mobile_detect/mobiledetect/mobiledetectlib/LICENSE b/tools/mobile_detect/mobiledetect/mobiledetectlib/LICENSE new file mode 100644 index 000000000..69d9874c9 --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Şerban Ghiţă, Nick Ilyin and contributors. + +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/tools/mobile_detect/mobiledetect/mobiledetectlib/MobileDetect.json b/tools/mobile_detect/mobiledetect/mobiledetectlib/MobileDetect.json new file mode 100644 index 000000000..c641602fe --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/MobileDetect.json @@ -0,0 +1,435 @@ +{ + "version": "4.8.09", + "headerMatch": { + "HTTP_ACCEPT": { + "matches": [ + "application\/x-obml2d", + "application\/vnd.rim.html", + "text\/vnd.wap.wml", + "application\/vnd.wap.xhtml+xml" + ] + }, + "HTTP_X_WAP_PROFILE": null, + "HTTP_X_WAP_CLIENTID": null, + "HTTP_WAP_CONNECTION": null, + "HTTP_PROFILE": null, + "HTTP_X_OPERAMINI_PHONE_UA": null, + "HTTP_X_NOKIA_GATEWAY_ID": null, + "HTTP_X_ORANGE_ID": null, + "HTTP_X_VODAFONE_3GPDPCONTEXT": null, + "HTTP_X_HUAWEI_USERID": null, + "HTTP_UA_OS": null, + "HTTP_X_MOBILE_GATEWAY": null, + "HTTP_X_ATT_DEVICEID": null, + "HTTP_UA_CPU": { + "matches": [ + "ARM" + ] + }, + "Sec-CH-UA-Mobile": { + "matches": [ + "?1" + ] + } + }, + "uaHttpHeaders": [ + "HTTP_USER_AGENT", + "HTTP_X_OPERAMINI_PHONE_UA", + "HTTP_X_DEVICE_USER_AGENT", + "HTTP_X_ORIGINAL_USER_AGENT", + "HTTP_X_SKYFIRE_PHONE", + "HTTP_X_BOLT_PHONE_UA", + "HTTP_DEVICE_STOCK_UA", + "HTTP_X_UCBROWSER_DEVICE_UA" + ], + "cloudFrontHttpHeaders": [ + "HTTP_CLOUDFRONT_IS_MOBILE_VIEWER", + "HTTP_CLOUDFRONT_IS_TABLET_VIEWER", + "HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER" + ], + "uaMatch": { + "phones": { + "iPhone": "\\biPhone\\b|\\biPod\\b", + "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+|\\b(BBA100|BBB100|BBD100|BBE100|BBF100|STH100)\\b-[0-9]+", + "Pixel": "; \\bPixel\\b", + "HTC": [ + "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)", + "APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200", + "ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m|Android [0-9.]+; Pixel" + ], + "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 5X|Nexus 6", + "Dell": "Dell[;]? (Streak|Aero|Venue|Venue Pro|Flash|Smoke|Mini 3iX)|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b", + "Motorola": [ + "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955", + "A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611", + "MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863", + "ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317", + "XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800", + "XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b|XT1068|XT1092|XT1052" + ], + "Samsung": [ + "\\bSamsung\\b|SM-G950F|SM-G955F|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310", + "SM-F946B|SM-A127F", + "SM-S908E|SM-G955N|SM-S918U1|SM-G998B|SM-G970N|SM-G973U|SM-S901U|SM-A515F|SM-S901E|SM-G980F|SM-S901B", + "GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510", + "GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K", + "GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010", + "GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100", + "GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210", + "GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250", + "GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420", + "GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700", + "GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103", + "GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800", + "GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210", + "GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350", + "GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660", + "GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230", + "GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600", + "SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930", + "SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730", + "SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351", + "SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430", + "SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740", + "SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157", + "SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657", + "SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817", + "SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220", + "SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225", + "SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105", + "SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200", + "SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717", + "SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917", + "SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500", + "SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777", + "SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229", + "SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409", + "SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609", + "SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749", + "SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200", + "SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497", + "SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10", + "SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700", + "SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700", + "SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220", + "SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550", + "SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920", + "SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535", + "SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510", + "GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582", + "GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K", + "SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558", + "GT-I9205|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C|SM-A310F|GT-I9190|SM-J500FN|SM-G903F|SM-J330F", + "SM-G610F|SM-G981B|SM-G892A|SM-A530F|SM-G988N|SM-G781B|SM-A805N|SM-G965F" + ], + "LG": [ + "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200)", + "LG[- ]?(MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK)", + "LG[- ]?(E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690)", + "LG[- ]?(MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740)", + "LG[- ]?(VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323|M257)|LM-G710" + ], + "Sony": [ + "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i", + "C5303|C6902|C6903|C6906|C6943|D2533|SOV34|601SO|F8332" + ], + "Asus": "Asus.*Galaxy|PadFone.*Mobile|ASUS_Z01QD|ASUS_X00TD", + "Xiaomi": [ + "^(?!.*\\bx11\\b).*xiaomi.*$|POCOPHONE F1|\\bMI\\b 8|\\bMi\\b 10|Redmi Note 9S|Redmi 5A|Redmi Note 5A Prime|Redmi Note 7 Pro", + "N2G47H|M2001J2G|M2001J2I|M1805E10A|M2004J11G|M1902F1G|M2002J9G|M2004J19G|M2003J6A1G|M2012K11C|M2007J1SC" + ], + "NokiaLumia": "Lumia [0-9]{3,4}", + "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b", + "Palm": "PalmSource|Palm", + "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature", + "Pantech": [ + "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L", + "IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S", + "IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995", + "IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790" + ], + "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250", + "Wiko": [ + "KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY", + "BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM" + ], + "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)", + "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b", + "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q", + "Alcatel": "Alcatel", + "Nintendo": "Nintendo (3DS|Switch)", + "Amoi": "Amoi", + "INQ": "INQ", + "OnePlus": "ONEPLUS|CPH2663", + "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser", + "Huawei": "HMSCore|Huawei" + }, + "tablets": { + "iPad": "iPad|iPad.*Mobile", + "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)", + "GoogleTablet": "Android.*Pixel C", + "SamsungTablet": [ + "SM-X616B|SM-X610|SM-X516B|SM-X910|SM-X916B|SM-X816B|SM-X810|SM-X710|SM-X716B|SM-X510|SM-P619|SM-T225|SM-T225N|SM-T736B|SM-T505|SM-T733|SM-X205|SM-X210|SM-X216B", + "SM-X700|SM-X706|SM-X706B|SM-X706U|SM-X706N|SM-X800|SM-X806|SM-X806B|SM-X806U|SM-X806N|SM-X900|SM-X906|SM-X906B|SM-X906U|SM-X906N|SM-P613|SM-X110|SM-X115", + "SM-T970|SM-T380|SM-T5950|SM-T905|SM-T231|SM-T500|SM-T860|SM-T536|SM-T837A|SM-X200|SM-T220|SM-T870|SM-X906C", + "SM-T815Y|SM-T585|SM-T285|SM-T825|SM-W708|SM-T835|SM-T830|SM-T837V|SM-T720|SM-T510|SM-T387V|SM-P610|SM-T290|SM-T515|SM-T590|SM-T595|SM-T725|SM-T817P|SM-P585N0|SM-T395|SM-T295|SM-T865|SM-P610N|SM-P615", + "SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y?|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587|SM-P350|SM-P555M|SM-P355M|SM-T113NU", + "SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-T116BU|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715", + "SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237", + "GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X", + "GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X", + "SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210", + "GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L", + "SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113", + "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SM-X300|SM-T630" + ], + "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\\b|Android.*Silk\/[0-9.]+ like Chrome\/[0-9.]+ (?!Mobile)", + "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)", + "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10", + "AsusTablet": [ + "ME181C|P01Y|PO1MA|P01Z|\\bP027\\b|\\bP024\\b|\\bP00C\\b", + "\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K01A | K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C", + "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b" + ], + "BlackBerryTablet": "PlayBook|RIM Tablet", + "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410", + "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617", + "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2", + "AcerTablet": [ + "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b", + "W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20\\b|\\bA3-A30|A3-A40" + ], + "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO", + "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b", + "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b", + "PrestigioTablet": [ + "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C", + "PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD", + "PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002" + ], + "LenovoTablet": [ + "TB-X704L|TB-J606F|TB-X606F|TB-X306X|YT-J706X|TB128FU", + "YT3-X50M|YT-X705F|YT-X703F|YT-X703L|YT-X705L|YT-X705X|TB2-X30F|TB2-X30L|TB2-X30M|A2107A-F|A2107A-H|TB3-730F|TB3-730M|TB3-730X|TB-7504F|TB-7504X|TB-X704F|TB-X104F|TB3-X70F|TB-X705F|TB-8504F|TB3-X70L|TB3-710F", + "TB-X103F|TB-X304X|TB-X304F|TB-X304L|TB-X505F|TB-X505L|TB-X505X|TB-X605F|TB-X605L|TB-8703F|TB-8703X|TB-8703N|TB-8704N|TB-8704F|TB-8704X|TB-8704V|TB-7304F|TB-7304I|TB-7304X|Tab2A7-10F|Tab2A7-20F|TB2-X30L|YT3-X50L|YT3-X50F", + "Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-850M|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)" + ], + "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7", + "XiaomiTablet": "21051182G", + "YarvikTablet": [ + "Android.*\\b(TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b", + "Android.*\\b(TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211)\\b", + "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152)\\b" + ], + "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB", + "ArnovaTablet": "97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2", + "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004", + "IRUTablet": "M702pro", + "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b", + "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)", + "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)", + "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b", + "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark", + "NokiaLumiaTablet": "Lumia 2520", + "SonyTablet": [ + "EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP641|SGP612|SOT31|SGP771|SGP611|SGP612|SGP712", + "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321" + ], + "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b", + "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT", + "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010", + "MIDTablet": [ + "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800", + "MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10" + ], + "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b", + "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)", + "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A", + "FlyTablet": "IQ310|Fly Vision", + "bqTablet": "Android.*(bq)?.*\\b(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris ([E|M]10|M8))\\b|Maxwell.*Lite|Maxwell.*Plus", + "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim|M2-A01L|BAH-L09|BAH-W09|AGS-L09|CMR-AL19|KOB2-L09|BG2-U01|BG2-W09|BG2-U03|AGS-W09", + "NecTablet": "\\bN-06D|\\bN-08D", + "PantechTablet": "Pantech.*P4100", + "BronchoTablet": "Broncho.*(N701|N708|N802|a710)", + "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b", + "ZyncTablet": "z1000|Z99 2G|z930|z990|z909|Z919|z900", + "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA", + "NabiTablet": "Android.*\\bNabi", + "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build", + "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b", + "TexetTablet": [ + "TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE", + "TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD", + "TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A", + "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020" + ], + "PlaystationTablet": "Playstation.*(Portable|Vita)", + "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab", + "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b", + "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ", + "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1", + "GalapadTablet": "Android [0-9.]+; [a-z-]+; \\bG1\\b", + "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b", + "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b", + "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide", + "PROSCANTablet": [ + "\\b(PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b", + "\\b(PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082)\\b", + "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K)\\b" + ], + "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026", + "ChangJiaTablet": [ + "TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503", + "TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205", + "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106" + ], + "GUTablet": "TX-A1301|TX-M9002|Q702|kf026", + "PointOfViewTablet": [ + "TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10", + "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945" + ], + "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)|Qualcore 1027", + "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync", + "DPSTablet": "DPS Dream 9|DPS Dual 7", + "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10", + "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989", + "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b", + "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan", + "GoCleverTablet": [ + "TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042", + "TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2", + "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76" + ], + "ModecomTablet": [ + "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702", + "FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003" + ], + "VoninoTablet": [ + "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS)\\b", + "\\b(Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b" + ], + "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1", + "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab", + "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497|VFD 1400", + "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2", + "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711", + "iMobileTablet": "i-mobile i-note", + "TolinoTablet": "tolino tab [0-9.]+|tolino shine", + "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b", + "AMPETablet": "Android.* A78 ", + "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)", + "TecnoTablet": "TECNO P9|TECNO DP8D", + "JXDTablet": [ + "Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603)\\b", + "Android.* \\b(S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b" + ], + "iJoyTablet": [ + "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7)", + "Tablet (Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst)", + "Tablet (Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam)", + "Tablet (Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)" + ], + "FX2Tablet": "FX2 PAD7|FX2 PAD10", + "XoroTablet": [ + "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790", + "PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032", + "TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151" + ], + "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a", + "VerizonTablet": "QTAQZ3|QTAIR7|QTAQTZ3|QTASUN1|QTASUN2|QTAXIA1", + "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10", + "CaptivaTablet": "CAPTIVA PAD", + "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S", + "TeclastTablet": [ + "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G", + "\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G", + "\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b", + "\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b", + "\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b", + "\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi" + ], + "OndaTablet": [ + "\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811)\\b[\\s]+", + "\\b(V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819)\\b[\\s]+", + "\\b(V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+|V10 \\b4G\\b" + ], + "JaytechTablet": "TPC-PA762", + "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010", + "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b", + "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b", + "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b", + "AocTablet": "MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712", + "MpmanTablet": [ + "MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71", + "MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77", + "MP709|MID701|MID711|MID170|MPDC703|MPQC1010" + ], + "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b", + "WolderTablet": [ + "miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT)\\b", + "miTab \\b(EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND)\\b", + "miTab \\b(BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b" + ], + "MediacomTablet": "M-MPI10C3G|M-SP10EG|M-SP10EGP|M-SP10HXAH|M-SP7HXAH|M-SP10HXBH|M-SP8HXAH|M-SP8MXA", + "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b", + "NibiruTablet": "Nibiru M1|Nibiru Jupiter One", + "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI", + "LeaderTablet": [ + "TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G", + "TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100" + ], + "UbislateTablet": "UbiSlate[\\s]?7C", + "PocketBookTablet": "Pocketbook", + "KocasoTablet": "\\b(TB-1207)\\b", + "HisenseTablet": "\\b(F5281|E2371)\\b", + "Hudl": "Hudl HT7S3|Hudl 2", + "TelstraTablet": "T-Hub2", + "GenericTablet": [ + "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002", + "\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab", + "\\bM6pro\\b|CT1020W|arc 10HD|\\bTP750\\b|\\bQTAQZ3\\b|WVT101|TM1088|KT107" + ] + }, + "browsers": { + "Chrome": "\\bCrMo\\b|CriOS.*Mobile|Android.*Chrome\/[.0-9]* Mobile", + "Dolfin": "\\bDolfin\\b", + "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+$|Coast\/[0-9.]+", + "Skyfire": "Skyfire", + "Edge": "EdgiOS.*Mobile|Mobile Safari\/[.0-9]* Edge", + "IE": "IEMobile|MSIEMobile", + "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS.*Mobile", + "Bolt": "bolt", + "TeaShark": "teashark", + "Blazer": "Blazer", + "Safari": "Version((?!\\bEdgiOS\\b).)*Mobile.*Safari|Safari.*Mobile|MobileSafari", + "WeChat": "\\bMicroMessenger\\b", + "UCBrowser": "UC.*Browser|UCWEB", + "baiduboxapp": "baiduboxapp", + "baidubrowser": "baidubrowser", + "DiigoBrowser": "DiigoBrowser", + "Mercury": "\\bMercury\\b", + "ObigoBrowser": "Obigo", + "NetFront": "NF-Browser", + "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger", + "PaleMoon": "Android.*PaleMoon|Mobile.*PaleMoon", + "HuaweiBrowser": "HuaweiBrowser" + }, + "os": { + "AndroidOS": "Android", + "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os", + "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino", + "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b", + "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Windows Mobile|Windows Phone [0-9.]+|WCE;", + "WindowsPhoneOS": "Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;", + "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad|AppleCoreMedia", + "iPadOS": "CPU OS 13", + "SailfishOS": "Sailfish", + "MeeGoOS": "MeeGo", + "MaemoOS": "Maemo", + "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b", + "webOS": "webOS|hpwOS", + "badaOS": "\\bBada\\b", + "BREWOS": "BREW", + "HarmonyOS": "HarmonyOS" + } + } +} \ No newline at end of file diff --git a/tools/mobile_detect/mobiledetect/mobiledetectlib/README.md b/tools/mobile_detect/mobiledetect/mobiledetectlib/README.md new file mode 100644 index 000000000..ed31b5857 --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/README.md @@ -0,0 +1,63 @@ +![Mobile Detect](http://demo.mobiledetect.net/logo-github.png) + +MobileDetect, PHP mobile detection class +======================================== + +![Workflow status](https://img.shields.io/github/actions/workflow/status/serbanghita/Mobile-Detect/4.8.x-test.yml?style=flat-square) +![Latest tag](https://img.shields.io/github/v/tag/serbanghita/Mobile-Detect?filter=4.*&style=flat-square) +![Monthly Downloads](https://img.shields.io/packagist/dm/mobiledetect/mobiledetectlib?style=flat-square&label=installs) +![Total Downloads](https://img.shields.io/packagist/dt/mobiledetect/mobiledetectlib?style=flat-square&label=installs) +![MIT License](https://img.shields.io/packagist/l/mobiledetect/mobiledetectlib?style=flat-square) + +Mobile Detect is a lightweight PHP class for detecting mobile devices (including tablets). +It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment. + +## Before you install + +There are three versions of MobileDetect. +`4.8.x` is the main version that is ALWAYS going to be updated first. + +| Version | Tests | Namespace | Code | PHP Version | Status | +|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|------------------------------------------------------------------|-------------|----------------------| +| 2.8.x | [![5x](https://img.shields.io/github/actions/workflow/status/serbanghita/Mobile-Detect/2.8.x-test.yml?style=flat-square)](https://github.com/serbanghita/Mobile-Detect/actions/workflows/test.yml) | `\Mobile_Detect` | [2.8](https://github.com/serbanghita/Mobile-Detect/tree/2.8.x) | \>=5.0,<7.0 | Deprecated | +| 3.74.x | [![7x](https://img.shields.io/github/actions/workflow/status/serbanghita/Mobile-Detect/3.74.x-test.yml?style=flat-square)](https://github.com/serbanghita/Mobile-Detect/actions/workflows/test.yml) | `Detection\MobileDetect` | [3.74](https://github.com/serbanghita/Mobile-Detect/tree/3.74.x) | \>=7.4,<8.0 | LTS | +| 4.8.x | [![7x](https://img.shields.io/github/actions/workflow/status/serbanghita/Mobile-Detect/4.8.x-test.yml?style=flat-square)](https://github.com/serbanghita/Mobile-Detect/actions/workflows/test.yml) | `Detection\MobileDetect` | [4.8](https://github.com/serbanghita/Mobile-Detect/tree/4.8.x) | \>=8.0 | Current, **Recommended** | + +## 🤝 Supporting + +If you are using Mobile Detect open-source package in your production apps, in presentation demos, hobby projects, school projects or so, you can sponsor my work by [donating a small amount :+1:](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=mobiledetectlib%40gmail%2ecom&lc=US&item_name=Mobile%20Detect¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted). I'm currently paying for hosting and spend a lot of my family time to maintain the project and planning the future releases. I would highly appreciate any money donations. + +Special thanks to: + +* the community :+1: for donations, submitting patches and issues +* the JetBrains team for the open-source licenses for [PHPStorm IDE](https://www.jetbrains.com/phpstorm/) +* [Gitbook](https://www.gitbook.com/) team for the open-source license for their technical documentation tool. + + +## 📃 Documentation + +The entire documentation is available on Gitbook: [https://docs.mobiledetect.net](https://docs.mobiledetect.net) + +## 👾 Demo + +Point your device to: +[https://demo.mobiledetect.net](https://demo.mobiledetect.net) + +## 🐛 Testing + +``` bash +vendor/bin/phpunit -v -c tests/phpunit.xml --coverage-html .coverage +``` + +## 🤝 Contributing + +Please see the [Contribute guide](https://mobile-detect.gitbook.io/home/contribute) for details. + +## 🔒 Security + +If you discover any security related issues, please email serbanghita@gmail.com instead of using the issue tracker. + +## 🎉 Credits + +- [Serban Ghita](https://github.com/serbanghita) +- [All Contributors](https://mobile-detect.gitbook.io/home/credits) diff --git a/tools/mobile_detect/mobiledetect/mobiledetectlib/SECURITY.md b/tools/mobile_detect/mobiledetect/mobiledetectlib/SECURITY.md new file mode 100644 index 000000000..de43b5e39 --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/SECURITY.md @@ -0,0 +1,18 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +|---------| ------------------ | +| 2.8.x | :white_check_mark: | +| 3.74.x | :white_check_mark: | +| 4.8.x | :white_check_mark: | + +## Reporting a Vulnerability + +Please report all vulnerabilities to Serban Ghita ``. \ +The usual response time is 1 week for lower impact security reports. + +Also add an issue with explanation and links in order to keep track of the fix. + +Thank you! diff --git a/tools/mobile_detect/mobiledetect/mobiledetectlib/composer.json b/tools/mobile_detect/mobiledetect/mobiledetectlib/composer.json new file mode 100644 index 000000000..8e5f05ea5 --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/composer.json @@ -0,0 +1,41 @@ +{ + "name": "mobiledetect/mobiledetectlib", + "type": "library", + "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.", + "keywords": ["mobile", "mobile detect", "mobile detector", "php mobile detect", "detect mobile devices"], + "homepage": "https://github.com/serbanghita/Mobile-Detect", + "license": "MIT", + "authors": [ + { + "name": "Serban Ghita", + "email": "serbanghita@gmail.com", + "homepage": "http://mobiledetect.net", + "role": "Developer" + } + ], + "require": { + "php": ">=8.0", + "psr/simple-cache": "^3", + "psr/cache": "^3.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^v3.65.0", + "phpunit/phpunit": "^9.6.18", + "squizlabs/php_codesniffer": "^3.11.1", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.12.x-dev" + }, + "autoload": { + "psr-4": { + "Detection\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "DetectionTests\\": "tests/" + } + }, + "archive": { + "exclude": ["scripts"] + } +} diff --git a/tools/mobile_detect/mobiledetect/mobiledetectlib/docker-compose.yml b/tools/mobile_detect/mobiledetect/mobiledetectlib/docker-compose.yml new file mode 100644 index 000000000..2ff2cee3f --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/docker-compose.yml @@ -0,0 +1,62 @@ +services: + setup: + build: + context: . + dockerfile: ./docker/Dockerfile.setup + + runUnitTests: + # Need xdebug from this image to run with coverage + # https://hub.docker.com/r/alcohol/php/tags + image: alcohol/php:8.3-xdebug + depends_on: + setup: + condition: service_completed_successfully + working_dir: /app + environment: + XDEBUG_MODE: coverage + command: > + /bin/sh -c "vendor/bin/phpunit -v -c tests/phpunit.xml --coverage-html ./coverage --strict-coverage --stop-on-risky" + volumes: + - .:/app + + runPerfTests: + image: php:8.3-rc-alpine3.18 + depends_on: + setup: + condition: service_completed_successfully + working_dir: /app + command: > + /bin/sh -c "vendor/bin/phpbench run tests/benchmark/MobileDetectBench.php --retry-threshold=1 --iterations=10 --revs=1000 --report=aggregate" + volumes: + - .:/app + + runLinting: + image: php:8.3-rc-alpine3.18 + depends_on: + setup: + condition: service_completed_successfully + working_dir: /app + command: > + /bin/sh -c "vendor/bin/phpcs; vendor/bin/phpcbf" + volumes: + - .:/app + + generateModel: + image: php:8.3-rc-alpine3.18 + depends_on: + setup: + condition: service_completed_successfully + runUnitTests: + condition: service_completed_successfully + runPerfTests: + condition: service_completed_successfully + runLinting: + condition: service_completed_successfully + + working_dir: /app + command: > + /bin/sh -c "php ./scripts/export_to_json.php" + volumes: + - .:/app + + diff --git a/tools/mobile_detect/mobiledetect/mobiledetectlib/docker/Dockerfile.setup b/tools/mobile_detect/mobiledetect/mobiledetectlib/docker/Dockerfile.setup new file mode 100644 index 000000000..41d124509 --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/docker/Dockerfile.setup @@ -0,0 +1,9 @@ +FROM composer:latest AS build +WORKDIR /app +COPY . . +COPY ./docker/build.sh . +RUN pwd +# Make the script executable +SHELL ["/bin/bash", "-c"] +RUN chmod +x build.sh +RUN ./build.sh diff --git a/tools/mobile_detect/mobiledetect/mobiledetectlib/docker/build.sh b/tools/mobile_detect/mobiledetect/mobiledetectlib/docker/build.sh new file mode 100644 index 000000000..1a0cde6a0 --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/docker/build.sh @@ -0,0 +1,6 @@ +echo "Start building ..." +rm -rf vendor +rm -f composer.lock composer.phar +set -xe +# Install composer with dev dependencies so we can run tests. +composer install --dev diff --git a/tools/mobile_detect/mobiledetect/mobiledetectlib/phpbench.json b/tools/mobile_detect/mobiledetect/mobiledetectlib/phpbench.json new file mode 100644 index 000000000..0df230f5a --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/phpbench.json @@ -0,0 +1,4 @@ +{ + "$schema":"./vendor/phpbench/phpbench/phpbench.schema.json", + "runner.bootstrap": "vendor/autoload.php" +} diff --git a/tools/mobile_detect/mobiledetect/mobiledetectlib/src/Cache/Cache.php b/tools/mobile_detect/mobiledetect/mobiledetectlib/src/Cache/Cache.php new file mode 100644 index 000000000..0a08a612c --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/src/Cache/Cache.php @@ -0,0 +1,104 @@ +cache_db); + } + + /** + * @return array{string} + */ + public function getKeys(): array + { + return array_keys($this->cache_db); + } + + /** + * @throws CacheException + */ + public function get(string $key, mixed $default = null): CacheItem|null + { + if (empty($key)) { + throw new CacheException('Invalid cache key'); + } + + return $this->cache_db[$key] ?? null; + } + + /** + * @throws CacheException + */ + public function set(string $key, mixed $value, \DateInterval|int|null $ttl = null): bool + { + if (empty($key)) { + throw new CacheException('Invalid cache key'); + } + $item = new CacheItem($key, $value); + $item->expiresAfter($ttl); + $this->cache_db[$key] = $item; + return true; + } + + public function delete(string $key): bool + { + unset($this->cache_db[$key]); + return true; + } + + public function clear(): bool + { + $this->cache_db = []; + return true; + } + + public function getMultiple(iterable $keys, mixed $default = null): iterable + { + return array_reduce((array)$keys, function ($result, $key) { + $result[$key] = $this->get($key); + return $result; + }, []); + } + + /** + * @param array $values + * @param \DateInterval|int|null $ttl + * @return bool + * @throws CacheException + */ + public function setMultiple(iterable $values, \DateInterval|int|null $ttl = null): bool + { + foreach ($values as $key => $value) { + $this->set($key, $value, $ttl); + } + return true; + } + + public function deleteMultiple(iterable $keys): bool + { + foreach ($keys as $key) { + unset($this->cache_db[$key]); + } + return true; + } + + public function has(string $key): bool + { + return isset($this->cache_db[$key]); + } +} diff --git a/tools/mobile_detect/mobiledetect/mobiledetectlib/src/Cache/CacheException.php b/tools/mobile_detect/mobiledetect/mobiledetectlib/src/Cache/CacheException.php new file mode 100644 index 000000000..e23bcd8ac --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/src/Cache/CacheException.php @@ -0,0 +1,16 @@ + true) + */ + protected bool|null $value = null; + /** + * @var DateTimeInterface|null + */ + public DateTimeInterface|null $expiresAt = null; + /** + * @var DateInterval|null + */ + public DateInterval|null $expiresAfter = null; + + public function __construct($key, $value = null) + { + $this->key = $key; + if (!is_null($value)) { + $this->value = $value; + } + } + + /** + * @return string + */ + public function getKey(): string + { + return $this->key; + } + + /** + * @return bool|null + */ + public function get(): ?bool + { + return $this->value; + } + + /** + * @return bool + */ + public function isHit(): bool + { + // Item never expires. + if ($this->expiresAt === null && $this->expiresAfter === null) { + return true; + } + + if (!is_null($this->expiresAt) && $this->expiresAt > new DateTime()) { + return true; + } + + if (!is_null($this->expiresAfter)) { + try { + $future_date = (new DateTime())->add($this->expiresAfter); + } catch (\Exception $e) { + return false; + } + + if ($future_date > new DateTime()) { + return true; + } + } + + return false; + } + + /** + * @param mixed $value + * @return $this + */ + public function set(mixed $value): static + { + $this->value = $value; + return $this; + } + + /** + * @param \DateTimeInterface|null $expiration + * @return $this + */ + public function expiresAt(?\DateTimeInterface $expiration): static + { + $this->expiresAt = $expiration instanceof \DateTime ? $expiration : null; + + return $this; + } + + /** + * @param int|\DateInterval|null $time + * @return $this + */ + public function expiresAfter(\DateInterval|int|null $time): static + { + $expiresAfter = null; + + if ($time instanceof \DateInterval) { + $expiresAfter = $time; + } elseif (is_int($time)) { + if ($time > 0) { + $expiresAfter = new \DateInterval("PT{$time}S"); + } + } + + $this->expiresAfter = $expiresAfter; + + return $this; + } +} diff --git a/tools/mobile_detect/mobiledetect/mobiledetectlib/src/Exception/MobileDetectException.php b/tools/mobile_detect/mobiledetect/mobiledetectlib/src/Exception/MobileDetectException.php new file mode 100644 index 000000000..2667e9b9f --- /dev/null +++ b/tools/mobile_detect/mobiledetect/mobiledetectlib/src/Exception/MobileDetectException.php @@ -0,0 +1,7 @@ + (since 2012) + * @author Nick Ilyin + * @author: Victor Stanciu (original author) + * + * @version 4.8.09 + */ + +declare(strict_types=1); + +namespace Detection; + +use BadMethodCallException; +use Detection\Cache\Cache; +use Detection\Cache\CacheException; +use Detection\Exception\MobileDetectException; +use Psr\Cache\CacheItemInterface; +use Psr\Cache\InvalidArgumentException; +use Psr\SimpleCache\CacheInterface; + +/** + * Auto-generated isXXXX() magic methods. + * php export/dump_magic_methods.php + * + * @method bool isiPhone() + * @method bool isBlackBerry() + * @method bool isPixel() + * @method bool isHTC() + * @method bool isNexus() + * @method bool isDell() + * @method bool isMotorola() + * @method bool isSamsung() + * @method bool isLG() + * @method bool isSony() + * @method bool isAsus() + * @method bool isXiaomi() + * @method bool isNokiaLumia() + * @method bool isMicromax() + * @method bool isPalm() + * @method bool isVertu() + * @method bool isPantech() + * @method bool isFly() + * @method bool isWiko() + * @method bool isiMobile() + * @method bool isSimValley() + * @method bool isWolfgang() + * @method bool isAlcatel() + * @method bool isNintendo() + * @method bool isAmoi() + * @method bool isINQ() + * @method bool isOnePlus() + * @method bool isGenericPhone() + * @method bool isHuawei() + * @method bool isiPad() + * @method bool isNexusTablet() + * @method bool isGoogleTablet() + * @method bool isSamsungTablet() + * @method bool isKindle() + * @method bool isSurfaceTablet() + * @method bool isHPTablet() + * @method bool isAsusTablet() + * @method bool isBlackBerryTablet() + * @method bool isHTCtablet() + * @method bool isMotorolaTablet() + * @method bool isNookTablet() + * @method bool isAcerTablet() + * @method bool isToshibaTablet() + * @method bool isLGTablet() + * @method bool isFujitsuTablet() + * @method bool isPrestigioTablet() + * @method bool isLenovoTablet() + * @method bool isDellTablet() + * @method bool isYarvikTablet() + * @method bool isMedionTablet() + * @method bool isArnovaTablet() + * @method bool isIntensoTablet() + * @method bool isIRUTablet() + * @method bool isMegafonTablet() + * @method bool isEbodaTablet() + * @method bool isAllViewTablet() + * @method bool isArchosTablet() + * @method bool isAinolTablet() + * @method bool isNokiaLumiaTablet() + * @method bool isSonyTablet() + * @method bool isPhilipsTablet() + * @method bool isCubeTablet() + * @method bool isCobyTablet() + * @method bool isMIDTablet() + * @method bool isMSITablet() + * @method bool isSMiTTablet() + * @method bool isRockChipTablet() + * @method bool isFlyTablet() + * @method bool isbqTablet() + * @method bool isHuaweiTablet() + * @method bool isNecTablet() + * @method bool isPantechTablet() + * @method bool isBronchoTablet() + * @method bool isVersusTablet() + * @method bool isZyncTablet() + * @method bool isPositivoTablet() + * @method bool isNabiTablet() + * @method bool isKoboTablet() + * @method bool isDanewTablet() + * @method bool isTexetTablet() + * @method bool isPlaystationTablet() + * @method bool isTrekstorTablet() + * @method bool isPyleAudioTablet() + * @method bool isAdvanTablet() + * @method bool isDanyTechTablet() + * @method bool isGalapadTablet() + * @method bool isMicromaxTablet() + * @method bool isKarbonnTablet() + * @method bool isAllFineTablet() + * @method bool isPROSCANTablet() + * @method bool isYONESTablet() + * @method bool isChangJiaTablet() + * @method bool isGUTablet() + * @method bool isPointOfViewTablet() + * @method bool isOvermaxTablet() + * @method bool isHCLTablet() + * @method bool isDPSTablet() + * @method bool isVistureTablet() + * @method bool isCrestaTablet() + * @method bool isMediatekTablet() + * @method bool isConcordeTablet() + * @method bool isGoCleverTablet() + * @method bool isModecomTablet() + * @method bool isVoninoTablet() + * @method bool isECSTablet() + * @method bool isStorexTablet() + * @method bool isVodafoneTablet() + * @method bool isEssentielBTablet() + * @method bool isRossMoorTablet() + * @method bool isiMobileTablet() + * @method bool isTolinoTablet() + * @method bool isAudioSonicTablet() + * @method bool isAMPETablet() + * @method bool isSkkTablet() + * @method bool isTecnoTablet() + * @method bool isJXDTablet() + * @method bool isiJoyTablet() + * @method bool isFX2Tablet() + * @method bool isXoroTablet() + * @method bool isViewsonicTablet() + * @method bool isVerizonTablet() + * @method bool isOdysTablet() + * @method bool isCaptivaTablet() + * @method bool isIconbitTablet() + * @method bool isTeclastTablet() + * @method bool isOndaTablet() + * @method bool isJaytechTablet() + * @method bool isBlaupunktTablet() + * @method bool isDigmaTablet() + * @method bool isEvolioTablet() + * @method bool isLavaTablet() + * @method bool isAocTablet() + * @method bool isMpmanTablet() + * @method bool isCelkonTablet() + * @method bool isWolderTablet() + * @method bool isMediacomTablet() + * @method bool isMiTablet() + * @method bool isNibiruTablet() + * @method bool isNexoTablet() + * @method bool isLeaderTablet() + * @method bool isUbislateTablet() + * @method bool isPocketBookTablet() + * @method bool isKocasoTablet() + * @method bool isHisenseTablet() + * @method bool isHudl() + * @method bool isTelstraTablet() + * @method bool isGenericTablet() + * @method bool isAndroidOS() + * @method bool isBlackBerryOS() + * @method bool isPalmOS() + * @method bool isSymbianOS() + * @method bool isWindowsMobileOS() + * @method bool isWindowsPhoneOS() + * @method bool isiOS() + * @method bool isiPadOS() + * @method bool isSailfishOS() + * @method bool isMeeGoOS() + * @method bool isMaemoOS() + * @method bool isJavaOS() + * @method bool iswebOS() + * @method bool isbadaOS() + * @method bool isBREWOS() + * @method bool isHarmonyOS() + * @method bool isChrome() + * @method bool isDolfin() + * @method bool isOpera() + * @method bool isSkyfire() + * @method bool isEdge() + * @method bool isIE() + * @method bool isFirefox() + * @method bool isBolt() + * @method bool isTeaShark() + * @method bool isBlazer() + * @method bool isSafari() + * @method bool isWeChat() + * @method bool isUCBrowser() + * @method bool isbaiduboxapp() + * @method bool isbaidubrowser() + * @method bool isDiigoBrowser() + * @method bool isMercury() + * @method bool isObigoBrowser() + * @method bool isNetFront() + * @method bool isGenericBrowser() + * @method bool isPaleMoon() + * @method bool isHuaweiBrowser() + * @method bool isWebKit() + * @method bool isConsole() + * @method bool isWatch() + */ +class MobileDetect +{ + /** + * A cache for resolved matches + * Implementation of PSR-16: Common Interface for Caching Libraries + * https://www.php-fig.org/psr/psr-16/ + * + * Replace this with your own implementation. + */ + protected CacheInterface $cache; + + /** + * Stores the version number of the current release. + */ + protected string $VERSION = '4.8.09'; + + protected array $config = [ + // Auto-initialization on HTTP headers from $_SERVER['HTTP...'] + // Disable this if you're going for performance and set the + // User-Agent via $detect->setUserAgent("..."). + // @var boolean + 'autoInitOfHttpHeaders' => true, + // Maximum HTTP User-Agent value allowed. + // @var int + 'maximumUserAgentLength' => 500, + // Function that creates the cache key. e.g. (base64, sha1, custom fn). + // Note: used to be base64 but we went with sha1 because of fixed length. + 'cacheKeyFn' => 'sha1', + // Cache TTL + // @var null|int|\DateInterval + 'cacheTtl' => 86400, + ]; + + /** + * A frequently used regular expression to extract version #s. + */ + protected const VERSION_REGEX = '([\w._\+]+)'; + + /** + * A type for the version() method indicating a string return value. + */ + private const VERSION_TYPE_STRING = 'text'; + + /** + * A type for the version() method indicating a float return value. + */ + private const VERSION_TYPE_FLOAT = 'float'; + + /** + * The User-Agent HTTP header is stored in here. + * @var string|null + */ + protected ?string $userAgent = null; + + /** + * HTTP headers in the PHP-flavor. So HTTP_USER_AGENT and SERVER_SOFTWARE. + * @var array + */ + protected array $httpHeaders = []; + + /** + * CloudFront headers. E.g. CloudFront-Is-Desktop-Viewer, CloudFront-Is-Mobile-Viewer & CloudFront-Is-Tablet-Viewer. + * @var array + */ + protected static array $knownCloudFrontHeaders = [ + 'HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', + 'HTTP_CLOUDFRONT_IS_TABLET_VIEWER', + 'HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER' + ]; + + protected static string $cloudFrontUA = 'Amazon CloudFront'; + + /** + * The matching regex string. Used only for debugging. + * @var string + */ + protected string $matchingRegex = ""; + + /** + * The matches extracted from the regex expression. Used only for debugging. + * @var array + */ + protected array $matchesArray = []; + + /** + * HTTP headers that trigger the 'isMobile' detection to be true. + * @var array + */ + protected static array $knownMobilePositiveHeaders = [ + 'HTTP_ACCEPT' => [ + 'matches' => [ + // Opera Mini + // @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/ + 'application/x-obml2d', + // BlackBerry devices. + 'application/vnd.rim.html', + 'text/vnd.wap.wml', + 'application/vnd.wap.xhtml+xml' + ]], + 'HTTP_X_WAP_PROFILE' => null, + 'HTTP_X_WAP_CLIENTID' => null, + 'HTTP_WAP_CONNECTION' => null, + 'HTTP_PROFILE' => null, + // Reported by Opera on Nokia devices (e.g. C3). + 'HTTP_X_OPERAMINI_PHONE_UA' => null, + 'HTTP_X_NOKIA_GATEWAY_ID' => null, + 'HTTP_X_ORANGE_ID' => null, + 'HTTP_X_VODAFONE_3GPDPCONTEXT' => null, + 'HTTP_X_HUAWEI_USERID' => null, + // Reported by Windows Smartphones. + 'HTTP_UA_OS' => null, + // Reported by Verizon, Vodafone proxy system. + 'HTTP_X_MOBILE_GATEWAY' => null, + // Seen this on HTC Sensation. SensationXE_Beats_Z715e. + 'HTTP_X_ATT_DEVICEID' => null, + // Seen this on a HTC. + 'HTTP_UA_CPU' => ['matches' => ['ARM']], + // See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-UA-Mobile + // "?1" means that the device wants a "mobile" experience. + 'Sec-CH-UA-Mobile' => ['matches' => ['?1']], + ]; + + /** + * List of mobile devices (phones). + * @var array + */ + protected static array $phoneDevices = [ + 'iPhone' => '\biPhone\b|\biPod\b', // |\biTunes + 'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+|\b(BBA100|BBB100|BBD100|BBE100|BBF100|STH100)\b-[0-9]+', + 'Pixel' => '; \bPixel\b', + 'HTC' => [ + 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)', + 'APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200', + 'ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b|T-Mobile G1|Z520m|Android [0-9.]+; Pixel' + ], + 'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 5X|Nexus 6', + // @todo: Is 'Dell Streak' a tablet or a phone? ;) + 'Dell' => 'Dell[;]? (Streak|Aero|Venue|Venue Pro|Flash|Smoke|Mini 3iX)|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b', + 'Motorola' => [ + 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955', + 'A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611', + 'MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863', + 'ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317', + 'XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800', + 'XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\bMoto E\b|XT1068|XT1092|XT1052', + ], + 'Samsung' => [ + '\bSamsung\b|SM-G950F|SM-G955F|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310', + 'SM-F946B|SM-A127F', + 'SM-S908E|SM-G955N|SM-S918U1|SM-G998B|SM-G970N|SM-G973U|SM-S901U|SM-A515F|SM-S901E|SM-G980F|SM-S901B', + 'GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510', + 'GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K', + 'GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010', + 'GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100', + 'GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210', + 'GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250', + 'GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420', + 'GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700', + 'GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103', + 'GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800', + 'GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210', + 'GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350', + 'GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660', + 'GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230', + 'GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600', + 'SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930', + 'SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730', + 'SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351', + 'SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430', + 'SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740', + 'SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157', + 'SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657', + 'SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817', + 'SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220', + 'SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225', + 'SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105', + 'SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200', + 'SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717', + 'SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917', + 'SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500', + 'SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777', + 'SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229', + 'SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409', + 'SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609', + 'SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749', + 'SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200', + 'SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497', + 'SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10', + 'SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700', + 'SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700', + 'SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220', + 'SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550', + 'SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920', + 'SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535', + 'SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510', + 'GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582', + 'GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K', + 'SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558', + 'GT-I9205|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C|SM-A310F|GT-I9190|SM-J500FN|SM-G903F|SM-J330F', + 'SM-G610F|SM-G981B|SM-G892A|SM-A530F|SM-G988N|SM-G781B|SM-A805N|SM-G965F', + ], + 'LG' => [ + '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200)', + 'LG[- ]?(MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK)', + 'LG[- ]?(E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690)', + 'LG[- ]?(MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740)', + 'LG[- ]?(VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323|M257)|LM-G710', + ], + 'Sony' => [ + 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i', + 'C5303|C6902|C6903|C6906|C6943|D2533|SOV34|601SO|F8332', + ], + 'Asus' => 'Asus.*Galaxy|PadFone.*Mobile|ASUS_Z01QD|ASUS_X00TD', + 'Xiaomi' => [ + '^(?!.*\bx11\b).*xiaomi.*$|POCOPHONE F1|\bMI\b 8|\bMi\b 10|Redmi Note 9S|Redmi 5A|Redmi Note 5A Prime|Redmi Note 7 Pro', + 'N2G47H|M2001J2G|M2001J2I|M1805E10A|M2004J11G|M1902F1G|M2002J9G|M2004J19G|M2003J6A1G|M2012K11C|M2007J1SC', + ], + 'NokiaLumia' => 'Lumia [0-9]{3,4}', + // http://www.micromaxinfo.com/mobiles/smartphones + // Added because the codes might conflict with Acer Tablets. + 'Micromax' => 'Micromax.*\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\b', + // @todo Complete the regex. + 'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ; + // Just for fun ;) + 'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', + // http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH) + // Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android. + 'Pantech' => [ + 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L', + 'IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S', + 'IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995', + 'IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790', + ], + // http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones. + 'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250', + // http://fr.wikomobile.com + 'Wiko' => [ + 'KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY', + 'BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM' + ], + 'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)', + // Added simvalley mobile just for fun. They have some interesting devices. + // http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html + 'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b', + // Wolfgang - a brand that is sold by Aldi supermarkets. + // http://www.wolfgangmobile.com/ + 'Wolfgang' => 'AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q', + 'Alcatel' => 'Alcatel', + 'Nintendo' => 'Nintendo (3DS|Switch)', + // http://en.wikipedia.org/wiki/Amoi + 'Amoi' => 'Amoi', + // http://en.wikipedia.org/wiki/INQ + 'INQ' => 'INQ', + 'OnePlus' => 'ONEPLUS|CPH2663', + // @Tapatalk is a mobile app; http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039 + 'GenericPhone' => 'Tapatalk|PDA;|SAGEM|\bmmp\b|pocket|\bpsp\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\bwap\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser', + 'Huawei' => 'HMSCore|Huawei', + ]; + + /** + * List of tablet devices. + * @var array + */ + protected static array $tabletDevices = [ + // @todo: check for mobile friendly emails topic. + 'iPad' => 'iPad|iPad.*Mobile', + // Removed |^.*Android.*Nexus(?!(?:Mobile).)*$ + // @see #442 + // @todo Merge NexusTablet into GoogleTablet. + 'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)', + // https://en.wikipedia.org/wiki/Pixel_C + 'GoogleTablet' => 'Android.*Pixel C', + 'SamsungTablet' => [ + 'SM-X616B|SM-X610|SM-X516B|SM-X910|SM-X916B|SM-X816B|SM-X810|SM-X710|SM-X716B|SM-X510|SM-P619|SM-T225|SM-T225N|SM-T736B|SM-T505|SM-T733|SM-X205|SM-X210|SM-X216B', + 'SM-X700|SM-X706|SM-X706B|SM-X706U|SM-X706N|SM-X800|SM-X806|SM-X806B|SM-X806U|SM-X806N|SM-X900|SM-X906|SM-X906B|SM-X906U|SM-X906N|SM-P613|SM-X110|SM-X115', + 'SM-T970|SM-T380|SM-T5950|SM-T905|SM-T231|SM-T500|SM-T860|SM-T536|SM-T837A|SM-X200|SM-T220|SM-T870|SM-X906C', // SCH-P709|SCH-P729|SM-T2558|GT-I9205 - Samsung Mega - treat them like a regular phone. + 'SM-T815Y|SM-T585|SM-T285|SM-T825|SM-W708|SM-T835|SM-T830|SM-T837V|SM-T720|SM-T510|SM-T387V|SM-P610|SM-T290|SM-T515|SM-T590|SM-T595|SM-T725|SM-T817P|SM-P585N0|SM-T395|SM-T295|SM-T865|SM-P610N|SM-P615', + 'SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y?|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587|SM-P350|SM-P555M|SM-P355M|SM-T113NU', + 'SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-T116BU|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715', + 'SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237', + 'GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X', + 'GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X', + 'SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210', + 'GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L', + 'SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113', + 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SM-X300|SM-T630', + ], + // http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html + 'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\b|Android.*Silk/[0-9.]+ like Chrome/[0-9.]+ (?!Mobile)', + // Only the Surface tablets with Windows RT are considered mobile. + // http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx + 'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)', + // http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT + 'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10', + // Watch out for PadFone, see #132. + // http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/ + 'AsusTablet' => [ + 'ME181C|P01Y|PO1MA|P01Z|\bP027\b|\bP024\b|\bP00C\b', + '\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG|ME302KL| K01A | K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\bME70C\b|ME581C|ME581CL|ME8510C', + '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b', + ], + 'BlackBerryTablet' => 'PlayBook|RIM Tablet', + 'HTCtablet' => 'HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410', + 'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617', + 'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2', + // http://www.acer.ro/ac/ro/RO/content/drivers + // http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer) + // http://us.acer.com/ac/en/US/content/group/tablets + // http://www.acer.de/ac/de/DE/content/models/tablets/ + // Can conflict with Micromax and Motorola phones codes. + 'AcerTablet' => [ + 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b', + 'W3-810|\bA3-A10\b|\bA3-A11\b|\bA3-A20\b|\bA3-A30|A3-A40' + ], + // http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/ + // http://us.toshiba.com/tablets/tablet-finder + // http://www.toshiba.co.jp/regza/tablet/ + 'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO', + // http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html + // http://www.lg.com/us/tablets + 'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b', + 'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b', + // Prestigio Tablets http://www.prestigio.com/support + 'PrestigioTablet' => [ + 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C', + 'PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD', + 'PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002', + ], + // http://support.lenovo.com/en_GB/downloads/default.page?# + 'LenovoTablet' => [ + 'TB-X704L|TB-J606F|TB-X606F|TB-X306X|YT-J706X|TB128FU', + 'YT3-X50M|YT-X705F|YT-X703F|YT-X703L|YT-X705L|YT-X705X|TB2-X30F|TB2-X30L|TB2-X30M|A2107A-F|A2107A-H|TB3-730F|TB3-730M|TB3-730X|TB-7504F|TB-7504X|TB-X704F|TB-X104F|TB3-X70F|TB-X705F|TB-8504F|TB3-X70L|TB3-710F', + 'TB-X103F|TB-X304X|TB-X304F|TB-X304L|TB-X505F|TB-X505L|TB-X505X|TB-X605F|TB-X605L|TB-8703F|TB-8703X|TB-8703N|TB-8704N|TB-8704F|TB-8704X|TB-8704V|TB-7304F|TB-7304I|TB-7304X|Tab2A7-10F|Tab2A7-20F|TB2-X30L|YT3-X50L|YT3-X50F', + 'Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-850M|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)', + ], + // http://www.dell.com/support/home/us/en/04/Products/tab_mob/tablets + 'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7', + 'XiaomiTablet' => '21051182G', + // http://www.yarvik.com/en/matrix/tablets/ + 'YarvikTablet' => [ + 'Android.*\b(TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b', + 'Android.*\b(TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211)\b', + 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152)\b', + ], + 'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB', + 'ArnovaTablet' => '97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2', + // http://www.intenso.de/kategorie_en.php?kategorie=33 + // @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate + 'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004', + // IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/ + 'IRUTablet' => 'M702pro', + 'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b', + // http://www.e-boda.ro/tablete-pc.html + 'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)', + // http://www.allview.ro/produse/droseries/lista-tablete-pc/ + 'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)', + // http://wiki.archosfans.com/index.php?title=Main_Page + // @note Rewrite the regex format after we add more UAs. + 'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b', + // http://www.ainol.com/plugin.php?identifier=ainol&module=product + 'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark', + 'NokiaLumiaTablet' => 'Lumia 2520', + // @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER + // Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser + // http://www.sony.jp/support/tablet/ + 'SonyTablet' => [ + 'EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP641|SGP612|SOT31|SGP771|SGP611|SGP612|SGP712', + 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321', + ], + // http://www.support.philips.com/support/catalog/worldproducts.jsp?userLanguage=en&userCountry=cn&categoryid=3G_LTE_TABLET_SU_CN_CARE&title=3G%20tablets%20/%20LTE%20range&_dyncharset=UTF-8 + 'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b', + // db + http://www.cube-tablet.com/buy-products.html + 'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT', + // http://www.cobyusa.com/?p=pcat&pcat_id=3001 + 'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010', + // http://www.match.net.cn/products.asp + 'MIDTablet' => [ + 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800', + 'MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10', + ], + // http://www.msi.com/support + // @todo Research the Windows Tablets. + 'MSITablet' => 'MSI \b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\b', + // @todo http://www.kyoceramobile.com/support/drivers/ + // 'KyoceraTablet' => null, + // @todo http://intexuae.com/index.php/category/mobile-devices/tablets-products/ + // 'IntextTablet' => null, + // http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets) + // http://www.imp3.net/14/show.php?itemid=20454 + 'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)', + // http://www.rock-chips.com/index.php?do=prod&pid=2 + 'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A', + // http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/ + 'FlyTablet' => 'IQ310|Fly Vision', + // http://www.bqreaders.com/gb/tablets-prices-sale.html + 'bqTablet' => 'Android.*(bq)?.*\b(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris ([E|M]10|M8))\b|Maxwell.*Lite|Maxwell.*Plus', + // http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290 + // http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets) + 'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim|M2-A01L|BAH-L09|BAH-W09|AGS-L09|CMR-AL19|KOB2-L09|BG2-U01|BG2-W09|BG2-U03|AGS-W09', + // Nec or Medias Tab + 'NecTablet' => '\bN-06D|\bN-08D', + // Pantech Tablets: http://www.pantechusa.com/phones/ + 'PantechTablet' => 'Pantech.*P4100', + // Broncho Tablets: http://www.broncho.cn/ (hard to find) + 'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)', + // http://versusuk.com/support.html + 'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b', + // http://www.zync.in/index.php/our-products/tablet-phablets + 'ZyncTablet' => 'z1000|Z99 2G|z930|z990|z909|Z919|z900', // Removed "z999" because of https://github.com/serbanghita/Mobile-Detect/issues/717 + // http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/ + 'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA', + // https://www.nabitablet.com/ + 'NabiTablet' => 'Android.*\bNabi', + 'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build', + // French Danew Tablets http://www.danew.com/produits-tablette.php + 'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b', + // Texet Tablets and Readers http://www.texet.ru/tablet/ + 'TexetTablet' => [ + 'TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE', + 'TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD', + 'TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A', + 'NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020', + ], + // Avoid detecting 'PLAYSTATION 3' as mobile. + 'PlaystationTablet' => 'Playstation.*(Portable|Vita)', + // http://www.trekstor.de/surftabs.html + 'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab', + // http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets + 'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b', + // http://www.advandigital.com/index.php?link=content-product&jns=JP001 + // because of the short codenames we have to include whitespaces to reduce the possible conflicts. + 'AdvanTablet' => 'Android.* \b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\b ', + // http://www.danytech.com/category/tablet-pc + 'DanyTechTablet' => 'Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1', + // http://www.galapad.net/product.html ; https://github.com/serbanghita/Mobile-Detect/issues/761 + 'GalapadTablet' => 'Android [0-9.]+; [a-z-]+; \bG1\b', + // http://www.micromaxinfo.com/tablet/funbook + 'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b', + // http://www.karbonnmobiles.com/products_tablet.php + 'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b', + // http://www.myallfine.com/Products.asp + 'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide', + // http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr= + 'PROSCANTablet' => [ + '\b(PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\b', + '\b(PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082)\b', + '\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K)\b', + ], + // http://www.yonesnav.com/products/products.php + 'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026', + // http://www.cjshowroom.com/eproducts.aspx?classcode=004001001 + // China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html) + 'ChangJiaTablet' => [ + 'TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503', + 'TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205', + 'TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106', + ], + // http://www.gloryunion.cn/products.asp + // http://www.allwinnertech.com/en/apply/mobile.html + // http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB) + // @todo: Softwiner tablets? + // aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions. + 'GUTablet' => 'TX-A1301|TX-M9002|Q702|kf026', // A12R|D75A|D77|D79|R83|A95|A106C|R15|A75|A76|D71|D72|R71|R73|R77|D82|R85|D92|A97|D92|R91|A10F|A77F|W71F|A78F|W78F|W81F|A97F|W91F|W97F|R16G|C72|C73E|K72|K73|R96G + // http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118 + 'PointOfViewTablet' => [ + 'TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10', + 'TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945', + ], + // http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/ + // @todo: add more tests. + 'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)|Qualcore 1027', + // http://hclmetablet.com/India/index.php + 'HCLTablet' => 'HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync', + // http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html + 'DPSTablet' => 'DPS Dream 9|DPS Dual 7', + // http://www.visture.com/index.asp + 'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10', + // http://www.mijncresta.nl/tablet + 'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989', + // MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309 + 'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b', + // Concorde tab + 'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan', + // GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/ + 'GoCleverTablet' => [ + 'TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042', + 'TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2', + 'GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76', + ], + // Modecom Tablets - http://www.modecom.eu/tablets/portal/ + 'ModecomTablet' => [ + 'FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702', + 'FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003', + ], + // Vonino Tablets + 'VoninoTablet' => [ + '\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS)\b', + '\b(Android.*\bQ8\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\b', + ], + // ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0 + 'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1', + // Storex Tablets - http://storex.fr/espace_client/support.html + // @note: no need to add all the tablet codes since they are guided by the first regex. + 'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab', + // Generic Vodafone tablets. + 'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497|VFD 1400', + // French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb + // Aka: http://www.essentielb.fr/ + 'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2', + // Ross & Moor - http://ross-moor.ru/ + 'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711', + // i-mobile http://product.i-mobilephone.com/Mobile_Device + 'iMobileTablet' => 'i-mobile i-note', + // http://www.tolino.de/de/vergleichen/ + 'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine', + // AudioSonic - a Kmart brand + // http://www.kmart.com.au/webapp/wcs/stores/servlet/Search?langId=-1&storeId=10701&catalogId=10001&categoryId=193001&pageSize=72¤tPage=1&searchCategory=193001%2b4294965664&sortBy=p_MaxPrice%7c1 + 'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b', + // AMPE Tablets - http://www.ampe.com.my/product-category/tablets/ + // @todo: add them gradually to avoid conflicts. + 'AMPETablet' => 'Android.* A78 ', + // Skk Mobile - http://skkmobile.com.ph/product_tablets.php + 'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)', + // Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1 + 'TecnoTablet' => 'TECNO P9|TECNO DP8D', + // JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3 + 'JXDTablet' => [ + 'Android.* \b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603)\b', + 'Android.* \b(S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b', + ], + // i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/ + 'iJoyTablet' => [ + 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7)', + 'Tablet (Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst)', + 'Tablet (Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam)', + 'Tablet (Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)', + ], + // http://www.intracon.eu/tablet + 'FX2Tablet' => 'FX2 PAD7|FX2 PAD10', + // http://www.xoro.de/produkte/ + // @note: Might be the same brand with 'Simply tablets' + 'XoroTablet' => [ + 'KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790', + 'PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032', + 'TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151', + ], + // http://www1.viewsonic.com/products/computing/tablets/ + 'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a', + // https://www.verizonwireless.com/tablets/verizon/ + 'VerizonTablet' => 'QTAQZ3|QTAIR7|QTAQTZ3|QTASUN1|QTASUN2|QTAXIA1', + // http://www.odys.de/web/internet-tablet_en.html + 'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10', + // http://www.captiva-power.de/products.html#tablets-en + 'CaptivaTablet' => 'CAPTIVA PAD', + // IconBIT - http://www.iconbit.com/products/tablets/ + 'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S', + // http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63 + 'TeclastTablet' => [ + 'T98 4G|\bP80\b|\bX90HD\b|X98 Air|X98 Air 3G|\bX89\b|P80 3G|\bX80h\b|P98 Air|\bX89HD\b|P98 3G|\bP90HD\b|P89 3G|X98 3G', + '\bP70h\b|P79HD 3G|G18d 3G|\bP79HD\b|\bP89s\b|\bA88\b|\bP10HD\b|\bP19HD\b|G18 3G|\bP78HD\b|\bA78\b|\bP75\b|G17s 3G|G17h 3G', + '\bP85t\b|\bP90\b|\bP11\b|\bP98t\b|\bP98HD\b|\bG18d\b|\bP85s\b|\bP11HD\b|\bP88s\b|\bA80HD\b|\bA80se\b|\bA10h\b|\bP89\b', + '\bP78s\b|\bG18\b|\bP85\b|\bA70h\b|\bA70\b|\bG17\b|\bP18\b|\bA80s\b|\bA11s\b|\bP88HD\b|\bA80h\b|\bP76s\b|\bP76h\b|\bP98\b', + '\bA10HD\b|\bP78\b|\bP88\b|\bA11\b|\bA10t\b|\bP76a\b|\bP76t\b|\bP76e\b|\bP85HD\b|\bP85a\b|\bP86\b|\bP75HD\b|\bP76v\b|\bA12\b', + '\bP75a\b|\bA15\b|\bP76Ti\b|\bP81HD\b|\bA10\b|\bT760VE\b|\bT720HD\b|\bP76\b|\bP73\b|\bP71\b|\bP72\b|\bT720SE\b|\bC520Ti\b|\bT760\b|\bT720VE\b|T720-3GE|T720-WiFi', + ], + // Onda - http://www.onda-tablet.com/buy-android-onda.html?dir=desc&limit=all&order=price + 'OndaTablet' => [ + '\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811)\b[\s]+', + '\b(V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819)\b[\s]+', + '\b(V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\b[\s]+|V10 \b4G\b', + ], + 'JaytechTablet' => 'TPC-PA762', + 'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010', + // http://www.digma.ru/support/download/ + // @todo: Ebooks also (if requested) + 'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b', + // http://www.evolioshop.com/ro/tablete-pc.html + // http://www.evolio.ro/support/downloads_static.html?cat=2 + // @todo: Research some more + 'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b', + // @todo http://www.lavamobiles.com/tablets-data-cards + 'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY|\bE-TAB\b', + // http://www.breezetablet.com/ + 'AocTablet' => 'MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712', + // http://www.mpmaneurope.com/en/products/internet-tablets-14/android-tablets-14/ + 'MpmanTablet' => [ + 'MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\bMPG7\b|MPDCG75|MPDCG71', + 'MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77', + 'MP709|MID701|MID711|MID170|MPDC703|MPQC1010', + ], + // https://www.celkonmobiles.com/?_a=categoryphones&sid=2 + 'CelkonTablet' => 'CT695|CT888|CT[\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\bCT-1\b', + // http://www.wolderelectronics.com/productos/manuales-y-guias-rapidas/categoria-2-miTab + 'WolderTablet' => [ + 'miTab \b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT)\b', + 'miTab \b(EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND)\b', + 'miTab \b(BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\b', + ], + 'MediacomTablet' => 'M-MPI10C3G|M-SP10EG|M-SP10EGP|M-SP10HXAH|M-SP7HXAH|M-SP10HXBH|M-SP8HXAH|M-SP8MXA', + // http://www.mi.com/en + 'MiTablet' => '\bMI PAD\b|\bHM NOTE 1W\b', + // http://www.nbru.cn/index.html + 'NibiruTablet' => 'Nibiru M1|Nibiru Jupiter One', + // http://navroad.com/products/produkty/tablety/ + // http://navroad.com/products/produkty/tablety/ + 'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI', + // http://leader-online.com/new_site/product-category/tablets/ + // http://www.leader-online.net.au/List/Tablet + 'LeaderTablet' => [ + 'TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G', + 'TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100', + ], + // http://www.datawind.com/ubislate/ + 'UbislateTablet' => 'UbiSlate[\s]?7C', + // http://www.pocketbook-int.com/ru/support + 'PocketBookTablet' => 'Pocketbook', + // http://www.kocaso.com/product_tablet.html + 'KocasoTablet' => '\b(TB-1207)\b', + // http://global.hisense.com/product/asia/tablet/Sero7/201412/t20141215_91832.htm + 'HisenseTablet' => '\b(F5281|E2371)\b', + // http://www.tesco.com/direct/hudl/ + 'Hudl' => 'Hudl HT7S3|Hudl 2', + // http://www.telstra.com.au/home-phone/thub-2/ + 'TelstraTablet' => 'T-Hub2', + 'GenericTablet' => [ + 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002', + '\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab', + '\bM6pro\b|CT1020W|arc 10HD|\bTP750\b|\bQTAQZ3\b|WVT101|TM1088|KT107', + ], + ]; + + /** + * List of mobile Operating Systems. + * @var array + */ + protected static array $operatingSystems = [ + 'AndroidOS' => 'Android', + 'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os', + 'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino', + 'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b', + // @reference: http://en.wikipedia.org/wiki/Windows_Mobile + 'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Windows Mobile|Windows Phone [0-9.]+|WCE;', + // @reference: http://en.wikipedia.org/wiki/Windows_Phone + // http://wifeng.cn/?r=blog&a=view&id=106 + // http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx + // http://msdn.microsoft.com/library/ms537503.aspx + // https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx + 'WindowsPhoneOS' => 'Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;', + 'iOS' => '\biPhone.*Mobile|\biPod|\biPad|AppleCoreMedia', + // https://en.wikipedia.org/wiki/IPadOS + 'iPadOS' => 'CPU OS 13', + // @reference https://en.m.wikipedia.org/wiki/Sailfish_OS + // https://sailfishos.org/ + 'SailfishOS' => 'Sailfish', + // http://en.wikipedia.org/wiki/MeeGo + // @todo: research MeeGo in UAs + 'MeeGoOS' => 'MeeGo', + // http://en.wikipedia.org/wiki/Maemo + // @todo: research Maemo in UAs + 'MaemoOS' => 'Maemo', + 'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135 + 'webOS' => 'webOS|hpwOS', + 'badaOS' => '\bBada\b', + 'BREWOS' => 'BREW', + 'HarmonyOS' => 'HarmonyOS', + ]; + + /** + * List of mobile User Agents. + * + * IMPORTANT: This is a list of mobile browsers only. + * Since Mobile Detect 2.x.x, this list supports mobile browsers only. + * Mobile Detect was never designed to detect all browsers. + * @var array + */ + protected static array $browsers = [ + //'Vivaldi' => 'Vivaldi', + // @reference: https://developers.google.com/chrome/mobile/docs/user-agent + 'Chrome' => '\bCrMo\b|CriOS.*Mobile|Android.*Chrome/[.0-9]* Mobile', + 'Dolfin' => '\bDolfin\b', + 'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+$|Coast/[0-9.]+', + 'Skyfire' => 'Skyfire', + // Added "Edge on iOS" https://github.com/serbanghita/Mobile-Detect/issues/764 + 'Edge' => 'EdgiOS.*Mobile|Mobile Safari/[.0-9]* Edge', + 'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+ + 'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS.*Mobile', + 'Bolt' => 'bolt', + 'TeaShark' => 'teashark', + 'Blazer' => 'Blazer', + // @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3 + // Excluded "Edge on iOS" https://github.com/serbanghita/Mobile-Detect/issues/764 + 'Safari' => 'Version((?!\bEdgiOS\b).)*Mobile.*Safari|Safari.*Mobile|MobileSafari', + // http://en.wikipedia.org/wiki/Midori_(web_browser) + //'Midori' => 'midori', + //'Tizen' => 'Tizen', + 'WeChat' => '\bMicroMessenger\b', + 'UCBrowser' => 'UC.*Browser|UCWEB', + 'baiduboxapp' => 'baiduboxapp', + 'baidubrowser' => 'baidubrowser', + // https://github.com/serbanghita/Mobile-Detect/issues/7 + 'DiigoBrowser' => 'DiigoBrowser', + // http://www.puffinbrowser.com/index.php + // https://github.com/serbanghita/Mobile-Detect/issues/752 + // 'Puffin' => 'Puffin', + // http://mercury-browser.com/index.html + 'Mercury' => '\bMercury\b', + // http://en.wikipedia.org/wiki/Obigo_Browser + 'ObigoBrowser' => 'Obigo', + // http://en.wikipedia.org/wiki/NetFront + 'NetFront' => 'NF-Browser', + // @reference: http://en.wikipedia.org/wiki/Minimo + // http://en.wikipedia.org/wiki/Vision_Mobile_Browser + 'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger', + // @reference: https://en.wikipedia.org/wiki/Pale_Moon_(web_browser) + 'PaleMoon' => 'Android.*PaleMoon|Mobile.*PaleMoon', + 'HuaweiBrowser' => 'HuaweiBrowser', + ]; + + /** + * All possible HTTP headers that represent the + * User-Agent string. + * @var array + */ + protected static array $knownUserAgentHttpHeaders = [ + // The default User-Agent string. + 'HTTP_USER_AGENT', + // Header can occur on devices using Opera Mini. + 'HTTP_X_OPERAMINI_PHONE_UA', + // Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/ + 'HTTP_X_DEVICE_USER_AGENT', + 'HTTP_X_ORIGINAL_USER_AGENT', + 'HTTP_X_SKYFIRE_PHONE', + 'HTTP_X_BOLT_PHONE_UA', + 'HTTP_DEVICE_STOCK_UA', + 'HTTP_X_UCBROWSER_DEVICE_UA' + ]; + + /** + * The individual segments that could exist in a User-Agent string. VER refers to the regular + * expression defined in the constant self::VERSION_REGEX. + * @var array + */ + protected static array $properties = [ + + // Build + 'Mobile' => 'Mobile/[VER]', + 'Build' => 'Build/[VER]', + 'Version' => 'Version/[VER]', + 'VendorID' => 'VendorID/[VER]', + + // Devices + 'iPad' => 'iPad.*CPU[a-z ]+[VER]', + 'iPhone' => 'iPhone.*CPU[a-z ]+[VER]', + 'iPod' => 'iPod.*CPU[a-z ]+[VER]', + //'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'), + 'Kindle' => 'Kindle/[VER]', + + // Browser + 'Chrome' => ['Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'], + 'Coast' => ['Coast/[VER]'], + 'Dolfin' => 'Dolfin/[VER]', + // @reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent/Firefox + 'Firefox' => ['Firefox/[VER]', 'FxiOS/[VER]'], + 'Fennec' => 'Fennec/[VER]', + // http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx + // https://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx + 'Edge' => 'Edge/[VER]', + 'IE' => ['IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'Trident/[0-9.]+;.*rv:[VER]'], + // http://en.wikipedia.org/wiki/NetFront + 'NetFront' => 'NetFront/[VER]', + 'NokiaBrowser' => 'NokiaBrowser/[VER]', + 'Opera' => [' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]'], + 'Opera Mini' => 'Opera Mini/[VER]', + 'Opera Mobi' => 'Version/[VER]', + 'UCBrowser' => ['UCWEB[VER]', 'UC.*Browser/[VER]'], + 'MQQBrowser' => 'MQQBrowser/[VER]', + 'MicroMessenger' => 'MicroMessenger/[VER]', + 'baiduboxapp' => 'baiduboxapp/[VER]', + 'baidubrowser' => 'baidubrowser/[VER]', + 'SamsungBrowser' => 'SamsungBrowser/[VER]', + 'Iron' => 'Iron/[VER]', + // @note: Safari 7534.48.3 is actually Version 5.1. + // @note: On BlackBerry the Version is overwriten by the OS. + 'Safari' => ['Version/[VER]', 'Safari/[VER]'], + 'Skyfire' => 'Skyfire/[VER]', + 'Tizen' => 'Tizen/[VER]', + 'Webkit' => 'webkit[ /][VER]', + 'PaleMoon' => 'PaleMoon/[VER]', + 'SailfishBrowser' => 'SailfishBrowser/[VER]', + + // Engine + 'Gecko' => 'Gecko/[VER]', + 'Trident' => 'Trident/[VER]', + 'Presto' => 'Presto/[VER]', + 'Goanna' => 'Goanna/[VER]', + + // OS + 'iOS' => ' \bi?OS\b [VER][ ;]{1}', + 'Android' => 'Android [VER]', + 'Sailfish' => 'Sailfish [VER]', + 'BlackBerry' => ['BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'], + 'BREW' => 'BREW [VER]', + 'Java' => 'Java/[VER]', + // @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx + // @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases + 'Windows Phone OS' => ['Windows Phone OS [VER]', 'Windows Phone [VER]'], + 'Windows Phone' => 'Windows Phone [VER]', + 'Windows CE' => 'Windows CE/[VER]', + // http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd + 'Windows NT' => 'Windows NT [VER]', + 'Symbian' => ['SymbianOS/[VER]', 'Symbian/[VER]'], + 'webOS' => ['webOS/[VER]', 'hpwOS/[VER];'], + ]; + + /** + * Construct an instance of this class. + */ + public function __construct( + ?CacheInterface $cache = null, + array $config = [], + ) { + // If no custom cache provided then use our own. + $this->cache = $cache ?? new Cache(); + // Override config from user. + $this->config = array_merge($this->config, $config); + + // Beware that if you use "autoInitOfHttpHeaders: false" and you forget to setUserAgent + // to something other than a string, an MobileDetectException exception will be thrown. + if ($this->config['autoInitOfHttpHeaders']) { + $this->autoInitKnownHttpHeaders(); + } + } + + /** + * Get the current script version. + * Used in demo.php file. + * + * @return string The version number in semantic version format. + */ + public function getVersion(): string + { + return $this->VERSION; + } + + /** + * On startup Mobile Detect library will auto-initiate from the existing + * HTTP headers extracted from $_SERVER. + * + * @return void + */ + public function autoInitKnownHttpHeaders(): void + { + // Go through known HTTP headers that we care about. + // See "4.1.18. Protocol-Specific Meta-Variables" of http://www.faqs.org/rfcs/rfc3875.html + $knownHttpHeaders = array_merge( + array_values(self::$knownUserAgentHttpHeaders), + array_keys(self::$knownMobilePositiveHeaders), + array_values(self::$knownCloudFrontHeaders) + ); + + // Did not iterate through global $_SERVER to find ['HTTP...'] header values + // because it's very slow and on some servers it can have more than 50 worthless keys. +// $httpHeaders = array_filter($_SERVER, function ($key) { +// return str_starts_with($key, 'HTTP_'); +// }, ARRAY_FILTER_USE_KEY); + $httpHeaders = []; + foreach ($knownHttpHeaders as $headerName) { + if (isset($_SERVER[$headerName])) { + $httpHeaders[$headerName] = $_SERVER[$headerName]; + } + } + $this->setHttpHeaders($httpHeaders); + + // Set the User-Agent even if it's an empty string so that "autoInitOfHttpHeaders" doesn't throw an exception. + // https://github.com/serbanghita/Mobile-Detect/issues/946#issuecomment-1885675939 + if (!$this->hasUserAgent()) { + $this->setUserAgent(""); + } + } + + /** + * Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers. + * + * @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract + * the headers. The default null is left for backwards compatibility. + */ + public function setHttpHeaders(array $httpHeaders = []): void + { + $this->httpHeaders = $httpHeaders; + + // Don't process any further if no actual HTTP headers were set. + if (count($httpHeaders) === 0) { + return; + } + + // Setting new HTTP headers automatically resets the User-Agent. + // Set current User-Agent from known User-Agent-like HTTP header(s). + $userAgent = ""; + foreach ($this->getUaHttpHeaders() as $altHeader) { + if (!empty($this->httpHeaders[$altHeader])) { + $userAgent .= $this->httpHeaders[$altHeader] . " "; + } + } + + if (!empty($userAgent)) { + $this->setUserAgent($userAgent); + } + + // Override User-Agent string if 'Amazon Cloudfront' specific HTTP headers are present. + if ( + $this->hasHttpHeader(self::$knownCloudFrontHeaders[0]) || + $this->hasHttpHeader(self::$knownCloudFrontHeaders[1]) + ) { + $this->setUserAgent(self::$cloudFrontUA); + } + } + + /** + * Retrieves the HTTP headers. + * + * @return array + */ + public function getHttpHeaders(): array + { + return $this->httpHeaders; + } + + public function hasHttpHeaders(): bool + { + return count($this->httpHeaders) > 0; + } + + protected function hasHttpHeader(string $name): bool + { + return !empty($this->httpHeaders[$name]); + } + + /** + * Retrieves a particular header. If it doesn't exist, no exception/error is caused. + * Simply null is returned. + * + * @param string $header The name of the header to retrieve. Can be HTTP compliant such as + * "User-Agent" or "X-Device-User-Agent" or can be php-esque with the + * all-caps, HTTP_ prefixed, underscore separated awesomeness. + * + * @return string|null The value of the header. + */ + public function getHttpHeader(string $header): ?string + { + // are we using PHP-flavored headers? + if (!str_contains($header, '_')) { + $header = str_replace('-', '_', $header); + $header = strtoupper($header); + } + + // test the alternate, too + $altHeader = 'HTTP_' . $header; + + //Test both the regular and the HTTP_ prefix + if (isset($this->httpHeaders[$header])) { + return $this->httpHeaders[$header]; + } elseif (isset($this->httpHeaders[$altHeader])) { + return $this->httpHeaders[$altHeader]; + } + + return null; + } + + public function getMobileHeaders(): array + { + return static::$knownMobilePositiveHeaders; + } + + /** + * Get all possible HTTP headers that + * can contain the User-Agent string. + * + * @return array List of HTTP headers. + */ + public function getUaHttpHeaders(): array + { + return static::$knownUserAgentHttpHeaders; + } + + /** + * Retrieves the HTTP CloudFront headers + * that trigger a mobile detection. + * + * @return array + */ + public function getCloudFrontHttpHeaders(): array + { + return static::$knownCloudFrontHeaders; + } + + /** + * Prepare the User-Agent string for matching phase. + * + * @param string $userAgent The User-Agent string. + * @return string + */ + private function prepareUserAgent(string $userAgent): string + { + $userAgent = trim($userAgent); + return substr($userAgent, 0, $this->config['maximumUserAgentLength']); + } + + /** + * Set the User-Agent to be used. + * + * @param string $userAgent The User-Agent string. + * @return string + */ + public function setUserAgent(string $userAgent): string + { + $preparedUserAgent = $this->prepareUserAgent($userAgent); + return $this->userAgent = $preparedUserAgent; + } + + /** + * Retrieve the User-Agent. + * + * @return string|null The user agent if it's set. + */ + public function getUserAgent(): ?string + { + return $this->userAgent; + } + + public function hasUserAgent(): bool + { + return is_string($this->userAgent); + } + + public function isUserAgentEmpty(): bool + { + return $this->hasUserAgent() && $this->userAgent === ''; + } + + public function getMatchingRegex(): ?string + { + return $this->matchingRegex; + } + + public function getMatchesArray(): ?array + { + return $this->matchesArray; + } + + /** + * Retrieve the list of known phone devices. + * + * @return array List of phone devices. + */ + public static function getPhoneDevices(): array + { + return static::$phoneDevices; + } + + /** + * Retrieve the list of known tablet devices. + * + * @return array List of tablet devices. + */ + public static function getTabletDevices(): array + { + return static::$tabletDevices; + } + + /** + * Retrieve the list of known browsers. Specifically, the user agents. + * + * @return array List of browsers / user agents. + */ + public static function getBrowsers(): array + { + return static::$browsers; + } + + /** + * Method gets the mobile detection rules. + * This method is used for the magic methods $detect->is*(). + * Retrieve the current set of rules. + * + * @return array + */ + public function getRules(): array + { + static $rules; + + if (!$rules) { + $rules = array_merge( + static::$browsers, + static::$operatingSystems, + static::$phoneDevices, + static::$tabletDevices + ); + } + + return $rules; + } + + /** + * Retrieve the list of mobile operating systems. + * + * @return array The list of mobile operating systems. + */ + public static function getOperatingSystems(): array + { + return static::$operatingSystems; + } + + /** + * Check the HTTP headers for signs of mobile. + * This is the fastest mobile check possible; it's used + * inside isMobile() method. + * + * @return bool + */ + public function checkHttpHeadersForMobile(): bool + { + foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) { + if (isset($this->httpHeaders[$mobileHeader])) { + if (isset($matchType['matches']) && is_array($matchType['matches'])) { + foreach ($matchType['matches'] as $_match) { + if (str_contains($this->httpHeaders[$mobileHeader], $_match)) { + return true; + } + } + + return false; + } else { + return true; + } + } + } + + return false; + } + + /** + * Magic overloading method. + * + * @method boolean is[...]() + * @param string $name + * @param array $arguments + * @return bool + * @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is' + * @throws \Exception + * @throws InvalidArgumentException + */ + public function __call(string $name, array $arguments) + { + // make sure the name starts with 'is', otherwise + if (!str_starts_with($name, 'is')) { + throw new BadMethodCallException("No such method exists: $name"); + } + + $ruleName = substr($name, 2); + + return $this->is($ruleName); + } + + /** + * Check if the device is mobile. + * Returns true if any type of mobile device detected, including special ones + * @return bool + * @throws MobileDetectException + */ + public function isMobile(): bool + { + if (!$this->hasUserAgent()) { + throw new MobileDetectException('No valid user-agent has been set.'); + } + + if ($this->isUserAgentEmpty()) { + return false; + } + + // Cache check. + try { + $cacheKey = $this->createCacheKey("mobile"); + $cacheItem = $this->cache->get($cacheKey); + if ($cacheItem !== null) { + if ($cacheItem instanceof CacheItemInterface) { + return $cacheItem->get(); + } else { + return $cacheItem; + } + } + + // Special case: Amazon CloudFront mobile viewer + if ( + $this->getUserAgent() === self::$cloudFrontUA && + $this->getHttpHeader('HTTP_CLOUDFRONT_IS_MOBILE_VIEWER') === 'true' + ) { + $this->cache->set($cacheKey, true, $this->config['cacheTtl']); + return true; + } + + if ($this->hasHttpHeaders() && $this->checkHttpHeadersForMobile()) { + $this->cache->set($cacheKey, true, $this->config['cacheTtl']); + return true; + } else { + $result = $this->matchUserAgentWithFirstFoundMatchingRule(); + $this->cache->set($cacheKey, $result, $this->config['cacheTtl']); + return $result; + } + } catch (CacheException $e) { + throw new MobileDetectException("Cache problem in isMobile(): {$e->getMessage()}"); + } + } + + /** + * Check if the device is a tablet. + * Return true if any type of tablet device is detected. + * @return bool + * @throws MobileDetectException + */ + public function isTablet(): bool + { + if (!$this->hasUserAgent()) { + throw new MobileDetectException('No user-agent has been set.'); + } + + if ($this->isUserAgentEmpty()) { + return false; + } + + // Cache check. + try { + $cacheKey = $this->createCacheKey("tablet"); + $cacheItem = $this->cache->get($cacheKey); + if ($cacheItem !== null) { + if ($cacheItem instanceof CacheItemInterface) { + return $cacheItem->get(); + } else { + return $cacheItem; + } + } + + // Special case: Amazon CloudFront mobile viewer + if ( + $this->getUserAgent() === self::$cloudFrontUA && + $this->getHttpHeader('HTTP_CLOUDFRONT_IS_TABLET_VIEWER') === 'true' + ) { + $this->cache->set($cacheKey, true, $this->config['cacheTtl']); + return true; + } + + foreach (static::$tabletDevices as $_regex) { + $regexString = $_regex; + // "regex" is array of "strings" + if (is_array($_regex)) { + $regexString = implode("|", $_regex); + } + if ($this->match($regexString, $this->getUserAgent())) { + $this->cache->set($cacheKey, true, $this->config['cacheTtl']); + return true; + } + +// if (is_array($_regex)) { +// foreach ($_regex as $regexString) { +// $result = $this->match($regexString, $this->getUserAgent()); +// if ($result) { +// $this->cache->set($cacheKey, true, $this->config['cacheTtl']); +// return true; +// } +// } +// } else { +// // assume the regex is a "string" +// if ($this->match($_regex, $this->getUserAgent())) { +// $this->cache->set($cacheKey, true, $this->config['cacheTtl']); +// return true; +// } +// } + } + + $this->cache->set($cacheKey, false, $this->config['cacheTtl']); + return false; + } catch (CacheException $e) { + throw new MobileDetectException("Cache problem in isTablet(): {$e->getMessage()}"); + } + } + + /** + * Checks if a rule (e.g. isIphone, isIOS, etc.) matches its regex against the User-Agent. + * + * @param string $ruleName + * @return bool + * @throws MobileDetectException + */ + public function is(string $ruleName): bool + { + if (!$this->hasUserAgent()) { + throw new MobileDetectException('No user-agent has been set.'); + } + + if ($this->isUserAgentEmpty()) { + return false; + } + + // Cache check. + try { + $cacheKey = $this->createCacheKey($ruleName); + $cacheItem = $this->cache->get($cacheKey); + if ($cacheItem !== null) { + if ($cacheItem instanceof CacheItemInterface) { + return $cacheItem->get(); + } else { + return $cacheItem; + } + } + + $result = $this->matchUserAgentWithRule($ruleName); + + // Cache save. + $this->cache->set($cacheKey, $result, $this->config['cacheTtl']); + return $result; + } catch (CacheException $e) { + throw new MobileDetectException("Cache problem in is(): {$e->getMessage()}"); + } + } + + /** + * Some detection rules are relative (not standard), + * because of the diversity of devices, vendors and + * their conventions in representing the User-Agent or + * the HTTP headers. + * + * This method will be used to check custom regexes against + * the User-Agent string. + * + * @param string $regex + * @param string $userAgent + * @return bool + * + * @todo: search in the HTTP headers too. + */ + public function match(string $regex, string $userAgent): bool + { + $match = (bool) preg_match(sprintf('#%s#is', $regex), $userAgent, $matches); + // If positive match is found, store the results for debug. + if ($match) { + $this->matchingRegex = $regex; + $this->matchesArray = $matches; + } + + return $match; + } + + /** + * Find a detection rule that matches the current User-agent. + * @return bool + */ + protected function matchUserAgentWithFirstFoundMatchingRule(): bool + { + // Begin general search. + foreach ($this->getRules() as $_regex) { + if (empty($_regex)) { + continue; + } + + // regex is an array of "strings" + if (is_array($_regex)) { + foreach ($_regex as $regexString) { + if ($this->match($regexString, $this->getUserAgent())) { + return true; + } + } + } else { + // assume regex is "string" + if ($this->match($_regex, $this->getUserAgent())) { + return true; + } + } + } + + return false; + } + + /** + * Search for a certain key in the rules array. + * If the key is found then try to match the corresponding + * regex against the User-Agent. + * + * @param string $ruleName + * @return bool + */ + protected function matchUserAgentWithRule(string $ruleName): bool + { + $result = false; + // Make the keys lowercase, so we can match: isIphone(), isiPhone(), isiphone(), etc. + $ruleName = strtolower($ruleName); + // change the keys to lower case + $_rules = array_change_key_case($this->getRules()); + + if (false === empty($_rules[$ruleName])) { + $regexString = $_rules[$ruleName]; + if (is_array($_rules[$ruleName])) { + $regexString = implode("|", $_rules[$ruleName]); + } + $result = $this->match($regexString, $this->getUserAgent()); +// if (is_array($_rules[$ruleName])) { +// foreach($_rules[$ruleName] as $ruleRegex) { +// $result = $this->match($ruleRegex, $this->getUserAgent()); +// if ($result) { +// return true; +// } +// } +// } else { +// $result = $this->match($_rules[$ruleName], $this->getUserAgent()); +// } + } + + return $result; + } + + /** + * Prepare the version number. + * @todo Remove the error suppression from str_replace() call. + * + * @param string $ver The string version, like "2.6.21.2152"; + * @return float + */ + public function prepareVersionNo(string $ver): float + { + $ver = str_replace(array('_', ' ', '/'), '.', $ver); + $arrVer = explode('.', $ver, 2); + + if (isset($arrVer[1])) { + $arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions. + } + + return (float) implode('.', $arrVer); + } + + /** + * Check the version of the given property in the User-Agent. + * Will return a float number. (e.g. 2_0 will return 2.0, 4.3.1 will return 4.31) + * + * @param string $propertyName The name of the property. See self::getProperties() array + * keys for all possible properties. + * @param string $type Either self::VERSION_TYPE_STRING to get a string value or + * self::VERSION_TYPE_FLOAT indicating a float value. This parameter + * is optional and defaults to self::VERSION_TYPE_STRING. Passing an + * invalid parameter will default to the type as well. + * + * @return string|float|false The version of the property we are trying to extract. + */ + public function version(string $propertyName, string $type = self::VERSION_TYPE_STRING): float|bool|string + { + if (empty($propertyName) || !$this->hasUserAgent()) { + return false; + } + + // set the $type to the default if we don't recognize the type + if ($type !== self::VERSION_TYPE_STRING && $type !== self::VERSION_TYPE_FLOAT) { + $type = self::VERSION_TYPE_STRING; + } + + $properties = self::getProperties(); + + // Check if the property exists in the properties array. + if (true === isset($properties[$propertyName])) { + // Prepare the pattern to be matched. + // Make sure we always deal with an array (string is converted). + $properties[$propertyName] = (array) $properties[$propertyName]; + + foreach ($properties[$propertyName] as $propertyMatchString) { + $propertyPattern = str_replace('[VER]', self::VERSION_REGEX, $propertyMatchString); + + // Identify and extract the version. + preg_match(sprintf('#%s#is', $propertyPattern), $this->userAgent, $match); + + if (false === empty($match[1])) { + return ($type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1]); + } + } + } + + return false; + } + + public function getCache(): Cache + { + return $this->cache; + } + + /** + * @throws CacheException + */ + protected function createCacheKey(string $key): string + { + $userAgentKey = $this->hasUserAgent() ? $this->userAgent : ''; + $httpHeadersKey = $this->hasHttpHeaders() ? static::flattenHeaders($this->httpHeaders) : ''; + + $cacheKey = "$key:$userAgentKey:$httpHeadersKey"; + + $cacheKeyFn = $this->config['cacheKeyFn']; + + if (!is_callable($cacheKeyFn)) { + throw new CacheException('cacheKeyFn is not a function.'); + } + + return call_user_func($cacheKeyFn, $cacheKey); + } + + public static function flattenHeaders(array $httpHeaders): string + { + $key = ''; + foreach ($httpHeaders as $name => $value) { + $key .= "$name: $value" . PHP_EOL; + } + return trim($key); + } + + /** + * Get the properties array. + * + * @return array + */ + public static function getProperties(): array + { + return static::$properties; + } +} diff --git a/tools/mobile_detect/psr/cache/CHANGELOG.md b/tools/mobile_detect/psr/cache/CHANGELOG.md new file mode 100644 index 000000000..58ddab05a --- /dev/null +++ b/tools/mobile_detect/psr/cache/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog + +All notable changes to this project will be documented in this file, in reverse chronological order by release. + +## 1.0.1 - 2016-08-06 + +### Fixed + +- Make spacing consistent in phpdoc annotations php-fig/cache#9 - chalasr +- Fix grammar in phpdoc annotations php-fig/cache#10 - chalasr +- Be more specific in docblocks that `getItems()` and `deleteItems()` take an array of strings (`string[]`) compared to just `array` php-fig/cache#8 - GrahamCampbell +- For `expiresAt()` and `expiresAfter()` in CacheItemInterface fix docblock to specify null as a valid parameters as well as an implementation of DateTimeInterface php-fig/cache#7 - GrahamCampbell + +## 1.0.0 - 2015-12-11 + +Initial stable release; reflects accepted PSR-6 specification diff --git a/tools/mobile_detect/psr/cache/LICENSE.txt b/tools/mobile_detect/psr/cache/LICENSE.txt new file mode 100644 index 000000000..b1c2c97b9 --- /dev/null +++ b/tools/mobile_detect/psr/cache/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2015 PHP Framework Interoperability Group + +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/tools/mobile_detect/psr/cache/README.md b/tools/mobile_detect/psr/cache/README.md new file mode 100644 index 000000000..9855a318b --- /dev/null +++ b/tools/mobile_detect/psr/cache/README.md @@ -0,0 +1,12 @@ +Caching Interface +============== + +This repository holds all interfaces related to [PSR-6 (Caching Interface)][psr-url]. + +Note that this is not a Caching implementation of its own. It is merely interfaces that describe the components of a Caching mechanism. + +The installable [package][package-url] and [implementations][implementation-url] are listed on Packagist. + +[psr-url]: https://www.php-fig.org/psr/psr-6/ +[package-url]: https://packagist.org/packages/psr/cache +[implementation-url]: https://packagist.org/providers/psr/cache-implementation diff --git a/tools/mobile_detect/psr/cache/composer.json b/tools/mobile_detect/psr/cache/composer.json new file mode 100644 index 000000000..4b687971e --- /dev/null +++ b/tools/mobile_detect/psr/cache/composer.json @@ -0,0 +1,25 @@ +{ + "name": "psr/cache", + "description": "Common interface for caching libraries", + "keywords": ["psr", "psr-6", "cache"], + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=8.0.0" + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/tools/mobile_detect/psr/cache/src/CacheException.php b/tools/mobile_detect/psr/cache/src/CacheException.php new file mode 100644 index 000000000..bb785f46c --- /dev/null +++ b/tools/mobile_detect/psr/cache/src/CacheException.php @@ -0,0 +1,10 @@ + 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/tools/mobile_detect/psr/simple-cache/README.md b/tools/mobile_detect/psr/simple-cache/README.md new file mode 100644 index 000000000..43641d175 --- /dev/null +++ b/tools/mobile_detect/psr/simple-cache/README.md @@ -0,0 +1,8 @@ +PHP FIG Simple Cache PSR +======================== + +This repository holds all interfaces related to PSR-16. + +Note that this is not a cache implementation of its own. It is merely an interface that describes a cache implementation. See [the specification](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-16-simple-cache.md) for more details. + +You can find implementations of the specification by looking for packages providing the [psr/simple-cache-implementation](https://packagist.org/providers/psr/simple-cache-implementation) virtual package. diff --git a/tools/mobile_detect/psr/simple-cache/composer.json b/tools/mobile_detect/psr/simple-cache/composer.json new file mode 100644 index 000000000..f307a8456 --- /dev/null +++ b/tools/mobile_detect/psr/simple-cache/composer.json @@ -0,0 +1,25 @@ +{ + "name": "psr/simple-cache", + "description": "Common interfaces for simple caching", + "keywords": ["psr", "psr-16", "cache", "simple-cache", "caching"], + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=8.0.0" + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + } +} diff --git a/tools/mobile_detect/psr/simple-cache/src/CacheException.php b/tools/mobile_detect/psr/simple-cache/src/CacheException.php new file mode 100644 index 000000000..f61b24c2b --- /dev/null +++ b/tools/mobile_detect/psr/simple-cache/src/CacheException.php @@ -0,0 +1,10 @@ + $keys A list of keys that can be obtained in a single operation. + * @param mixed $default Default value to return for keys that do not exist. + * + * @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + */ + public function getMultiple(iterable $keys, mixed $default = null): iterable; + + /** + * Persists a set of key => value pairs in the cache, with an optional TTL. + * + * @param iterable $values A list of key => value pairs for a multiple-set operation. + * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and + * the driver supports TTL then the library may set a default value + * for it or let the driver take care of that. + * + * @return bool True on success and false on failure. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $values is neither an array nor a Traversable, + * or if any of the $values are not a legal value. + */ + public function setMultiple(iterable $values, null|int|\DateInterval $ttl = null): bool; + + /** + * Deletes multiple cache items in a single operation. + * + * @param iterable $keys A list of string-based keys to be deleted. + * + * @return bool True if the items were successfully removed. False if there was an error. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + */ + public function deleteMultiple(iterable $keys): bool; + + /** + * Determines whether an item is present in the cache. + * + * NOTE: It is recommended that has() is only to be used for cache warming type purposes + * and not to be used within your live applications operations for get/set, as this method + * is subject to a race condition where your has() will return true and immediately after, + * another script can remove it making the state of your app out of date. + * + * @param string $key The cache item key. + * + * @return bool + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if the $key string is not a legal value. + */ + public function has(string $key): bool; +} diff --git a/tools/mobile_detect/psr/simple-cache/src/InvalidArgumentException.php b/tools/mobile_detect/psr/simple-cache/src/InvalidArgumentException.php new file mode 100644 index 000000000..6a9524a20 --- /dev/null +++ b/tools/mobile_detect/psr/simple-cache/src/InvalidArgumentException.php @@ -0,0 +1,13 @@ +create($parsed); diff --git a/tools/parser_sql/builders/ColumnTypeBuilder.php b/tools/parser_sql/builders/ColumnTypeBuilder.php index 1550b2e47..365d20a22 100644 --- a/tools/parser_sql/builders/ColumnTypeBuilder.php +++ b/tools/parser_sql/builders/ColumnTypeBuilder.php @@ -80,6 +80,20 @@ class ColumnTypeBuilder implements Builder { return $parsed['base_expr']; } + protected function buildCollation($parsed) { + if ($parsed['expr_type'] !== ExpressionType::COLLATE) { + return ""; + } + return $parsed['base_expr']; + } + + protected function buildComment($parsed) { + if ($parsed['expr_type'] !== ExpressionType::COMMENT) { + return ""; + } + return $parsed['base_expr']; + } + public function build(array $parsed) { if ($parsed['expr_type'] !== ExpressionType::COLUMN_TYPE) { return ""; @@ -92,6 +106,8 @@ class ColumnTypeBuilder implements Builder { $sql .= $this->buildReserved($v); $sql .= $this->buildDefaultValue($v); $sql .= $this->buildCharacterSet($v); + $sql .= $this->buildCollation($v); + $sql .= $this->buildComment($v); if ($len == strlen($sql)) { throw new UnableToCreateSQLException('CREATE TABLE column-type subtree', $k, $v, 'expr_type'); diff --git a/tools/parser_sql/builders/FulltextIndexBuilder.php b/tools/parser_sql/builders/FulltextIndexBuilder.php new file mode 100644 index 000000000..47ab170fa --- /dev/null +++ b/tools/parser_sql/builders/FulltextIndexBuilder.php @@ -0,0 +1,99 @@ + + * @copyright 2010-2014 Justin Swanhart and André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * @version SVN: $Id$ + * + */ + +namespace PHPSQLParser\builders; +use PHPSQLParser\exceptions\UnableToCreateSQLException; +use PHPSQLParser\utils\ExpressionType; + +/** + * This class implements the builder for the index key part of a CREATE TABLE statement. + * You can overwrite all functions to achieve another handling. + * + * @author André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * + */ +class FulltextIndexBuilder implements Builder { + + protected function buildReserved($parsed) { + $builder = new ReservedBuilder(); + return $builder->build($parsed); + } + + protected function buildConstant($parsed) { + $builder = new ConstantBuilder(); + return $builder->build($parsed); + } + + protected function buildIndexKey($parsed) { + if ($parsed['expr_type'] !== ExpressionType::INDEX) { + return ""; + } + return $parsed['base_expr']; + } + + protected function buildColumnList($parsed) { + $builder = new ColumnListBuilder(); + return $builder->build($parsed); + } + + public function build(array $parsed) { + if ($parsed['expr_type'] !== ExpressionType::FULLTEXT_IDX) { + return ""; + } + $sql = ""; + foreach ($parsed['sub_tree'] as $k => $v) { + $len = strlen($sql); + $sql .= $this->buildReserved($v); + $sql .= $this->buildColumnList($v); + $sql .= $this->buildConstant($v); + $sql .= $this->buildIndexKey($v); + + if ($len == strlen($sql)) { + throw new UnableToCreateSQLException('CREATE TABLE fulltext-index key subtree', $k, $v, 'expr_type'); + } + + $sql .= " "; + } + return substr($sql, 0, -1); + } +} +?> diff --git a/tools/parser_sql/builders/FunctionBuilder.php b/tools/parser_sql/builders/FunctionBuilder.php index 157204104..4d5674a3e 100644 --- a/tools/parser_sql/builders/FunctionBuilder.php +++ b/tools/parser_sql/builders/FunctionBuilder.php @@ -92,7 +92,12 @@ class FunctionBuilder implements Builder { $builder = new SubQueryBuilder(); return $builder->build($parsed); } - + + protected function buildUserVariableExpression($parsed) { + $builder = new UserVariableBuilder(); + return $builder->build($parsed); + } + public function build(array $parsed) { if (($parsed['expr_type'] !== ExpressionType::AGGREGATE_FUNCTION) && ($parsed['expr_type'] !== ExpressionType::SIMPLE_FUNCTION) @@ -114,6 +119,7 @@ class FunctionBuilder implements Builder { $sql .= $this->buildReserved($v); $sql .= $this->buildSelectBracketExpression($v); $sql .= $this->buildSelectExpression($v); + $sql .= $this->buildUserVariableExpression($v); if ($len == strlen($sql)) { throw new UnableToCreateSQLException('function subtree', $k, $v, 'expr_type'); diff --git a/tools/parser_sql/builders/OrderByBuilder.php b/tools/parser_sql/builders/OrderByBuilder.php index e088ad95e..d1c872a84 100644 --- a/tools/parser_sql/builders/OrderByBuilder.php +++ b/tools/parser_sql/builders/OrderByBuilder.php @@ -84,7 +84,7 @@ class OrderByBuilder implements Builder { } protected function buildPosition($parsed) { - $builder = new PositionBuilder(); + $builder = new OrderByPositionBuilder(); return $builder->build($parsed); } diff --git a/tools/parser_sql/builders/OrderByPositionBuilder.php b/tools/parser_sql/builders/OrderByPositionBuilder.php new file mode 100644 index 000000000..e1be594d9 --- /dev/null +++ b/tools/parser_sql/builders/OrderByPositionBuilder.php @@ -0,0 +1,66 @@ + + * @copyright 2010-2014 Justin Swanhart and André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * @version SVN: $Id$ + * + */ + +namespace PHPSQLParser\builders; +use PHPSQLParser\utils\ExpressionType; + +/** + * This class implements the builder for positions of the GROUP-BY clause. + * You can overwrite all functions to achieve another handling. + * + * @author André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * + */ +class OrderByPositionBuilder implements Builder { + protected function buildDirection($parsed) { + $builder = new DirectionBuilder(); + return $builder->build($parsed); + } + + public function build(array $parsed) { + if ($parsed['expr_type'] !== ExpressionType::POSITION) { + return ""; + } + return $parsed['base_expr'] . $this->buildDirection($parsed); + } +} +?> diff --git a/tools/parser_sql/builders/TableBracketExpressionBuilder.php b/tools/parser_sql/builders/TableBracketExpressionBuilder.php index 41eb3875a..83860b038 100644 --- a/tools/parser_sql/builders/TableBracketExpressionBuilder.php +++ b/tools/parser_sql/builders/TableBracketExpressionBuilder.php @@ -84,6 +84,16 @@ class TableBracketExpressionBuilder implements Builder { return $builder->build($parsed); } + protected function buildUniqueIndex($parsed) { + $builder = new UniqueIndexBuilder(); + return $builder->build($parsed); + } + + protected function buildFulltextIndex($parsed) { + $builder = new FulltextIndexBuilder(); + return $builder->build($parsed); + } + public function build(array $parsed) { if ($parsed['expr_type'] !== ExpressionType::BRACKET_EXPRESSION) { return ""; @@ -97,6 +107,8 @@ class TableBracketExpressionBuilder implements Builder { $sql .= $this->buildLikeExpression($v); $sql .= $this->buildForeignKey($v); $sql .= $this->buildIndexKey($v); + $sql .= $this->buildUniqueIndex($v); + $sql .= $this->buildFulltextIndex($v); if ($len == strlen($sql)) { throw new UnableToCreateSQLException('CREATE TABLE create-def expression subtree', $k, $v, 'expr_type'); diff --git a/tools/parser_sql/builders/UniqueIndexBuilder.php b/tools/parser_sql/builders/UniqueIndexBuilder.php new file mode 100644 index 000000000..b0f44d000 --- /dev/null +++ b/tools/parser_sql/builders/UniqueIndexBuilder.php @@ -0,0 +1,97 @@ + + * @copyright 2010-2014 Justin Swanhart and André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * @version SVN: $Id$ + * + */ + +namespace PHPSQLParser\builders; +use PHPSQLParser\exceptions\UnableToCreateSQLException; +use PHPSQLParser\utils\ExpressionType; + +/** + * This class implements the builder for the index key part of a CREATE TABLE statement. + * You can overwrite all functions to achieve another handling. + * + * @author André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * + */ +class UniqueIndexBuilder implements Builder { + + protected function buildReserved($parsed) { + $builder = new ReservedBuilder(); + return $builder->build($parsed); + } + + protected function buildConstant($parsed) { + $builder = new ConstantBuilder(); + return $builder->build($parsed); + } + + protected function buildIndexType($parsed) { + $builder = new IndexTypeBuilder(); + return $builder->build($parsed); + } + + protected function buildColumnList($parsed) { + $builder = new ColumnListBuilder(); + return $builder->build($parsed); + } + + public function build(array $parsed) { + if ($parsed['expr_type'] !== ExpressionType::UNIQUE_IDX) { + return ""; + } + $sql = ""; + foreach ($parsed['sub_tree'] as $k => $v) { + $len = strlen($sql); + $sql .= $this->buildReserved($v); + $sql .= $this->buildColumnList($v); + $sql .= $this->buildConstant($v); + $sql .= $this->buildIndexType($v); + + if ($len == strlen($sql)) { + throw new UnableToCreateSQLException('CREATE TABLE unique-index key subtree', $k, $v, 'expr_type'); + } + + $sql .= " "; + } + return substr($sql, 0, -1); + } +} +?> diff --git a/tools/parser_sql/builders/index.php b/tools/parser_sql/builders/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/parser_sql/builders/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/parser_sql/exceptions/index.php b/tools/parser_sql/exceptions/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/parser_sql/exceptions/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/parser_sql/index.php b/tools/parser_sql/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/parser_sql/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/parser_sql/lexer/PHPSQLLexer.php b/tools/parser_sql/lexer/PHPSQLLexer.php index 4ef0e1267..8faf5574c 100644 --- a/tools/parser_sql/lexer/PHPSQLLexer.php +++ b/tools/parser_sql/lexer/PHPSQLLexer.php @@ -84,7 +84,7 @@ class PHPSQLLexer { if (!is_string($sql)) { throw new InvalidParameterException($sql); } - $tokens = preg_split($this->splitters->getSplittersRegexPattern(), $sql, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + $tokens = preg_split($this->splitters->getSplittersRegexPattern(), $sql, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); $tokens = $this->concatComments($tokens); $tokens = $this->concatEscapeSequences($tokens); $tokens = $this->balanceBackticks($tokens); diff --git a/tools/parser_sql/lexer/index.php b/tools/parser_sql/lexer/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/parser_sql/lexer/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/parser_sql/positions/PositionCalculator.php b/tools/parser_sql/positions/PositionCalculator.php index 53eb57f6c..8f63b0045 100644 --- a/tools/parser_sql/positions/PositionCalculator.php +++ b/tools/parser_sql/positions/PositionCalculator.php @@ -90,7 +90,8 @@ class PositionCalculator { ExpressionType::SUBPARTITION_HASH, ExpressionType::SUBPARTITION_COUNT, ExpressionType::CHARSET, ExpressionType::ENGINE, ExpressionType::QUERY, ExpressionType::INDEX_ALGORITHM, ExpressionType::INDEX_LOCK, - ExpressionType::SUBQUERY_FACTORING, ExpressionType::CUSTOM_FUNCTION + ExpressionType::SUBQUERY_FACTORING, ExpressionType::CUSTOM_FUNCTION, + ExpressionType::SIMPLE_FUNCTION ); /** @@ -127,6 +128,9 @@ class PositionCalculator { } protected function findPositionWithinString($sql, $value, $expr_type) { + if ($value === '') { + return false; + } $offset = 0; $ok = false; @@ -145,8 +149,9 @@ class PositionCalculator { } // if we have a quoted string, we every character is allowed after it - // see issue 137 - $quoted = ($sql[$pos + strlen($value) - 1] === '`'); + // see issues 137 and 361 + $quotedBefore = in_array($sql[$pos], array('`', '('), true); + $quotedAfter = in_array($sql[$pos + strlen($value) - 1], array('`', ')'), true); $after = ""; if (isset($sql[$pos + strlen($value)])) { $after = $sql[$pos + strlen($value)]; @@ -175,10 +180,11 @@ class PositionCalculator { // in all other cases we accept // whitespace, comma, operators, parenthesis and end_of_string - $ok = ($before === "" || in_array($before, self::$allowedOnOther, true)); + $ok = ($before === "" || in_array($before, self::$allowedOnOther, true) + || ($quotedBefore && (strtolower($before) >= 'a' && strtolower($before) <= 'z'))); $ok = $ok && ($after === "" || in_array($after, self::$allowedOnOther, true) - || ($quoted && (strtolower($after) >= 'a' && strtolower($after) <= 'z'))); + || ($quotedAfter && (strtolower($after) >= 'a' && strtolower($after) <= 'z'))); if ($ok) { break; diff --git a/tools/parser_sql/positions/index.php b/tools/parser_sql/positions/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/parser_sql/positions/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/parser_sql/processors/AbstractProcessor.php b/tools/parser_sql/processors/AbstractProcessor.php index b172399d2..4e88cc8eb 100644 --- a/tools/parser_sql/processors/AbstractProcessor.php +++ b/tools/parser_sql/processors/AbstractProcessor.php @@ -64,7 +64,7 @@ abstract class AbstractProcessor { * * @param Options $options */ - public function __construct(Options $options = null) + public function __construct(?Options $options = null) { $this->options = $options; } diff --git a/tools/parser_sql/processors/ColumnDefinitionProcessor.php b/tools/parser_sql/processors/ColumnDefinitionProcessor.php index 4cd162aef..53b619a47 100644 --- a/tools/parser_sql/processors/ColumnDefinitionProcessor.php +++ b/tools/parser_sql/processors/ColumnDefinitionProcessor.php @@ -82,6 +82,19 @@ class ColumnDefinitionProcessor extends AbstractProcessor { return $expr; } + protected function peekAtNextToken($tokens, $index) + { + $offset = $index + 1; + while (isset($tokens[$offset])) { + $token = trim($tokens[$offset]); + if ($token !== '') { + return strtoupper($token); + } + $offset++; + } + return ''; + } + public function process($tokens) { $trim = ''; @@ -123,6 +136,7 @@ class ColumnDefinitionProcessor extends AbstractProcessor { break 2; case 'VARCHAR': + case 'VARCHARACTER': // Alias for VARCHAR $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'length' => false); $prevCategory = 'TEXT'; $currCategory = 'SINGLE_PARAM_PARENTHESIS'; @@ -155,10 +169,15 @@ class ColumnDefinitionProcessor extends AbstractProcessor { case 'TINYBIT': case 'TINYINT': case 'SMALLINT': + case 'INT2': // Alias of SMALLINT case 'MEDIUMINT': + case 'INT3': // Alias of MEDIUMINT + case 'MIDDLEINT': // Alias of MEDIUMINT case 'INT': case 'INTEGER': + case 'INT4': // Alias of INT case 'BIGINT': + case 'INT8': // Alias of BIGINT case 'BOOL': case 'BOOLEAN': $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'unsigned' => false, @@ -188,7 +207,9 @@ class ColumnDefinitionProcessor extends AbstractProcessor { case 'REAL': case 'DOUBLE': + case 'FLOAT8': // Alias for DOUBLE case 'FLOAT': + case 'FLOAT4': // Alias for FLOAT $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'unsigned' => false, 'zerofill' => false); $currCategory = 'TWO_PARAM_PARENTHESIS'; @@ -250,11 +271,25 @@ class ColumnDefinitionProcessor extends AbstractProcessor { // spatial types continue 2; - case 'CHARACTER': + case 'CHARSET': $currCategory = 'CHARSET'; $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim); continue 2; + case 'CHARACTER': + // Alias of CHAR as well as pre-running for CHARACTER SET + // To determine which we peek at the next token to see if it's a SET or not. + if ($this->peekAtNextToken($tokens, $key) == 'SET') { + $currCategory = 'CHARSET'; + $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim); + // If it's not a SET we assume that it is a CHARACTER type definition + } else { + $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'length' => false); + $currCategory = 'SINGLE_PARAM_PARENTHESIS'; + $prevCategory = 'TEXT'; + } + continue 2; + case 'SET': if ($currCategory == 'CHARSET') { $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim); diff --git a/tools/parser_sql/processors/ExpressionListProcessor.php b/tools/parser_sql/processors/ExpressionListProcessor.php index b0353f76e..f8d72cf76 100644 --- a/tools/parser_sql/processors/ExpressionListProcessor.php +++ b/tools/parser_sql/processors/ExpressionListProcessor.php @@ -256,8 +256,15 @@ class ExpressionListProcessor extends AbstractProcessor { // if the last token is colref, const or expression // then * is an operator // but if the previous colref ends with a dot, the * is the all-columns-alias - if (!$prev->isColumnReference() && !$prev->isConstant() && !$prev->isExpression() - && !$prev->isBracketExpression() && !$prev->isAggregateFunction() && !$prev->isVariable()) { + if ( + !$prev->isColumnReference() + && !$prev->isConstant() + && !$prev->isExpression() + && !$prev->isBracketExpression() + && !$prev->isAggregateFunction() + && !$prev->isVariable() + && !$prev->isFunction() + ) { $curr->setTokenType(ExpressionType::COLREF); break; } diff --git a/tools/parser_sql/processors/FromProcessor.php b/tools/parser_sql/processors/FromProcessor.php index 3ab97b99a..2692f1c6e 100644 --- a/tools/parser_sql/processors/FromProcessor.php +++ b/tools/parser_sql/processors/FromProcessor.php @@ -76,7 +76,7 @@ class FromProcessor extends AbstractProcessor { } // loop init return array('expression' => "", 'token_count' => 0, 'table' => "", 'no_quotes' => "", 'alias' => false, - 'hints' => false, 'join_type' => "", 'next_join_type' => "", + 'hints' => array(), 'join_type' => "", 'next_join_type' => "", 'saved_join_type' => $parseInfo['saved_join_type'], 'ref_type' => false, 'ref_expr' => false, 'base_expr' => false, 'sub_tree' => false, 'subquery' => ""); } @@ -84,13 +84,17 @@ class FromProcessor extends AbstractProcessor { protected function processFromExpression(&$parseInfo) { $res = array(); + if ($parseInfo['hints'] === array()) { + $parseInfo['hints'] = false; + } + // exchange the join types (join_type is save now, saved_join_type holds the next one) $parseInfo['join_type'] = $parseInfo['saved_join_type']; // initialized with JOIN $parseInfo['saved_join_type'] = ($parseInfo['next_join_type'] ? $parseInfo['next_join_type'] : 'JOIN'); // we have a reg_expr, so we have to parse it if ($parseInfo['ref_expr'] !== false) { - $unparsed = $this->splitSQLIntoTokens($parseInfo['ref_expr']); + $unparsed = $this->splitSQLIntoTokens(trim($parseInfo['ref_expr'])); // here we can get a comma separated list foreach ($unparsed as $k => $v) { @@ -186,6 +190,11 @@ class FromProcessor extends AbstractProcessor { if ($token_category === 'LEFT' || $token_category === 'RIGHT' || $token_category === 'NATURAL') { $token_category = ''; $parseInfo['next_join_type'] = strtoupper(trim($prevToken)); // it seems to be a join + } elseif ($token_category === 'IDX_HINT') { + $parseInfo['expression'] .= $token; + if ($parseInfo['ref_type'] !== false) { // all after ON / USING + $parseInfo['ref_expr'] .= $token; + } } break; @@ -272,6 +281,12 @@ class FromProcessor extends AbstractProcessor { break; case 'FOR': + if ($token_category === 'IDX_HINT') { + $cur_hint = (count($parseInfo['hints']) - 1); + $parseInfo['hints'][$cur_hint]['hint_type'] .= " " . $upper; + continue 2; + } + $parseInfo['token_count']++; $skip_next = true; break; @@ -291,6 +306,12 @@ class FromProcessor extends AbstractProcessor { $parseInfo['next_join_type'] = 'CROSS'; case 'JOIN': + if ($token_category === 'IDX_HINT') { + $cur_hint = (count($parseInfo['hints']) - 1); + $parseInfo['hints'][$cur_hint]['hint_type'] .= " " . $upper; + continue 2; + } + if ($parseInfo['subquery']) { $parseInfo['sub_tree'] = $this->parse($this->removeParenthesisFromStart($parseInfo['subquery'])); $parseInfo['expression'] = $parseInfo['subquery']; @@ -300,6 +321,13 @@ class FromProcessor extends AbstractProcessor { $parseInfo = $this->initParseInfo($parseInfo); break; + case 'GROUP BY': + if ($token_category === 'IDX_HINT') { + $cur_hint = (count($parseInfo['hints']) - 1); + $parseInfo['hints'][$cur_hint]['hint_type'] .= " " . $upper; + continue 2; + } + default: // TODO: enhance it, so we can have base_expr to calculate the position of the keywords // build a subtree under "hints" diff --git a/tools/parser_sql/processors/IndexProcessor.php b/tools/parser_sql/processors/IndexProcessor.php index 50ef717d7..22e968b72 100644 --- a/tools/parser_sql/processors/IndexProcessor.php +++ b/tools/parser_sql/processors/IndexProcessor.php @@ -72,7 +72,7 @@ class IndexProcessor extends AbstractProcessor { $currCategory = 'INDEX_NAME'; $result = array('base_expr' => false, 'name' => false, 'no_quotes' => false, 'index-type' => false, 'on' => false, - 'options' => false); + 'options' => array()); $expr = array(); $base_expr = ''; $skip = 0; @@ -300,6 +300,9 @@ class IndexProcessor extends AbstractProcessor { $currCategory = ''; } + if ($result['options'] === array()) { + $result['options'] = false; + } return $result; } } diff --git a/tools/parser_sql/processors/SQLProcessor.php b/tools/parser_sql/processors/SQLProcessor.php index 4c8ccfc35..6826bb94e 100644 --- a/tools/parser_sql/processors/SQLProcessor.php +++ b/tools/parser_sql/processors/SQLProcessor.php @@ -59,7 +59,7 @@ class SQLProcessor extends SQLChunkProcessor { $prev_category = ""; $token_category = ""; $skip_next = 0; - $out = false; + $out = array(); // $tokens may come as a numeric indexed array starting with an index greater than 0 (or as a boolean) $tokenCount = count($tokens); @@ -242,7 +242,6 @@ class SQLProcessor extends SQLChunkProcessor { case 'DELETE': case 'ALTER': case 'INSERT': - case 'TRUNCATE': case 'OPTIMIZE': case 'GRANT': case 'REVOKE': @@ -264,6 +263,17 @@ class SQLProcessor extends SQLChunkProcessor { $out[$upper][0] = $trim; continue 2; + case 'TRUNCATE': + if ($prev_category === '') { + // set the category in case these get subclauses in a future version of MySQL + $token_category = $upper; + $out[$upper][0] = $trim; + continue 2; + } + // part of the CREATE TABLE statement or a function + $out[$prev_category][] = $trim; + continue 2; + case 'REPLACE': if ($prev_category === '') { // set the category in case these get subclauses in a future version of MySQL @@ -400,7 +410,7 @@ class SQLProcessor extends SQLChunkProcessor { break; case 'FOR': - if ($prev_category === 'SHOW') { + if ($prev_category === 'SHOW' || $token_category === 'FROM') { break; } $skip_next = 1; @@ -509,6 +519,10 @@ class SQLProcessor extends SQLChunkProcessor { $prev_category = $token_category; } + if (count($out) === 0) { + return false; + } + return parent::process($out); } } diff --git a/tools/parser_sql/processors/TableProcessor.php b/tools/parser_sql/processors/TableProcessor.php index 248fe3b4c..a163f4182 100644 --- a/tools/parser_sql/processors/TableProcessor.php +++ b/tools/parser_sql/processors/TableProcessor.php @@ -83,7 +83,7 @@ class TableProcessor extends AbstractProcessor { $currCategory = 'TABLE_NAME'; $result = array('base_expr' => false, 'name' => false, 'no_quotes' => false, 'create-def' => false, - 'options' => false, 'like' => false, 'select-option' => false); + 'options' => array(), 'like' => false, 'select-option' => false); $expr = array(); $base_expr = ''; $skip = 0; @@ -366,6 +366,9 @@ class TableProcessor extends AbstractProcessor { if ($result['select-option'] === false) { unset($result['select-option']); } + if ($result['options'] === array()) { + $result['options'] = false; + } return $result; } diff --git a/tools/parser_sql/processors/index.php b/tools/parser_sql/processors/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/parser_sql/processors/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/parser_sql/utils/PHPSQLParserConstants.php b/tools/parser_sql/utils/PHPSQLParserConstants.php index fe634d01b..7b01eafbd 100644 --- a/tools/parser_sql/utils/PHPSQLParserConstants.php +++ b/tools/parser_sql/utils/PHPSQLParserConstants.php @@ -71,7 +71,7 @@ class PHPSQLParserConstants { 'DAY_MICROSECOND', 'DAY_MINUTE', 'DAY_SECOND', 'DEC', 'DECIMAL', 'DECLARE', 'DEFAULT', 'DELAYED', 'DELETE', 'DESC', 'DESCRIBE', 'DETERMINISTIC', 'DISTINCT', 'DISTINCTROW', 'DIV', 'DOUBLE', 'DROP', 'ELSE', 'ELSEIF', 'END', 'ENCLOSED', 'ESCAPED', 'EXISTS', - 'EXIT', 'EXPLAIN', 'FALSE', 'FETCH', 'FIELDS', 'FLOAT', 'FOR', 'FORCE', 'FOREIGN', + 'EXIT', 'EXPLAIN', 'FETCH', 'FIELDS', 'FLOAT', 'FOR', 'FORCE', 'FOREIGN', 'FOUND', 'FRAC_SECOND', 'FROM', 'FULLTEXT', 'GRANT', 'GROUP', 'HAVING', 'HIGH_PRIORITY', 'HOUR_MICROSECOND', 'HOUR_MINUTE', 'HOUR_SECOND', 'IF', 'IGNORE', 'IN', 'INDEX', 'INFILE', 'INNER', 'INNODB', 'INOUT', 'INSENSITIVE', 'INSERT', 'INT', @@ -90,7 +90,7 @@ class PHPSQLParserConstants { 'SQL_TSI_MINUTE', 'SQL_TSI_MONTH', 'SQL_TSI_QUARTER', 'SQL_TSI_SECOND', 'SQL_TSI_WEEK', 'SQL_TSI_YEAR', 'SSL', 'STARTING', 'STRAIGHT_JOIN', 'STRIPED', 'TABLE', 'TABLES', 'TEMPORARY', 'TERMINATED', 'THEN', 'TIMESTAMPADD', 'TIMESTAMPDIFF', 'TINYBLOB', - 'TINYINT', 'TINYTEXT', 'TO', 'TRAILING', 'TRUE', 'UNDO', 'UNION', 'UNIQUE', 'UNLOCK', + 'TINYINT', 'TINYTEXT', 'TO', 'TRAILING', 'UNDO', 'UNION', 'UNIQUE', 'UNLOCK', 'UNSIGNED', 'UPDATE', 'USAGE', 'USE', 'USER_RESOURCES', 'USING', 'UTC_DATE', 'UTC_TIME', 'UTC_TIMESTAMP', 'VALUES', 'VARBINARY', 'VARCHAR', 'VARCHARACTER', 'VARYING', 'WHEN', 'WHERE', 'WHILE', 'WITH', 'WRITE', 'XOR', 'YEAR_MONTH', 'ZEROFILL'); diff --git a/tools/parser_sql/utils/index.php b/tools/parser_sql/utils/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/parser_sql/utils/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/pear/LICENSE b/tools/pear/LICENSE index 16d1f57ef..a00a2421f 100644 --- a/tools/pear/LICENSE +++ b/tools/pear/LICENSE @@ -1,68 +1,27 @@ --------------------------------------------------------------------- - The PHP License, version 3.0 -Copyright (c) 1999 - 2006 The PHP Group. All rights reserved. --------------------------------------------------------------------- +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, is permitted provided that the following conditions -are met: +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. + * 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. - 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. - - 3. The name "PHP" must not be used to endorse or promote products - derived from this software without prior written permission. For - written permission, please contact group@php.net. - - 4. Products derived from this software may not be called "PHP", nor - may "PHP" appear in their name, without prior written permission - from group@php.net. You may indicate that your software works in - conjunction with PHP by saying "Foo for PHP" instead of calling - it "PHP Foo" or "phpfoo" - - 5. The PHP Group may publish revised and/or new versions of the - license from time to time. Each version will be given a - distinguishing version number. - Once covered code has been published under a particular version - of the license, you may always continue to use it under the terms - of that version. You may also choose to use such covered code - under the terms of any subsequent version of the license - published by the PHP Group. No one other than the PHP Group has - the right to modify the terms applicable to covered code created - under this License. - - 6. Redistributions of any form whatsoever must retain the following - acknowledgment: - "This product includes PHP, freely available from - ". - -THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND -ANY EXPRESSED 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 PHP -DEVELOPMENT TEAM OR ITS 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. - --------------------------------------------------------------------- - -This software consists of voluntary contributions made by many -individuals on behalf of the PHP Group. - -The PHP Group can be contacted via Email at group@php.net. - -For more information on the PHP Group and the PHP project, -please see . - -This product includes the Zend Engine, freely available at -. +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/tools/pear/OS/Guess.php b/tools/pear/OS/Guess.php index d5aa295c3..ce960933c 100644 --- a/tools/pear/OS/Guess.php +++ b/tools/pear/OS/Guess.php @@ -4,14 +4,14 @@ * * PHP versions 4 and 5 * - * @category pear - * @package PEAR - * @author Stig Bakken - * @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 + * @category pear + * @package PEAR + * @author Stig Bakken + * @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 @@ -80,15 +80,15 @@ * * This class uses php_uname() to grok information about the current OS * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Gregory 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 - * @since Class available since Release 0.1 + * @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 { @@ -138,13 +138,9 @@ class OS_Guess $release = "$parts[3].$parts[2]"; break; case 'Windows' : - switch ($parts[1]) { - case '95/98': - $release = '9x'; - break; - default: - $release = $parts[1]; - break; + $release = $parts[1]; + if ($release == '95/98') { + $release = '9x'; } $cpu = 'i386'; break; @@ -157,18 +153,10 @@ class OS_Guess $sysname = 'darwin'; $nodename = $parts[2]; $release = $parts[3]; - if ($cpu == 'Macintosh') { - if ($parts[$n - 2] == 'Power') { - $cpu = 'powerpc'; - } - } + $cpu = $this->_determineIfPowerpc($cpu, $parts); break; case 'Darwin' : - if ($cpu == 'Macintosh') { - if ($parts[$n - 2] == 'Power') { - $cpu = 'powerpc'; - } - } + $cpu = $this->_determineIfPowerpc($cpu, $parts); $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]); break; default: @@ -187,6 +175,15 @@ class OS_Guess 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; @@ -196,74 +193,29 @@ class OS_Guess $major = $minor = 0; include_once "System.php"; - if (@is_link('/lib64/libc.so.6')) { - // Let's try reading the libc.so.6 symlink - if (preg_match('/^libc-(.*)\.so$/', basename(readlink('/lib64/libc.so.6')), $matches)) { - list($major, $minor) = explode('.', $matches[1]); - } - } else if (@is_link('/lib/libc.so.6')) { - // Let's try reading the libc.so.6 symlink - if (preg_match('/^libc-(.*)\.so$/', basename(readlink('/lib/libc.so.6')), $matches)) { - list($major, $minor) = explode('.', $matches[1]); + // 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) && - @file_exists('/usr/include/features.h') && - @is_readable('/usr/include/features.h')) { - if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) { - $features_file = fopen('/usr/include/features.h', 'rb'); - while (!feof($features_file)) { - $line = fgets($features_file, 8192); - if (!$line || (strpos($line, '#define') === false)) { - 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; - } - continue; - } - } - fclose($features_file); - if (!isset($glibc_major) || !isset($glibc_minor)) { - return $glibc = ''; - } - return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ; - } // no cpp - - $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); - } // features.h + if (!($major && $minor)) { + $versions = $this->_readGlibCVersionFromFeaturesHeaderFile(); + } + if (is_array($versions) && $versions != []) { + list($major, $minor) = $versions; + } if (!($major && $minor)) { return $glibc = ''; @@ -272,6 +224,102 @@ class OS_Guess 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)) { @@ -328,16 +376,20 @@ class OS_Guess function _matchFragment($fragment, $value) { if (strcspn($fragment, '*?') < strlen($fragment)) { - $reg = '/^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '\\z/'; + $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: - */ + */ \ No newline at end of file diff --git a/tools/pear/PEAR.php b/tools/pear/PEAR.php index fee6638f4..43c65dbdb 100644 --- a/tools/pear/PEAR.php +++ b/tools/pear/PEAR.php @@ -49,7 +49,9 @@ $GLOBALS['_PEAR_destructor_object_list'] = array(); $GLOBALS['_PEAR_shutdown_funcs'] = array(); $GLOBALS['_PEAR_error_handler_stack'] = array(); -@ini_set('track_errors', true); +if(function_exists('ini_set')) { + @ini_set('track_errors', true); +} /** * Base class for other PEAR classes. Provides rudimentary @@ -219,7 +221,7 @@ class PEAR ); } return call_user_func_array( - array(get_class(), '_' . $method), + array(__CLASS__, '_' . $method), array_merge(array($this), $arguments) ); } @@ -232,7 +234,7 @@ class PEAR ); } return call_user_func_array( - array(get_class(), '_' . $method), + array(__CLASS__, '_' . $method), array_merge(array(null), $arguments) ); } @@ -859,6 +861,7 @@ class PEAR_Error var $message = ''; var $userinfo = ''; var $backtrace = null; + var $callback = null; /** * PEAR_Error constructor diff --git a/tools/pear/PEAR/ErrorStack.php b/tools/pear/PEAR/ErrorStack.php index 6619fbb1e..c9177a88a 100644 --- a/tools/pear/PEAR/ErrorStack.php +++ b/tools/pear/PEAR/ErrorStack.php @@ -1,7 +1,7 @@ * array( @@ -44,7 +44,7 @@ $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. @@ -60,7 +60,7 @@ $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array( /** * 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() @@ -71,7 +71,7 @@ $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() @@ -165,14 +165,14 @@ class PEAR_ErrorStack { * @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 @@ -181,7 +181,7 @@ class PEAR_ErrorStack { * @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 @@ -236,10 +236,10 @@ class PEAR_ErrorStack { $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 @@ -275,7 +275,7 @@ class PEAR_ErrorStack { /** * Internal error handler for PEAR_ErrorStack class - * + * * Dies if the error is an exception (and would have died anyway) * @access private */ @@ -292,10 +292,10 @@ class PEAR_ErrorStack { die($message); } } - + /** * Set up a PEAR::Log object for all error stacks that don't have one - * @param Log $log + * @param Log $log */ public static function setDefaultLogger(&$log) { @@ -305,10 +305,10 @@ class PEAR_ErrorStack { $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; } } - + /** * Set up a PEAR::Log object for this error stack - * @param Log $log + * @param Log $log */ function setLogger(&$log) { @@ -318,10 +318,10 @@ class PEAR_ErrorStack { $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 @@ -336,10 +336,10 @@ class PEAR_ErrorStack { } } } - + /** * 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 @@ -348,10 +348,10 @@ class PEAR_ErrorStack { { 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 @@ -365,10 +365,10 @@ class PEAR_ErrorStack { $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() @@ -387,15 +387,15 @@ class PEAR_ErrorStack { } } } - + /** * 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 @@ -407,7 +407,7 @@ class PEAR_ErrorStack { { array_push($this->_errorCallback, $cb); } - + /** * Remove a callback from the error callback stack * @see pushCallback() @@ -420,7 +420,7 @@ class PEAR_ErrorStack { } return array_pop($this->_errorCallback); } - + /** * Set a temporary overriding error callback for every package error stack * @@ -434,7 +434,7 @@ class PEAR_ErrorStack { { array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb); } - + /** * Remove a temporary overriding error callback * @see staticPushCallback() @@ -448,15 +448,15 @@ class PEAR_ErrorStack { } 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 @@ -474,7 +474,7 @@ class PEAR_ErrorStack { * @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, @@ -487,7 +487,7 @@ class PEAR_ErrorStack { * //['repackage' => $err] repackaged error array/Exception class * ); * - * + * * Normally, the previous array is returned. */ function push($code, $level = 'error', $params = array(), $msg = false, @@ -501,7 +501,7 @@ class PEAR_ErrorStack { } $context = call_user_func($this->_contextCallback, $code, $params, $backtrace); } - + // save error $time = explode(' ', microtime()); $time = $time[1] + $time[0]; @@ -524,7 +524,7 @@ class PEAR_ErrorStack { $msg = call_user_func_array($this->_msgCallback, array(&$this, $err)); $err['message'] = $msg; - } + } $push = $log = true; $die = false; // try the overriding callback first @@ -546,16 +546,16 @@ class PEAR_ErrorStack { } if (is_callable($callback)) { switch(call_user_func($callback, $err)){ - case PEAR_ERRORSTACK_IGNORE: + case PEAR_ERRORSTACK_IGNORE: return $err; break; - case PEAR_ERRORSTACK_PUSH: + case PEAR_ERRORSTACK_PUSH: $log = false; break; - case PEAR_ERRORSTACK_LOG: + case PEAR_ERRORSTACK_LOG: $push = false; break; - case PEAR_ERRORSTACK_DIE: + case PEAR_ERRORSTACK_DIE: $die = true; break; // anything else returned has the same effect as pushandlog @@ -581,10 +581,10 @@ class PEAR_ErrorStack { } 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 @@ -614,7 +614,7 @@ class PEAR_ErrorStack { } return $s->push($code, $level, $params, $msg, $repackage, $backtrace); } - + /** * Log an error using PEAR::Log * @param array $err Error array @@ -649,10 +649,10 @@ class PEAR_ErrorStack { } } - + /** * 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 @@ -699,10 +699,10 @@ class PEAR_ErrorStack { } 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 @@ -736,7 +736,7 @@ class PEAR_ErrorStack { $this->_errorsByLevel = array(); return $ret; } - + /** * Determine whether there are any errors on a single error stack, or on any error stack * @@ -761,7 +761,7 @@ class PEAR_ErrorStack { } 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 @@ -771,7 +771,7 @@ class PEAR_ErrorStack { * @param array $sortfunc Function used to sort a merged array - default * sorts by time, and should be good for most cases * - * @return array + * @return array */ public static function staticGetErrors( $purge = false, $level = false, $merge = false, @@ -796,7 +796,7 @@ class PEAR_ErrorStack { } return $ret; } - + /** * Error sorting function, sorts by time * @access private @@ -850,7 +850,7 @@ class PEAR_ErrorStack { $ret = array('file' => $filebacktrace['file'], 'line' => $filebacktrace['line']); // rearrange for eval'd code or create function errors - if (strpos($filebacktrace['file'], '(') && + if (strpos($filebacktrace['file'], '(') && preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'], $matches)) { $ret['file'] = $matches[1]; @@ -872,26 +872,26 @@ class PEAR_ErrorStack { } 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 @@ -929,7 +929,7 @@ class PEAR_ErrorStack { } return $mainmsg; } - + /** * Standard Error Message Template generator from code * @return string @@ -941,15 +941,15 @@ class PEAR_ErrorStack { } 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 @@ -960,11 +960,11 @@ class PEAR_ErrorStack { { $this->_errorMsgs = $template; } - - + + /** * emulate PEAR::raiseError() - * + * * @return PEAR_Error */ function raiseError() @@ -976,4 +976,4 @@ class PEAR_ErrorStack { } $stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack'); $stack->pushCallback(array('PEAR_ErrorStack', '_handleError')); -?> +?> \ No newline at end of file diff --git a/tools/pear/System.php b/tools/pear/System.php index cf8f37993..2d5acaa3a 100644 --- a/tools/pear/System.php +++ b/tools/pear/System.php @@ -530,7 +530,9 @@ class System // 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) { - return $file; + if (file_exists($file)) { + return $file; + } } else { if (is_executable($file)) { return $file; @@ -625,4 +627,4 @@ class System } return $files; } -} +} \ No newline at end of file diff --git a/tools/profiling/Controller.php b/tools/profiling/Controller.php index 548bbcf0e..0c2b9da01 100644 --- a/tools/profiling/Controller.php +++ b/tools/profiling/Controller.php @@ -32,6 +32,7 @@ abstract class Controller extends ControllerCore protected $total_modules_time = 0; protected $total_modules_memory = 0; protected $global_var_size = array(); + protected $total_cache_size = 0; protected $modules_perfs = array(); protected $hooks_perfs = array(); @@ -40,6 +41,7 @@ abstract class Controller extends ControllerCore protected $profiler = array(); + private function getMemoryColor($n) { $n /= 1048576; @@ -336,7 +338,7 @@ abstract class Controller extends ControllerCore ); if (preg_match('/^\s*select\s+/i', $data['query'])) { $explain = Db::getInstance()->executeS('explain '.$data['query']); - if (stristr($explain[0]['Extra'], 'filesort')) { + if (isset($explain[0]['Extra']) && stristr($explain[0]['Extra'], 'filesort')) { $query_row['filesort'] = true; } foreach ($explain as $row) { diff --git a/tools/profiling/Tools.php b/tools/profiling/Tools.php index 5849bdcae..d1e107093 100644 --- a/tools/profiling/Tools.php +++ b/tools/profiling/Tools.php @@ -26,7 +26,7 @@ class Tools extends ToolsCore { - public static function redirect($url, $base_uri = __PS_BASE_URI__, Link $link = null, $headers = null) + public static function redirect($url, $base_uri = __PS_BASE_URI__, ?Link $link = null, $headers = null) { if (!$link) { $link = Context::getContext()->link; diff --git a/tools/random_compat/build-phar.sh b/tools/random_compat/build-phar.sh new file mode 100755 index 000000000..b4a5ba31c --- /dev/null +++ b/tools/random_compat/build-phar.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +basedir=$( dirname $( readlink -f ${BASH_SOURCE[0]} ) ) + +php -dphar.readonly=0 "$basedir/other/build_phar.php" $* \ No newline at end of file diff --git a/tools/random_compat/composer.json b/tools/random_compat/composer.json deleted file mode 100644 index 34f1381d5..000000000 --- a/tools/random_compat/composer.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "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": "4.*|5.*" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "autoload": { - "files": [ - "lib/random.php" - ] - } -} diff --git a/tools/random_compat/dist/index.php b/tools/random_compat/dist/index.php deleted file mode 100644 index eaa1dc457..000000000 --- a/tools/random_compat/dist/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2022 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../'); -exit; diff --git a/tools/random_compat/index.php b/tools/random_compat/index.php deleted file mode 100644 index eaa1dc457..000000000 --- a/tools/random_compat/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2022 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../'); -exit; diff --git a/tools/random_compat/lib/byte_safe_strings.php b/tools/random_compat/lib/byte_safe_strings.php deleted file mode 100644 index ef24488f9..000000000 --- a/tools/random_compat/lib/byte_safe_strings.php +++ /dev/null @@ -1,195 +0,0 @@ - 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/tools/random_compat/lib/cast_to_int.php b/tools/random_compat/lib/cast_to_int.php deleted file mode 100644 index 1b1bbfe8d..000000000 --- a/tools/random_compat/lib/cast_to_int.php +++ /dev/null @@ -1,77 +0,0 @@ - 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/tools/random_compat/lib/error_polyfill.php b/tools/random_compat/lib/error_polyfill.php deleted file mode 100644 index c02c5c8b4..000000000 --- a/tools/random_compat/lib/error_polyfill.php +++ /dev/null @@ -1,49 +0,0 @@ - -* @copyright 2010-2022 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../'); -exit; diff --git a/tools/random_compat/lib/random.php b/tools/random_compat/lib/random.php index 6df1cb0ce..c7731a56f 100644 --- a/tools/random_compat/lib/random.php +++ b/tools/random_compat/lib/random.php @@ -3,8 +3,8 @@ * Random_* Compatibility Library * for using the new PHP 7 random_* API in PHP 5 projects * - * @version 2.0.17 - * @released 2018-07-04 + * @version 2.99.99 + * @released 2018-06-06 * * The MIT License (MIT) * @@ -29,198 +29,4 @@ * SOFTWARE. */ -if (!defined('PHP_VERSION_ID')) { - // This constant was introduced in PHP 5.2.7 - $RandomCompatversion = array_map('intval', explode('.', PHP_VERSION)); - define( - 'PHP_VERSION_ID', - $RandomCompatversion[0] * 10000 - + $RandomCompatversion[1] * 100 - + $RandomCompatversion[2] - ); - $RandomCompatversion = null; -} - -/** - * PHP 7.0.0 and newer have these functions natively. - */ -if (PHP_VERSION_ID >= 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 (method_exists($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; +// NOP diff --git a/tools/random_compat/lib/random_bytes_com_dotnet.php b/tools/random_compat/lib/random_bytes_com_dotnet.php deleted file mode 100644 index 537d02b27..000000000 --- a/tools/random_compat/lib/random_bytes_com_dotnet.php +++ /dev/null @@ -1,91 +0,0 @@ -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/tools/random_compat/lib/random_bytes_dev_urandom.php b/tools/random_compat/lib/random_bytes_dev_urandom.php deleted file mode 100644 index c4e31ccbb..000000000 --- a/tools/random_compat/lib/random_bytes_dev_urandom.php +++ /dev/null @@ -1,190 +0,0 @@ - $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/tools/random_compat/lib/random_bytes_libsodium.php b/tools/random_compat/lib/random_bytes_libsodium.php deleted file mode 100644 index 2e5629018..000000000 --- a/tools/random_compat/lib/random_bytes_libsodium.php +++ /dev/null @@ -1,91 +0,0 @@ - 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/tools/random_compat/lib/random_bytes_libsodium_legacy.php b/tools/random_compat/lib/random_bytes_libsodium_legacy.php deleted file mode 100644 index f78b2199a..000000000 --- a/tools/random_compat/lib/random_bytes_libsodium_legacy.php +++ /dev/null @@ -1,93 +0,0 @@ - 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/tools/random_compat/lib/random_bytes_mcrypt.php b/tools/random_compat/lib/random_bytes_mcrypt.php deleted file mode 100644 index 0b13fa73c..000000000 --- a/tools/random_compat/lib/random_bytes_mcrypt.php +++ /dev/null @@ -1,79 +0,0 @@ - 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/tools/random_compat/other/build_phar.php b/tools/random_compat/other/build_phar.php new file mode 100644 index 000000000..70ef4b2ed --- /dev/null +++ b/tools/random_compat/other/build_phar.php @@ -0,0 +1,57 @@ +buildFromDirectory(dirname(__DIR__).'/lib'); +rename( + dirname(__DIR__).'/lib/index.php', + dirname(__DIR__).'/lib/random.php' +); + +/** + * If we pass an (optional) path to a private key as a second argument, we will + * sign the Phar with OpenSSL. + * + * If you leave this out, it will produce an unsigned .phar! + */ +if ($argc > 1) { + if (!@is_readable($argv[1])) { + echo 'Could not read the private key file:', $argv[1], "\n"; + exit(255); + } + $pkeyFile = file_get_contents($argv[1]); + + $private = openssl_get_privatekey($pkeyFile); + if ($private !== false) { + $pkey = ''; + openssl_pkey_export($private, $pkey); + $phar->setSignatureAlgorithm(Phar::OPENSSL, $pkey); + + /** + * Save the corresponding public key to the file + */ + if (!@is_readable($dist.'/random_compat.phar.pubkey')) { + $details = openssl_pkey_get_details($private); + file_put_contents( + $dist.'/random_compat.phar.pubkey', + $details['key'] + ); + } + } else { + echo 'An error occurred reading the private key from OpenSSL.', "\n"; + exit(255); + } +} diff --git a/tools/random_compat/psalm-autoload.php b/tools/random_compat/psalm-autoload.php new file mode 100644 index 000000000..d71d1b818 --- /dev/null +++ b/tools/random_compat/psalm-autoload.php @@ -0,0 +1,9 @@ + + + + + + + + + + + + + + + diff --git a/tools/smarty/.htaccess b/tools/smarty/.htaccess deleted file mode 100644 index 3de9e4008..000000000 --- a/tools/smarty/.htaccess +++ /dev/null @@ -1,10 +0,0 @@ -# Apache 2.2 - - Order deny,allow - Deny from all - - -# Apache 2.4 - - Require all denied - diff --git a/tools/smarty/Autoloader.php b/tools/smarty/Autoloader.php index c09361b66..da7e32abf 100644 --- a/tools/smarty/Autoloader.php +++ b/tools/smarty/Autoloader.php @@ -5,6 +5,11 @@ * @package Smarty */ + +if (!defined('SMARTY_HELPER_FUNCTIONS_LOADED')) { + include __DIR__ . '/functions.php'; +} + /** * Smarty Autoloader * @@ -39,7 +44,7 @@ class Smarty_Autoloader * * @var array */ - public static $rootClasses = array('smarty' => 'Smarty.class.php', 'smartybc' => 'SmartyBC.class.php',); + public static $rootClasses = array('smarty' => 'Smarty.class.php'); /** * Registers Smarty_Autoloader backward compatible to older installations. @@ -73,14 +78,10 @@ class Smarty_Autoloader */ public static function register($prepend = false) { - self::$SMARTY_DIR = defined('SMARTY_DIR') ? SMARTY_DIR : dirname(__FILE__) . DIRECTORY_SEPARATOR; + self::$SMARTY_DIR = defined('SMARTY_DIR') ? SMARTY_DIR : __DIR__ . DIRECTORY_SEPARATOR; self::$SMARTY_SYSPLUGINS_DIR = defined('SMARTY_SYSPLUGINS_DIR') ? SMARTY_SYSPLUGINS_DIR : self::$SMARTY_DIR . 'sysplugins' . DIRECTORY_SEPARATOR; - if (version_compare(PHP_VERSION, '5.3.0', '>=')) { - spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend); - } else { - spl_autoload_register(array(__CLASS__, 'autoload')); - } + spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend); } /** @@ -93,7 +94,7 @@ class Smarty_Autoloader if ($class[ 0 ] !== 'S' || strpos($class, 'Smarty') !== 0) { return; } - $_class = strtolower($class); + $_class = smarty_strtolower_ascii($class); if (isset(self::$rootClasses[ $_class ])) { $file = self::$SMARTY_DIR . self::$rootClasses[ $_class ]; if (is_file($file)) { diff --git a/tools/smarty/CHANGELOG.md b/tools/smarty/CHANGELOG.md deleted file mode 100644 index e3bb93a4f..000000000 --- a/tools/smarty/CHANGELOG.md +++ /dev/null @@ -1,3466 +0,0 @@ -# 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.39] - 2021-02-17 - -### Security -- Prevent access to `$smarty.template_object` in sandbox mode -- Fixed code injection vulnerability by using illegal function names in `{function name='blah'}{/function}` - -## [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 - -29.10.2018 - - bugfix Smarty::$php_handling == PHP_PASSTHRU (default) did eat the "\n" (newline) character if it did directly followed - a PHP tag like "?>" or other https://github.com/smarty-php/smarty/issues/501 - -14.10.2018 - - bugfix autoloader exit shortcut https://github.com/smarty-php/smarty/issues/467 - -11.10.2018 - - bugfix {insert} not works when caching is enabled and included template is present - https://github.com/smarty-php/smarty/issues/496 - - bugfix in date-format modifier; NULL at date string or default_date did not produce correct output - https://github.com/smarty-php/smarty/pull/458 - -09.10.2018 - - bugfix fix of 26.8.2017 https://github.com/smarty-php/smarty/issues/327 - modifier is applied to sum expression https://github.com/smarty-php/smarty/issues/491 - - bugfix indexed arrays could not be defined "array(...)"" - -18.09.2018 - - bugfix large plain text template sections without a Smarty tag > 700kB could - 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 - -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 - -31.08.2018 - - bugfix some custom left and right delimiters like '{^' '^}' did not work - https://github.com/smarty-php/smarty/issues/450 https://github.com/smarty-php/smarty/pull/482 - - - reformating for PSR-2 coding standards https://github.com/smarty-php/smarty/pull/483 - - - bugfix on Windows absolute filepathes did fail if the drive letter was followed by a linux DIRECTORY_SEPARATOR - like C:/ at Smarty > 3.1.33-dev-5 https://github.com/smarty-php/smarty/issues/451 - - - PSR-2 code style fixes for config and template file Lexer/Parser generated with - the Smarty Lexer/Parser generator from https://github.com/smarty-php/smarty-lexer - https://github.com/smarty-php/smarty/pull/483 - -26.08.2018 - - 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 - -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 - -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 - https://github.com/smarty-php/smarty/pull/438 - - improvement do not compute total property in {foreach} if not needed https://github.com/smarty-php/smarty/issues/443 - - bugfix plugins may not be loaded when setMergeCompiledIncludes is true https://github.com/smarty-php/smarty/issues/435 - -26.04.2018 - - bugfix regarding Security Vulnerability did not solve the problem under Linux. - Security issue CVE-2018-16831 - -## 3.1.32 - (24.04.2018) -24.04.2018 - - bugfix possible Security Vulnerability in Smarty_Security class. - -26.03.2018 - - bugfix plugins may not be loaded if {function} or {block} tags are executed in nocache mode - https://github.com/smarty-php/smarty/issues/371 - -26.03.2018 - - new feature {parent} = {$smarty.block.parent} {child} = {$smarty.block.child} - -23.03.2018 - - bugfix preg_replace could fail on large content resulting in a blank page https://github.com/smarty-php/smarty/issues/417 - -21.03.2018 - - bugfix {$smarty.section...} used outside {section}{/section} showed incorrect values if {section}{/section} was called inside - another loop https://github.com/smarty-php/smarty/issues/422 - - bugfix short form of {section} attributes did not work https://github.com/smarty-php/smarty/issues/428 - -17.03.2018 - - improvement Smarty::compileAllTemplates() exit with a non-zero status code if max errors is reached https://github.com/smarty-php/smarty/pull/402 - -16.03.2018 - - bugfix extends resource did not work with user defined left/right delimiter https://github.com/smarty-php/smarty/issues/419 - -22.11.2017 - - bugfix {break} and {continue} could fail if {foreach}{/foreach} did contain other - looping tags like {for}, {section} and {while} https://github.com/smarty-php/smarty/issues/323 - -20.11.2017 - - bugfix rework of newline spacing between tag code and template text. - now again identical with Smarty2 (forum topic 26878) - - replacement of " by ' - -05.11.2017 - - lexer/parser optimization - - code cleanup and optimizations - - bugfix {$smarty.section.name.loop} used together with {$smarty.section.name.total} could produce - wrong results (forum topic 27041) - -26.10.2017 - - bugfix Smarty version was not filled in header comment of compiled and cached files - - optimization replace internal Smarty::$ds property by DIRECTORY_SEPARATOR - - deprecate functions Smarty::muteExpectedErrors() and Smarty::unmuteExpectedErrors() - as Smarty does no longer use error suppression like @filemtime(). - for backward compatibility code is moved from Smarty class to an external class and still can be - called. - - correction of PHPDoc blocks - - minor code cleanup - -21.10.2017 - - bugfix custom delimiters could fail since modification of version 3.1.32-dev-23 - https://github.com/smarty-php/smarty/issues/394 - -18.10.2017 - - bugfix fix implementation of unclosed block tag in double quoted string of 12.10.2017 - https://github.com/smarty-php/smarty/issues/396 https://github.com/smarty-php/smarty/issues/397 - https://github.com/smarty-php/smarty/issues/391 https://github.com/smarty-php/smarty/issues/392 - -12.10.2017 - - bugfix $smarty.block.child and $smarty.block.parent could not be used like any - $smarty special variable https://github.com/smarty-php/smarty/issues/393 - - unclosed block tag in double quoted string must throw compiler exception. - https://github.com/smarty-php/smarty/issues/391 https://github.com/smarty-php/smarty/issues/392 - -07.10.2017 - - bugfix modification of 9.8.2017 did fail on some recursive - tag nesting. https://github.com/smarty-php/smarty/issues/389 - -26.8.2017 - - bugfix chained modifier failed when last modifier parameter is a signed value - https://github.com/smarty-php/smarty/issues/327 - - bugfix templates filepath with multibyte characters did not work - https://github.com/smarty-php/smarty/issues/385 - - bugfix {make_nocache} did display code if the template did not contain other nocache code - https://github.com/smarty-php/smarty/issues/369 - -09.8.2017 - - improvement repeated delimiter like {{ and }} will be treated as literal - https://groups.google.com/forum/#!topic/smarty-developers/h9r82Bx4KZw - -05.8.2017 - - bugfix wordwrap modifier could fail if used in nocache code. - converted plugin file shared.mb_wordwrap.php into modifier.mb_wordwrap.php - - cleanup of _getSmartyObj() - -31.7.2017 - - Call clearstatcache() after mkdir() failure https://github.com/smarty-php/smarty/pull/379 - -30.7.2017 - - rewrite mkdir() bugfix to retry automatically see https://github.com/smarty-php/smarty/pull/377 - https://github.com/smarty-php/smarty/pull/379 - -21.7.2017 - - security possible PHP code injection on custom resources at display() or fetch() - calls if the resource does not sanitize the template name - - bugfix fix 'mkdir(): File exists' error on create directory from parallel - processes https://github.com/smarty-php/smarty/pull/377 - - bugfix solve preg_match() hhvm parameter problem https://github.com/smarty-php/smarty/pull/372 - -27.5.2017 - - bugfix change compiled code for registered function and modifiers to called as callable to allow closures - https://github.com/smarty-php/smarty/pull/368, https://github.com/smarty-php/smarty/issues/273 - - bugfix https://github.com/smarty-php/smarty/pull/368 did break the default plugin handler - - improvement replace phpversion() by PHP_VERSION constant. - https://github.com/smarty-php/smarty/pull/363 - -21.5.2017 - - performance store flag for already required shared plugin functions in static variable or - Smarty's $_cache to improve performance when plugins are often called - https://github.com/smarty-php/smarty/commit/51e0d5cd405d764a4ea257d1bac1fb1205f74528#commitcomment-22280086 - - bugfix remove special treatment of classes implementing ArrayAccess in {foreach} - https://github.com/smarty-php/smarty/issues/332 - - bugfix remove deleted files by clear_cache() and clear_compiled_template() from - ACP cache if present, add some is_file() checks to avoid possible warnings on filemtime() - caused by above functions. - https://github.com/smarty-php/smarty/issues/341 - - bugfix version 3.1.31 did fail under PHP 5.2 - https://github.com/smarty-php/smarty/issues/365 - -19.5.2017 - - change properties $accessMap and $obsoleteProperties from private to protected - https://github.com/smarty-php/smarty/issues/351 - - new feature The named capture buffers can now be accessed also as array - See NEWS_FEATURES.txt https://github.com/smarty-php/smarty/issues/366 - - improvement check if ini_get() and ini_set() not disabled - https://github.com/smarty-php/smarty/pull/362 - -24.4.2017 - - fix spelling https://github.com/smarty-php/smarty/commit/e3eda8a5f5653d8abb960eb1bc47e3eca679b1b4#commitcomment-21803095 - -17.4.2017 - - correct generated code on empty() and isset() call, observe change PHP behaviour since PHP 5.5 - https://github.com/smarty-php/smarty/issues/347 - -14.4.2017 - - merge pull requests https://github.com/smarty-php/smarty/pull/349, https://github.com/smarty-php/smarty/pull/322 and https://github.com/smarty-php/smarty/pull/337 to fix spelling and annotation - -13.4.2017 - - bugfix array_merge() parameter should be checked https://github.com/smarty-php/smarty/issues/350 - -## 3.1.31 - (14.12.2016) - 23.11.2016 - - move template object cache into static variables - - 19.11.2016 - - bugfix inheritance root child templates containing nested {block}{/block} could call sub-bock content from parent - template https://github.com/smarty-php/smarty/issues/317 - - change version checking - - 11.11.2016 - - bugfix when Smarty is using a cached template object on Smarty::fetch() or Smarty::isCached() the inheritance data - must be removed https://github.com/smarty-php/smarty/issues/312 - - smaller speed optimization - - 08.11.2016 - - add bootstrap file to load and register Smarty_Autoloader. Change composer.json to make it known to composer - - 07.11.2016 - - optimization of lexer speed https://github.com/smarty-php/smarty/issues/311 - - 27.10.2016 - - bugfix template function definitions array has not been cached between Smarty::fetch() and Smarty::display() calls - https://github.com/smarty-php/smarty/issues/301 - - 23.10.2016 - - improvement/bugfix when Smarty::fetch() is called on a template object the inheritance and tplFunctions property - should be copied to the called template object - - 21.10.2016 - - bugfix for compile locking touched timestamp of old compiled file was not restored on compilation error https://github.com/smarty-php/smarty/issues/308 - - 20.10.2016 - - bugfix nocache code was not removed in cache file when subtemplate did contain PHP short tags in text but no other - nocache code https://github.com/smarty-php/smarty/issues/300 - - 19.10.2016 - - bugfix {make_nocache $var} did fail when variable value did contain '\' https://github.com/smarty-php/smarty/issues/305 - - bugfix {make_nocache $var} remove spaces from variable value https://github.com/smarty-php/smarty/issues/304 - - 12.10.2016 - - bugfix {include} with template names including variable or constants could fail after bugfix from - 28.09.2016 https://github.com/smarty-php/smarty/issues/302 - - 08.10.2016 - - optimization move runtime extension for template functions into Smarty objects - - 29.09.2016 - - improvement new Smarty::$extends_recursion property to disable execution of {extends} in templates called by extends resource - https://github.com/smarty-php/smarty/issues/296 - - 28.09.2016 - - bugfix the generated code for calling a subtemplate must pass the template resource name in single quotes https://github.com/smarty-php/smarty/issues/299 - - bugfix nocache hash was not removed for tags in subtemplates https://github.com/smarty-php/smarty/issues/300 - - 27.09.2016 - - bugfix when Smarty does use an internally cached template object on Smarty::fetch() calls - the template and config variables must be cleared https://github.com/smarty-php/smarty/issues/297 - - 20.09.2016 - - bugfix some $smarty special template variables are no longer accessed as real variable. - using them on calls like {if isset($smarty.foo)} or {if empty($smarty.foo)} will fail - http://www.smarty.net/forums/viewtopic.php?t=26222 - - temporary fix for https://github.com/smarty-php/smarty/issues/293 main reason still under investigation - - improvement new tags {block_parent} {block_child} in template inheritance - - 19.09.2016 - - optimization clear compiled and cached folder completely on detected version change - - cleanup convert cache resource file method clear into runtime extension - - 15.09.2016 - - bugfix assigning a variable in if condition by function like {if $value = array_shift($array)} the function got called twice https://github.com/smarty-php/smarty/issues/291 - - bugfix function plugins called with assign attribute like {foo assign='bar'} did not output returned content because - because assumption was made that it was assigned to a variable https://github.com/smarty-php/smarty/issues/292 - - bugfix calling $smarty->isCached() on a not existing cache file with $smarty->cache_locking = true; could cause a 10 second delay http://www.smarty.net/forums/viewtopic.php?t=26282 - - improvement make Smarty::clearCompiledTemplate() on custom resource independent from changes of templateId computation - - 11.09.2016 - - improvement {math} misleading E_USER_WARNING messages when parameter value = null https://github.com/smarty-php/smarty/issues/288 - - improvement move often used code snippets into methods - - performance Smarty::configLoad() did load unneeded template source object - - 09.09.2016 - - bugfix/optimization {foreach} did not execute the {foreachelse} when iterating empty objects https://github.com/smarty-php/smarty/pull/287 - - bugfix {foreach} must keep the @properties when restoring a saved $item variable as the properties might be used outside {foreach} https://github.com/smarty-php/smarty/issues/267 - - improvement {foreach} observe {break n} and {continue n} nesting levels when restoring saved $item and $key variables - - 08.09.2016 - - bugfix implement wrapper for removed method getConfigVariable() https://github.com/smarty-php/smarty/issues/286 - - 07.09.2016 - - bugfix using nocache like attribute with value true like {plugin nocache=true} did not work https://github.com/smarty-php/smarty/issues/285 - - bugfix uppercase TRUE, FALSE and NULL did not work when security was enabled https://github.com/smarty-php/smarty/issues/282 - - bugfix when {foreach} was looping over an object the total property like {$item@total} did always return 1 https://github.com/smarty-php/smarty/issues/281 - - bugfix {capture}{/capture} did add in 3.1.30 unintended additional blank lines https://github.com/smarty-php/smarty/issues/268 - - 01.09.2016 - - performance require_once should be called only once for shared plugins https://github.com/smarty-php/smarty/issues/280 - - 26.08.2016 - - bugfix change of 23.08.2016 failed on linux when use_include_path = true - - 23.08.2016 - - bugfix remove constant DS as shortcut for DIRECTORY_SEPARATOR as the user may have defined it to something else https://github.com/smarty-php/smarty/issues/277 - - 20.08-2016 - - bugfix {config_load ... scope="global"} shall not throw an arror but fallback to scope="smarty" https://github.com/smarty-php/smarty/issues/274 - - bugfix {make_nocache} failed when using composer autoloader https://github.com/smarty-php/smarty/issues/275 - - 14.08.2016 - - bugfix $smarty_>debugging = true; did E_NOTICE messages when {eval} tag was used https://github.com/smarty-php/smarty/issues/266 - - bugfix Class 'Smarty_Internal_Runtime_ValidateCompiled' not found when upgrading from some older Smarty versions with existing - 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) - - 07.08.2016 - - bugfix update of 04.08.2016 was incomplete - - 05.08.2016 - - bugfix compiling of templates failed when the Smarty delimiter did contain '/' https://github.com/smarty-php/smarty/issues/264 - - updated error checking at template and config default handler - - 04.08.2016 - - improvement move template function source parameter into extension - - 26.07.2016 - - optimization unneeded loading of compiled resource - - 24.07.2016 - - regression this->addPluginsDir('/abs/path/to/dir') adding absolute path without trailing '/' did fail https://github.com/smarty-php/smarty/issues/260 - - 23.07.2016 - - bugfix setTemplateDir('/') and setTemplateDir('') did create wrong absolute filepath https://github.com/smarty-php/smarty/issues/245 - - optimization of filepath normalization - - improvement remove double function declaration in plugin shared.escape_special_cars.php https://github.com/smarty-php/smarty/issues/229 - - 19.07.2016 - - bugfix multiple {include} with relative filepath within {block}{/block} could fail https://github.com/smarty-php/smarty/issues/246 - - bugfix {math} shell injection vulnerability patch provided by Tim Weber - - 18.07.2016 - - bugfix {foreach} if key variable and item@key attribute have been used both the key variable was not updated https://github.com/smarty-php/smarty/issues/254 - - bugfix modifier on plugins like {plugin|modifier ... } did fail when the plugin does return an array https://github.com/smarty-php/smarty/issues/228 - - bugfix avoid opcache_invalidate to result in ErrorException when opcache.restrict_api is not empty https://github.com/smarty-php/smarty/pull/244 - - bugfix multiple {include} with relative filepath within {block}{/block} could fail https://github.com/smarty-php/smarty/issues/246 - - 14.07.2016 - - bugfix wrong parameter on compileAllTemplates() and compileAllConfig() https://github.com/smarty-php/smarty/issues/231 - - 13.07.2016 - - bugfix PHP 7 compatibility on registered compiler plugins https://github.com/smarty-php/smarty/issues/241 - - update testInstall() https://github.com/smarty-php/smarty/issues/248https://github.com/smarty-php/smarty/issues/248 - - bugfix enable debugging could fail when template objects did already exists https://github.com/smarty-php/smarty/issues/237 - - bugfix template function data should be merged when loading subtemplate https://github.com/smarty-php/smarty/issues/240 - - bugfix wrong parameter on compileAllTemplates() https://github.com/smarty-php/smarty/issues/231 - - 12.07.2016 - - bugfix {foreach} item variable must be created also on empty from array https://github.com/smarty-php/smarty/issues/238 and https://github.com/smarty-php/smarty/issues/239 - - bugfix enableSecurity() must init cache flags https://github.com/smarty-php/smarty/issues/247 - - 27.05.2016 - - bugfix/improvement of compileAlltemplates() follow symlinks in template folder (PHP >= 5.3.1) https://github.com/smarty-php/smarty/issues/224 - clear internal cache and expension handler for each template to avoid possible conflicts https://github.com/smarty-php/smarty/issues/231 - - 16.05.2016 - - optimization {foreach} compiler and processing - - broken PHP 5.3 and 5.4 compatibility - - 15.05.2016 - - optimization and cleanup of resource code - - 10.05.2016 - - optimization of inheritance processing - - 07.05.2016 - -bugfix Only variables should be assigned by reference https://github.com/smarty-php/smarty/issues/227 - - 02.05.2016 - - enhancement {block} tag names can now be variable https://github.com/smarty-php/smarty/issues/221 - - 01.05.2016 - - bugfix same relative filepath at {include} called from template in different folders could display wrong sub-template - - 29.04.2016 - - bugfix {strip} remove space on linebreak between html tags https://github.com/smarty-php/smarty/issues/213 - - 24.04.2016 - - bugfix nested {include} with relative file path could fail when called in {block} ... {/block} https://github.com/smarty-php/smarty/issues/218 - - 14.04.2016 - - bugfix special variable {$smarty.capture.name} was not case sensitive on name https://github.com/smarty-php/smarty/issues/210 - - bugfix the default template handler must calculate the source uid https://github.com/smarty-php/smarty/issues/205 - - 13.04.2016 - - bugfix template inheritance status must be saved when calling sub-templates https://github.com/smarty-php/smarty/issues/215 - - 27.03.2016 - - bugfix change of 11.03.2016 cause again {capture} data could not been seen in other templates with {$smarty.capture.name} https://github.com/smarty-php/smarty/issues/153 - - 11.03.2016 - - optimization of capture and security handling - - improvement $smarty->clearCompiledTemplate() should return on recompiled or uncompiled resources - - 10.03.2016 - - optimization of resource processing - - 09.03.2016 - - improvement rework of 'scope' attribute handling see see NEW_FEATURES.txt https://github.com/smarty-php/smarty/issues/194 - https://github.com/smarty-php/smarty/issues/186 https://github.com/smarty-php/smarty/issues/179 - - bugfix correct Autoloader update of 2.3.2014 https://github.com/smarty-php/smarty/issues/199 - - 04.03.2016 - - bugfix change from 01.03.2016 will cause $smarty->isCached(..) failure if called multiple time for same template - (forum topic 25935) - - 02.03.2016 - - revert autoloader optimizations because of unexplainable warning when using plugins https://github.com/smarty-php/smarty/issues/199 - - 01.03.2016 - - bugfix template objects must be cached on $smarty->fetch('foo.tpl) calls incase the template is fetched - multiple times (forum topic 25909) - - 25.02.2016 - - bugfix wrong _realpath with 4 or more parent-directories https://github.com/smarty-php/smarty/issues/190 - - optimization of _realpath - - bugfix instanceof expression in template code must be treated as value https://github.com/smarty-php/smarty/issues/191 - - 20.02.2016 - - bugfix {strip} must keep space between hmtl tags. Broken by changes of 10.2.2016 https://github.com/smarty-php/smarty/issues/184 - - new feature/bugfix {foreach}{section} add 'properties' attribute to force compilation of loop properties - see NEW_FEATURES.txt https://github.com/smarty-php/smarty/issues/189 - - 19.02.2016 - - revert output buffer flushing on display, echo content again because possible problems when PHP files had - characters (newline} after ?> at file end https://github.com/smarty-php/smarty/issues/187 - - 14.02.2016 - - new tag {make_nocache} read NEW_FEATURES.txt https://github.com/smarty-php/smarty/issues/110 - - optimization of sub-template processing - - bugfix using extendsall as default resource and {include} inside {block} tags could produce unexpected results https://github.com/smarty-php/smarty/issues/183 - - optimization of tag attribute compiling - - optimization make compiler tag object cache static for higher compilation speed - - 11.02.2016 - - improvement added KnockoutJS comments to trimwhitespace outputfilter https://github.com/smarty-php/smarty/issues/82 - https://github.com/smarty-php/smarty/pull/181 - - 10.02.2016 - - bugfix {strip} must keep space on output creating smarty tags within html tags https://github.com/smarty-php/smarty/issues/177 - - bugfix wrong precedence on special if conditions like '$foo is ... by $bar' could cause wrong code https://github.com/smarty-php/smarty/issues/178 - - improvement because of ambiguities the inline constant support has been removed from the $foo.bar syntax https://github.com/smarty-php/smarty/issues/149 - - bugfix other {strip} error with output tags between hmtl https://github.com/smarty-php/smarty/issues/180 - - 09.02.2016 - - move some code from parser into compiler - - reformat all code for unique style - - update/bugfix scope attribute handling reworked. Read the newfeatures.txt file - - 05.02.2016 - - improvement internal compiler changes - - 01.02.2016 - - bugfix {foreach} compilation failed when $smarty->merge_compiled_includes = true and pre-filters are used. - - 29.01.2016 - - bugfix implement replacement code for _tag_stack property https://github.com/smarty-php/smarty/issues/151 - - 28.01.2016 - - bugfix allow windows network filepath or wrapper (forum topic 25876) https://github.com/smarty-php/smarty/issues/170 - - bugfix if fetch('foo.tpl') is called on a template object the $parent parameter should default to the calling template object https://github.com/smarty-php/smarty/issues/152 - - 27.01.2016 - - revert bugfix compiling {section} did create warning - - bugfix {$smarty.section.customer.loop} did throw compiler error https://github.com/smarty-php/smarty/issues/161 - update of yesterdays fix - - bugfix string resource could inject code at {block} or inline subtemplates through PHP comments https://github.com/smarty-php/smarty/issues/157 - - bugfix output filters did not observe nocache code flhttps://github.com/smarty-php/smarty/issues/154g https://github.com/smarty-php/smarty/issues/160 - - bugfix {extends} with relative file path did not work https://github.com/smarty-php/smarty/issues/154 - https://github.com/smarty-php/smarty/issues/158 - - bugfix {capture} data could not been seen in other templates with {$smarty.capture.name} https://github.com/smarty-php/smarty/issues/153 - - 26.01.2016 - - improvement observe Smarty::$_CHARSET in debugging console https://github.com/smarty-php/smarty/issues/169 - - bugfix compiling {section} did create warning - - bugfix {$smarty.section.customer.loop} did throw compiler error https://github.com/smarty-php/smarty/issues/161 - - 02.01.2016 - - update scope handling - - optimize block plugin compiler - - improvement runtime checks if registered block plugins are callable - - 01.01.2016 - - remove Smarty::$resource_cache_mode property - - 31.12.2015 - - optimization of {assign}, {if} and {while} compiled code - - 30.12.2015 - - bugfix plugin names starting with "php" did not compile https://github.com/smarty-php/smarty/issues/147 - - 29.12.2015 - - bugfix Smarty::error_reporting was not observed when display() or fetch() was called on template objects https://github.com/smarty-php/smarty/issues/145 - - 28.12.2015 - - optimization of {foreach} code size and processing - - 27.12.2015 - - improve inheritance code - - update external methods - - code fixes - - PHPdoc updates - - 25.12.2015 - - compile {block} tag code and its processing into classes - - optimization replace hhvm extension by inline code - - new feature If ACP is enabled force an apc_compile_file() when compiled or cached template was updated - - 24.12.2015 - - new feature Compiler does now observe the template_dir setting and will create separate compiled files if required - - bugfix post filter did fail on template inheritance https://github.com/smarty-php/smarty/issues/144 - - 23.12.2015 - - optimization move internal method decodeProperties back into template object - - optimization move subtemplate processing back into template object - - new feature Caching does now observe the template_dir setting and will create separate cache files if required - - 22.12.2015 - - change $xxx_dir properties from private to protected in case Smarty class gets extended - - code optimizations - - 21.12.2015 - - bugfix a filepath starting with '/' or '\' on windows should normalize to the root dir - of current working drive https://github.com/smarty-php/smarty/issues/134 - - 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) - 21.12.2015 - - optimization improve speed of filetime checks on extends and extendsall resource - - 20.12.2015 - - bugfix failure when the default resource type was set to 'extendsall' https://github.com/smarty-php/smarty/issues/123 - - update compilation of Smarty special variables - - bugfix add addition check for OS type on normalization of file path https://github.com/smarty-php/smarty/issues/134 - - bugfix the source uid of the extendsall resource must contain $template_dir settings https://github.com/smarty-php/smarty/issues/123 - - 19.12.2015 - - bugfix using $smarty.capture.foo in expressions could fail https://github.com/smarty-php/smarty/pull/138 - - bugfix broken PHP 5.2 compatibility https://github.com/smarty-php/smarty/issues/139 - - remove no longer used code - - improvement make sure that compiled and cache templates never can contain a trailing '?>? - - 18.12.2015 - - bugfix regression when modifier parameter was followed by math https://github.com/smarty-php/smarty/issues/132 - - 17.12.2015 - - bugfix {$smarty.capture.nameFail} did lowercase capture name https://github.com/smarty-php/smarty/issues/135 - - bugfix using {block append/prepend} on same block in multiple levels of inheritance templates could fail (forum topic 25827) - - bugfix text content consisting of just a single '0' like in {if true}0{/if} was suppressed (forum topic 25834) - - 16.12.2015 - - bugfix {foreach} did fail if from atrribute is a Generator class https://github.com/smarty-php/smarty/issues/128 - - bugfix direct access $smarty->template_dir = 'foo'; should call Smarty::setTemplateDir() https://github.com/smarty-php/smarty/issues/121 - - 15.12.2015 - - bugfix {$smarty.cookies.foo} did return the $_COOKIE array not the 'foo' value https://github.com/smarty-php/smarty/issues/122 - - bugfix a call to clearAllCache() and other should clear all internal template object caches (forum topic 25828) - - 14.12.2015 - - 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) - 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) - - bugfix Debug Console could display incorrect data when using subtemplates - - 09.12.2015 - - bugfix Smarty did fail under PHP 7.0.0 with use_include_path = true; - - 09.12.2015 - - bugfix {strip} should exclude some html tags from stripping, related to fix for https://github.com/smarty-php/smarty/issues/111 - - 08.12.2015 - - bugfix internal template function data got stored in wrong compiled file https://github.com/smarty-php/smarty/issues/114 - - 05.12.2015 - -bugfix {strip} should insert a single space https://github.com/smarty-php/smarty/issues/111 - - 25.11.2015 - -bugfix a left delimter like '[%' did fail on [%$var_[%$variable%]%] (forum topic 25798) - - 02.11.2015 - - bugfix {include} with variable file name like {include file="foo_`$bar`.tpl"} did fail in 3.1.28-dev https://github.com/smarty-php/smarty/issues/102 - - 01.11.2015 - - update config file processing - - 31.10.2015 - - bugfix add missing $trusted_dir property to SmartyBC class (forum topic 25751) - - 29.10.2015 - - improve template scope handling - - 24.10.2015 - - more optimizations of template processing - - bugfix Error when using {include} within {capture} https://github.com/smarty-php/smarty/issues/100 - - 21.10.2015 - - move some code into runtime extensions - - 18.10.2015 - - optimize filepath normalization - - rework of template inheritance - - speed and size optimizations - - bugfix under HHVM temporary cache file must only be created when caches template was updated - - fix compiled code for new {block} assign attribute - - update code generated by template function call handler - - 18.09.2015 - - bugfix {if $foo instanceof $bar} failed to compile if 2nd value is a variable https://github.com/smarty-php/smarty/issues/92 - - 17.09.2015 - - bugfix {foreach} first attribute was not correctly reset since commit 05a8fa2 of 02.08.2015 https://github.com/smarty-php/smarty/issues/90 - - 16.09.2015 - - update compiler by moving no longer needed properties, code optimizations and other - - 14.09.2015 - - optimize autoloader - - optimize subtemplate handling - - update template inheritance processing - - move code of {call} processing back into Smarty_Internal_Template class - - improvement invalidate OPCACHE for cleared compiled and cached template files (forum topic 25557) - - bugfix unintended multiple debug windows (forum topic 25699) - - 30.08.2015 - - size optimization move some runtime functions into extension - - optimize inline template processing - - optimization merge inheritance child and parent templates into one compiled template file - - 29.08.2015 - - improvement convert template inheritance into runtime processing - - bugfix {$smarty.block.parent} did always reference the root parent block https://github.com/smarty-php/smarty/issues/68 - - 23.08.2015 - - introduce Smarty::$resource_cache_mode and cache template object of {include} inside loop - - load seldom used Smarty API methods dynamically to reduce memory footprint - - cache template object of {include} if same template is included several times - - convert debug console processing to object - - use output buffers for better performance and less memory usage - - optimize nocache hash processing - - remove not really needed properties - - optimize rendering - - move caching to Smarty::_cache - - remove properties with redundant content - - optimize Smarty::templateExists() - - optimize use_include_path processing - - relocate properties for size optimization - - remove redundant code - - bugfix compiling super globals like {$smarty.get.foo} did fail in the master branch https://github.com/smarty-php/smarty/issues/77 - - 06.08.2015 - - avoid possible circular object references caused by parser/lexer objects - - rewrite compileAll... utility methods - - commit several internal improvements - - bugfix Smarty failed when compile_id did contain "|" - - 03.08.2015 - - rework clear cache methods - - bugfix compileAllConfig() was broken since 3.1.22 because of the changes in config file processing - - improve getIncludePath() to return directory if no file was given - - 02.08.2015 - - optimization and code cleanup of {foreach} and {section} compiler - - rework {capture} compiler - - 01.08.2015 - - update DateTime object can be instance of DateTimeImmutable since PHP5.5 https://github.com/smarty-php/smarty/pull/75 - - improvement show resource type and start of template source instead of uid on eval: and string: resource (forum topic 25630) - - 31.07.2015 - - optimize {foreach} and {section} compiler - - 29.07.2015 - - optimize {section} compiler for speed and size of compiled code - - 28.07.2015 - - update for PHP 7 compatibility - - 26.07.2015 - - improvement impement workaround for HHVM PHP incompatibillity https://github.com/facebook/hhvm/issues/4797 - - 25.07.2015 - - bugfix parser did hang on text starting fetch('foo.tpl') https://github.com/smarty-php/smarty/issues/70 - - improvement Added $limit parameter to regex_replace modifier #71 - - new feature multiple indices on file: resource - - 06.07.2015 - - optimize {block} compilation - - optimization get rid of __get and __set in source object - - 01.07.2015 - - optimize compile check handling - - update {foreach} compiler - - bugfix debugging console did not display string values containing \n, \r or \t correctly https://github.com/smarty-php/smarty/issues/66 - - optimize source resources - - 28.06.2015 - - move $smarty->enableSecurity() into Smarty_Security class - - optimize security isTrustedResourceDir() - - move auto load filter methods into extension - - move $smarty->getTemplateVars() into extension - - move getStreamVariable() into extension - - move $smarty->append() and $smarty->appendByRef() into extension - - optimize autoloader - - optimize file path normalization - - bugfix PATH_SEPARATOR was replaced by mistake in autoloader - - remove redundant code - - 27.06.2015 - - bugfix resolve naming conflict between custom Smarty delimiter '<%' and PHP ASP tags https://github.com/smarty-php/smarty/issues/64 - - update $smarty->_realpath for relative path not starting with './' - - update Smarty security with new realpath handling - - update {include_php} with new realpath handling - - move $smarty->loadPlugin() into extension - - minor compiler optimizations - - bugfix allow function plugins with name ending with 'close' https://github.com/smarty-php/smarty/issues/52 - - rework of $smarty->clearCompiledTemplate() and move it to its own extension - - 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) - 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) - 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) - 15.06.2015 - - optimization of smarty_cachereource_keyvaluestore.php code - - 14.06.2015 - - bugfix a relative sub template path could fail if template_dir path did contain /../ https://github.com/smarty-php/smarty/issues/50 - - optimization rework of path normalization - - bugfix an output tag with variable, modifier followed by an operator like {$foo|modifier+1} did fail https://github.com/smarty-php/smarty/issues/53 - - 13.06.2015 - - bugfix a custom cache resource using smarty_cachereource_keyvaluestore.php did fail if php.ini mbstring.func_overload = 2 (forum topic 25568) - - 11.06.2015 - - bugfix the lexer could hang on very large quoted strings (forum topic 25570) - - 08.06.2015 - - bugfix using {$foo} as array index like $bar.{$foo} or in double quoted string like "some {$foo} thing" failed https://github.com/smarty-php/smarty/issues/49 - - 04.06.2015 - - bugfix possible error message on unset() while compiling {block} tags https://github.com/smarty-php/smarty/issues/46 - - 01.06.2015 - - bugfix including template variables broken since 3.1.22 https://github.com/smarty-php/smarty/issues/47 - - 27.05.2015 - - bugfix {include} with variable file name must not create by default individual cache file (since 3.1.22) https://github.com/smarty-php/smarty/issues/43 - - 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) - 23.05.2015 - - improvement on php_handling to allow very large PHP sections, better error handling - - improvement allow extreme large comment sections (forum 25538) - - 21.05.2015 - - bugfix broken PHP 5.2 compatibility when compiling 1 did compile into wrong code https://github.com/smarty-php/smarty/issues/41 - - 19.05.2015 - - bugfix compiler did overwrite existing variable value when setting the nocache attribute https://github.com/smarty-php/smarty/issues/39 - - bugfix output filter trimwhitespace could run into the pcre.backtrack_limit on large output (code.google issue 220) - - bugfix compiler could run into the pcre.backtrack_limit on larger comment or {php} tag sections (forum 25538) - - 18.05.2015 - - improvement introduce shortcuts in lexer/parser rules for most frequent terms for higher - compilation speed - - 16.05.2015 - - bugfix {php}{/php} did work just for single lines https://github.com/smarty-php/smarty/issues/33 - - improvement remove not needed ?> handling from parser to new compiler module - - 05.05.2015 - - bugfix code could be messed up when {tags} are used in multiple attributes https://github.com/smarty-php/smarty/issues/23 - - 04.05.2015 - - bugfix Smarty_Resource::parseResourceName incompatible with Google AppEngine (https://github.com/smarty-php/smarty/issues/22) - - improvement use is_file() checks to avoid errors suppressed by @ which could still cause problems (https://github.com/smarty-php/smarty/issues/24) - - 28.04.2015 - - bugfix plugins of merged subtemplates not loaded in 3.1.22-dev (forum topic 25508) 2nd fix - - 28.04.2015 - - bugfix plugins of merged subtemplates not loaded in 3.1.22-dev (forum topic 25508) - - 23.04.2015 - - bugfix a nocache template variable used as parameter at {insert} was by mistake cached - - 20.04.2015 - - bugfix at a template function containing nocache code a parmeter could overwrite a template variable of same name - - 27.03.2015 - - bugfix Smarty_Security->allow_constants=false; did also disable true, false and null (change of 16.03.2015) - - improvement added a whitelist for trusted constants to security Smarty_Security::$trusted_constants (forum topic 25471) - - 20.03.2015 - - bugfix make sure that function properties get saved only in compiled files containing the fuction definition {forum topic 25452} - - bugfix correct update of global variable values on exit of template functions. (reported under Smarty Developers) - - 16.03.2015 - - bugfix problems with {function}{/function} and {call} tags in different subtemplate cache files {forum topic 25452} - - bugfix Smarty_Security->allow_constants=false; did not disallow direct usage of defined constants like {SMARTY_DIR} {forum topic 25457} - - bugfix {block}{/block} tags did not work inside double quoted strings https://github.com/smarty-php/smarty/issues/18 - - - 15.03.2015 - - bugfix $smarty->compile_check must be restored before rendering of a just updated cache file {forum 25452} - - 14.03.2015 - - bugfix {nocache} {/nocache} tags corrupted code when used within a nocache section caused by a nocache template variable. - - - bugfix template functions defined with {function} in an included subtemplate could not be called in nocache - mode with {call... nocache} if the subtemplate had it's own cache file {forum 25452} - - 10.03.2015 - - bugfix {include ... nocache} whith variable file or compile_id attribute was not executed in nocache mode. - - 12.02.2015 - - bugfix multiple Smarty::fetch() of same template when $smarty->merge_compiled_includes = true; could cause function already defined error - - 11.02.2015 - - bugfix recursive {includes} did create E_NOTICE message when $smarty->merge_compiled_includes = true; (github issue #16) - - 22.01.2015 - - new feature security can now control access to static methods and properties - see also NEW_FEATURES.txt - - 21.01.2015 - - bugfix clearCompiledTemplates(), clearAll() and clear() could try to delete whole drive at wrong path permissions because realpath() fail (forum 25397) - - bugfix 'self::' and 'parent::' was interpreted in template syntax as static class - - 04.01.2015 - - push last weeks changes to github - - - different optimizations - - improvement automatically create different versions of compiled templates and config files depending - on property settings. - - optimization restructure template processing by moving code into classes it better belongs to - - optimization restructure config file processing - - 31.12.2014 - - bugfix use function_exists('mb_get_info') for setting Smarty::$_MBSTRING. - Function mb_split could be overloaded depending on php.ini mbstring.func_overload - - - 29.12.2014 - - new feature security can now limit the template nesting level by property $max_template_nesting - see also NEW_FEATURES.txt (forum 25370) - - 29.12.2014 - - new feature security can now disable special $smarty variables listed in property $disabled_special_smarty_vars - see also NEW_FEATURES.txt (forum 25370) - - 27.12.2014 - - bugfix clear internal _is_file_cache when plugins_dir was modified - - 13.12.2014 - - improvement optimization of lexer and parser resulting in a up to 30% higher compiling speed - - 11.12.2014 - - bugfix resolve parser ambiguity between constant print tag {CONST} and other smarty tags after change of 09.12.2014 - - 09.12.2014 - - bugfix variables $null, $true and $false did not work after the change of 12.11.2014 (forum 25342) - - bugfix call of template function by a variable name did not work after latest changes (forum 25342) - - 23.11.2014 - - bugfix a plugin with attached modifier could fail if the tag was immediately followed by another Smarty tag (since 3.1.21) (forum 25326) - - 13.11.2014 - - improvement move autoload code into Autoloader.php. Use Composer autoloader when possible - - 12.11.2014 - - new feature added support of namespaces to template code - - 08.11.2014 - 10.11.2014 - - bugfix subtemplate called in nocache mode could be called with wrong compile_id when it did change on one of the calling templates - - improvement add code of template functions called in nocache mode dynamically to cache file (related to bugfix of 01.11.2014) - - bugfix Debug Console did not include all data from merged compiled subtemplates - - 04.11.2014 - - new feature $smarty->debugging = true; => overwrite existing Debug Console window (old behaviour) - $smarty->debugging = 2; => individual Debug Console window by template name - - 03.11.2014 - - bugfix Debug Console did not show included subtemplates since 3.1.17 (forum 25301) - - bugfix Modifier debug_print_var did not limit recursion or prevent recursive object display at Debug Console - (ATTENTION: parameter order has changed to be able to specify maximum recursion) - - bugfix Debug consol did not include subtemplate information with $smarty->merge_compiled_includes = true - - improvement The template variables are no longer displayed as objects on the Debug Console - - improvement $smarty->createData($parent = null, $name = null) new optional name parameter for display at Debug Console - - addition of some hooks for future extension of Debug Console - - 01.11.2014 - - bugfix and enhancement on subtemplate {include} and template {function} tags. - * Calling a template which has a nocache section could fail if it was called from a cached and a not cached subtemplate. - * Calling the same subtemplate cached and not cached with the $smarty->merge_compiled_includes enabled could cause problems - * Many smaller related changes - - 30.10.2014 - - bugfix access to class constant by object like {$object::CONST} or variable class name {$class::CONST} did not work (forum 25301) - - 26.10.2014 - - 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) - 18.10.2014 - - composer moved to github - - 17.10.2014 - - bugfix on $php_handling security and optimization of smarty_internal_parsetree (Thue Kristensen) - - 16.10.2014 - - bugfix composer.json update - - 15.10.2014 - - bugfix calling a new created cache file with fetch() and Smarty::CACHING_LIFETIME_SAVED multiple times did fail (forum 22350) - - 14.10.2014 - - bugfix any tag placed within " diff --git a/tools/smarty/functions.php b/tools/smarty/functions.php new file mode 100644 index 000000000..bac00e521 --- /dev/null +++ b/tools/smarty/functions.php @@ -0,0 +1,51 @@ + -* @copyright 2010-2020 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../'); -exit; diff --git a/tools/smarty/plugins/block.textformat.php b/tools/smarty/plugins/block.textformat.php index 5e494637e..fed090e4d 100644 --- a/tools/smarty/plugins/block.textformat.php +++ b/tools/smarty/plugins/block.textformat.php @@ -20,7 +20,7 @@ * - indent_char - string (" ") * - wrap_boundary - boolean (true) * - * @link http://www.smarty.net/manual/en/language.function.textformat.php {textformat} + * @link https://www.smarty.net/manual/en/language.function.textformat.php {textformat} * (Smarty online manual) * * @param array $params parameters diff --git a/tools/smarty/plugins/function.counter.php b/tools/smarty/plugins/function.counter.php index a4129e77c..54795459c 100644 --- a/tools/smarty/plugins/function.counter.php +++ b/tools/smarty/plugins/function.counter.php @@ -12,7 +12,7 @@ * Purpose: print out a counter value * * @author Monte Ohrt - * @link http://www.smarty.net/manual/en/language.function.counter.php {counter} + * @link https://www.smarty.net/manual/en/language.function.counter.php {counter} * (Smarty online manual) * * @param array $params parameters diff --git a/tools/smarty/plugins/function.cycle.php b/tools/smarty/plugins/function.cycle.php index 07ffcc5e2..793569991 100644 --- a/tools/smarty/plugins/function.cycle.php +++ b/tools/smarty/plugins/function.cycle.php @@ -28,7 +28,7 @@ * {cycle name=row values="one,two,three" reset=true} * {cycle name=row} * - * @link http://www.smarty.net/manual/en/language.function.cycle.php {cycle} + * @link https://www.smarty.net/manual/en/language.function.cycle.php {cycle} * (Smarty online manual) * @author Monte Ohrt * @author credit to Mark Priatel diff --git a/tools/smarty/plugins/function.fetch.php b/tools/smarty/plugins/function.fetch.php index 768761b23..4a3e88196 100644 --- a/tools/smarty/plugins/function.fetch.php +++ b/tools/smarty/plugins/function.fetch.php @@ -11,7 +11,7 @@ * Name: fetch * Purpose: fetch file, web or ftp data and display results * - * @link http://www.smarty.net/manual/en/language.function.fetch.php {fetch} + * @link https://www.smarty.net/manual/en/language.function.fetch.php {fetch} * (Smarty online manual) * @author Monte Ohrt * diff --git a/tools/smarty/plugins/function.html_checkboxes.php b/tools/smarty/plugins/function.html_checkboxes.php index 302358edd..a8e7a07d8 100644 --- a/tools/smarty/plugins/function.html_checkboxes.php +++ b/tools/smarty/plugins/function.html_checkboxes.php @@ -29,7 +29,7 @@ * - assign (optional) - assign the output as an array to this variable * - escape (optional) - escape the content (not value), defaults to true * - * @link http://www.smarty.net/manual/en/language.function.html.checkboxes.php {html_checkboxes} + * @link https://www.smarty.net/manual/en/language.function.html.checkboxes.php {html_checkboxes} * (Smarty online manual) * @author Christopher Kvarme * @author credits to Monte Ohrt diff --git a/tools/smarty/plugins/function.html_image.php b/tools/smarty/plugins/function.html_image.php index ad468e4f1..71bc63864 100644 --- a/tools/smarty/plugins/function.html_image.php +++ b/tools/smarty/plugins/function.html_image.php @@ -21,7 +21,7 @@ * - basedir - (optional) - base directory for absolute paths, default is environment variable DOCUMENT_ROOT * - path_prefix - prefix for path output (optional, default empty) * - * @link http://www.smarty.net/manual/en/language.function.html.image.php {html_image} + * @link https://www.smarty.net/manual/en/language.function.html.image.php {html_image} * (Smarty online manual) * @author Monte Ohrt * @author credits to Duda diff --git a/tools/smarty/plugins/function.html_options.php b/tools/smarty/plugins/function.html_options.php index 6907e8ee1..3e4335340 100644 --- a/tools/smarty/plugins/function.html_options.php +++ b/tools/smarty/plugins/function.html_options.php @@ -21,7 +21,7 @@ * - id (optional) - string default not set * - class (optional) - string default not set * - * @link http://www.smarty.net/manual/en/language.function.html.options.php {html_image} + * @link https://www.smarty.net/manual/en/language.function.html.options.php {html_image} * (Smarty online manual) * @author Monte Ohrt * @author Ralf Strehle (minor optimization) diff --git a/tools/smarty/plugins/function.html_radios.php b/tools/smarty/plugins/function.html_radios.php index 5e834587c..2223ff7ee 100644 --- a/tools/smarty/plugins/function.html_radios.php +++ b/tools/smarty/plugins/function.html_radios.php @@ -29,7 +29,7 @@ * {html_radios values=$ids name='box' separator='
' output=$names} * {html_radios values=$ids checked=$checked separator='
' output=$names} * - * @link http://smarty.php.net/manual/en/language.function.html.radios.php {html_radios} + * @link https://www.smarty.net/manual/en/language.function.html.radios.php {html_radios} * (Smarty online manual) * @author Christopher Kvarme * @author credits to Monte Ohrt diff --git a/tools/smarty/plugins/function.html_select_date.php b/tools/smarty/plugins/function.html_select_date.php index 86403e3dc..d9c571976 100644 --- a/tools/smarty/plugins/function.html_select_date.php +++ b/tools/smarty/plugins/function.html_select_date.php @@ -28,7 +28,7 @@ * - 2.0 complete rewrite for performance, * added attributes month_names, *_id * - * @link http://www.smarty.net/manual/en/language.function.html.select.date.php {html_select_date} + * @link https://www.smarty.net/manual/en/language.function.html.select.date.php {html_select_date} * (Smarty online manual) * @version 2.0 * @author Andrei Zmievski @@ -101,6 +101,7 @@ function smarty_function_html_select_date($params, Smarty_Internal_Template $tem $field_separator = "\n"; $option_separator = "\n"; $time = null; + // $all_empty = null; // $day_empty = null; // $month_empty = null; @@ -113,17 +114,7 @@ function smarty_function_html_select_date($params, Smarty_Internal_Template $tem foreach ($params as $_key => $_value) { switch ($_key) { case 'time': - if (!is_array($_value) && $_value !== null) { - $template->_checkPlugins( - array( - array( - 'function' => 'smarty_make_timestamp', - 'file' => SMARTY_PLUGINS_DIR . 'shared.make_timestamp.php' - ) - ) - ); - $time = smarty_make_timestamp($_value); - } + $$_key = $_value; // we'll handle conversion below break; case 'month_names': if (is_array($_value) && count($_value) === 12) { @@ -178,43 +169,59 @@ function smarty_function_html_select_date($params, Smarty_Internal_Template $tem } // Note: date() is faster than strftime() // Note: explode(date()) is faster than date() date() date() - if (isset($params[ 'time' ]) && is_array($params[ 'time' ])) { - if (isset($params[ 'time' ][ $prefix . 'Year' ])) { + + if (isset($time) && is_array($time)) { + if (isset($time[$prefix . 'Year'])) { // $_REQUEST[$field_array] given - foreach (array( - 'Y' => 'Year', - 'm' => 'Month', - 'd' => 'Day' - ) as $_elementKey => $_elementName) { + foreach ([ + 'Y' => 'Year', + 'm' => 'Month', + 'd' => 'Day' + ] as $_elementKey => $_elementName) { $_variableName = '_' . strtolower($_elementName); $$_variableName = - isset($params[ 'time' ][ $prefix . $_elementName ]) ? $params[ 'time' ][ $prefix . $_elementName ] : + isset($time[$prefix . $_elementName]) ? $time[$prefix . $_elementName] : date($_elementKey); } - } elseif (isset($params[ 'time' ][ $field_array ][ $prefix . 'Year' ])) { + } elseif (isset($time[$field_array][$prefix . 'Year'])) { // $_REQUEST given - foreach (array( - 'Y' => 'Year', - 'm' => 'Month', - 'd' => 'Day' - ) as $_elementKey => $_elementName) { + foreach ([ + 'Y' => 'Year', + 'm' => 'Month', + 'd' => 'Day' + ] as $_elementKey => $_elementName) { $_variableName = '_' . strtolower($_elementName); - $$_variableName = isset($params[ 'time' ][ $field_array ][ $prefix . $_elementName ]) ? - $params[ 'time' ][ $field_array ][ $prefix . $_elementName ] : date($_elementKey); + $$_variableName = isset($time[$field_array][$prefix . $_elementName]) ? + $time[$field_array][$prefix . $_elementName] : date($_elementKey); } } else { // no date found, use NOW - list($_year, $_month, $_day) = $time = explode('-', date('Y-m-d')); + [$_year, $_month, $_day] = explode('-', date('Y-m-d')); } + } elseif (isset($time) && preg_match("/(\d*)-(\d*)-(\d*)/", $time, $matches)) { + $_year = $_month = $_day = null; + if ($matches[1] > '') $_year = (int) $matches[1]; + if ($matches[2] > '') $_month = (int) $matches[2]; + if ($matches[3] > '') $_day = (int) $matches[3]; } elseif ($time === null) { if (array_key_exists('time', $params)) { - $_year = $_month = $_day = $time = null; + $_year = $_month = $_day = null; } else { - list($_year, $_month, $_day) = $time = explode('-', date('Y-m-d')); + [$_year, $_month, $_day] = explode('-', date('Y-m-d')); } } else { - list($_year, $_month, $_day) = $time = explode('-', date('Y-m-d', $time)); + $template->_checkPlugins( + array( + array( + 'function' => 'smarty_make_timestamp', + 'file' => SMARTY_PLUGINS_DIR . 'shared.make_timestamp.php' + ) + ) + ); + $time = smarty_make_timestamp($time); + [$_year, $_month, $_day] = explode('-', date('Y-m-d', $time)); } + // make syntax "+N" or "-N" work with $start_year and $end_year // Note preg_match('!^(\+|\-)\s*(\d+)$!', $end_year, $match) is slower than trim+substr foreach (array( @@ -309,8 +316,8 @@ function smarty_function_html_select_date($params, Smarty_Internal_Template $tem for ($i = 1; $i <= 12; $i++) { $_val = sprintf('%02d', $i); $_text = isset($month_names) ? smarty_function_escape_special_chars($month_names[ $i ]) : - ($month_format === '%m' ? $_val : strftime($month_format, $_month_timestamps[ $i ])); - $_value = $month_value_format === '%m' ? $_val : strftime($month_value_format, $_month_timestamps[ $i ]); + ($month_format === '%m' ? $_val : @strftime($month_format, $_month_timestamps[ $i ])); + $_value = $month_value_format === '%m' ? $_val : @strftime($month_value_format, $_month_timestamps[ $i ]); $_html_months .= '' . $option_separator; } diff --git a/tools/smarty/plugins/function.html_select_time.php b/tools/smarty/plugins/function.html_select_time.php index cb047bc0a..256b56b1c 100644 --- a/tools/smarty/plugins/function.html_select_time.php +++ b/tools/smarty/plugins/function.html_select_time.php @@ -11,7 +11,7 @@ * Name: html_select_time * Purpose: Prints the dropdowns for time selection * - * @link http://www.smarty.net/manual/en/language.function.html.select.time.php {html_select_time} + * @link https://www.smarty.net/manual/en/language.function.html.select.time.php {html_select_time} * (Smarty online manual) * @author Roberto Berto * @author Monte Ohrt diff --git a/tools/smarty/plugins/function.html_table.php b/tools/smarty/plugins/function.html_table.php index ae61e83dc..17b0586e2 100644 --- a/tools/smarty/plugins/function.html_table.php +++ b/tools/smarty/plugins/function.html_table.php @@ -38,7 +38,7 @@ * @author credit to Messju Mohr * @author credit to boots * @version 1.1 - * @link http://www.smarty.net/manual/en/language.function.html.table.php {html_table} + * @link https://www.smarty.net/manual/en/language.function.html.table.php {html_table} * (Smarty online manual) * * @param array $params parameters diff --git a/tools/smarty/plugins/function.mailto.php b/tools/smarty/plugins/function.mailto.php index 27351df82..671ac0694 100644 --- a/tools/smarty/plugins/function.mailto.php +++ b/tools/smarty/plugins/function.mailto.php @@ -36,7 +36,7 @@ * {mailto address="me@domain.com" cc="you@domain.com,they@domain.com"} * {mailto address="me@domain.com" extra='class="mailto"'} * - * @link http://www.smarty.net/manual/en/language.function.mailto.php {mailto} + * @link https://www.smarty.net/manual/en/language.function.mailto.php {mailto} * (Smarty online manual) * @version 1.2 * @author Monte Ohrt @@ -48,8 +48,13 @@ */ function smarty_function_mailto($params) { - static $_allowed_encoding = - array('javascript' => true, 'javascript_charcode' => true, 'hex' => true, 'none' => true); + static $_allowed_encoding = [ + 'javascript' => true, + 'javascript_charcode' => true, + 'hex' => true, + 'none' => true + ]; + $extra = ''; if (empty($params[ 'address' ])) { trigger_error("mailto: missing 'address' parameter", E_USER_WARNING); @@ -57,19 +62,19 @@ function smarty_function_mailto($params) } else { $address = $params[ 'address' ]; } + $text = $address; + // netscape and mozilla do not decode %40 (@) in BCC field (bug?) // so, don't encode it. - $search = array('%40', '%2C'); - $replace = array('@', ','); - $mail_parms = array(); + $mail_parms = []; foreach ($params as $var => $value) { switch ($var) { case 'cc': case 'bcc': case 'followupto': if (!empty($value)) { - $mail_parms[] = $var . '=' . str_replace($search, $replace, rawurlencode($value)); + $mail_parms[] = $var . '=' . str_replace(['%40', '%2C'], ['@', ','], rawurlencode($value)); } break; case 'subject': @@ -83,6 +88,7 @@ function smarty_function_mailto($params) default: } } + if ($mail_parms) { $address .= '?' . join('&', $mail_parms); } @@ -94,22 +100,21 @@ function smarty_function_mailto($params) ); return; } - // FIXME: (rodneyrehm) document.write() excues me what? 1998 has passed! + + $string = '' . htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, Smarty::$_CHARSET) . ''; + if ($encode === 'javascript') { - $string = 'document.write(\'' . $text . '\');'; $js_encode = ''; for ($x = 0, $_length = strlen($string); $x < $_length; $x++) { $js_encode .= '%' . bin2hex($string[ $x ]); } - return ''; + 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 ])) { @@ -132,6 +137,6 @@ function smarty_function_mailto($params) return '' . $text_encode . ''; } else { // no encoding - return '' . $text . ''; + return $string; } } diff --git a/tools/smarty/plugins/function.math.php b/tools/smarty/plugins/function.math.php index 7348d9649..34912d239 100644 --- a/tools/smarty/plugins/function.math.php +++ b/tools/smarty/plugins/function.math.php @@ -12,7 +12,7 @@ * Name: math * Purpose: handle math computations in template * - * @link http://www.smarty.net/manual/en/language.function.math.php {math} + * @link https://www.smarty.net/manual/en/language.function.math.php {math} * (Smarty online manual) * @author Monte Ohrt * @@ -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/tools/smarty/plugins/index.php b/tools/smarty/plugins/index.php deleted file mode 100644 index b1297ac0b..000000000 --- a/tools/smarty/plugins/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2020 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/smarty/plugins/modifier.capitalize.php b/tools/smarty/plugins/modifier.capitalize.php index c5fc400a6..2903d61d7 100644 --- a/tools/smarty/plugins/modifier.capitalize.php +++ b/tools/smarty/plugins/modifier.capitalize.php @@ -22,6 +22,8 @@ */ function smarty_modifier_capitalize($string, $uc_digits = false, $lc_rest = false) { + $string = (string) $string; + if (Smarty::$_MBSTRING) { if ($lc_rest) { // uppercase (including hyphenated words) diff --git a/tools/smarty/plugins/modifier.count.php b/tools/smarty/plugins/modifier.count.php new file mode 100644 index 000000000..ca35fc115 --- /dev/null +++ b/tools/smarty/plugins/modifier.count.php @@ -0,0 +1,36 @@ + Prior to PHP 8.0.0, if the parameter was neither an array nor an object that implements the Countable interface, + * > 1 would be returned, unless value was null, in which case 0 would be returned. + */ + + if ($arrayOrObject instanceof Countable || is_array($arrayOrObject)) { + return count($arrayOrObject, (int) $mode); + } elseif ($arrayOrObject === null) { + return 0; + } + return 1; +} diff --git a/tools/smarty/plugins/modifier.date_format.php b/tools/smarty/plugins/modifier.date_format.php index c8e88c5c9..e3589fd07 100644 --- a/tools/smarty/plugins/modifier.date_format.php +++ b/tools/smarty/plugins/modifier.date_format.php @@ -15,7 +15,7 @@ * - format: strftime format for output * - default_date: default date if $string is empty * - * @link http://www.smarty.net/manual/en/language.modifier.date.format.php date_format (Smarty online manual) + * @link https://www.smarty.net/manual/en/language.modifier.date.format.php date_format (Smarty online manual) * @author Monte Ohrt * * @param string $string input date string @@ -78,7 +78,8 @@ function smarty_modifier_date_format($string, $format = null, $default_date = '' } $format = str_replace($_win_from, $_win_to, $format); } - return strftime($format, $timestamp); + // @ to suppress deprecation errors when running in PHP8.1 or higher. + return @strftime($format, $timestamp); } else { return date($format, $timestamp); } diff --git a/tools/smarty/plugins/modifier.escape.php b/tools/smarty/plugins/modifier.escape.php index 150901c7c..e168679c3 100644 --- a/tools/smarty/plugins/modifier.escape.php +++ b/tools/smarty/plugins/modifier.escape.php @@ -11,7 +11,7 @@ * Name: escape * Purpose: escape string for output * - * @link http://www.smarty.net/docs/en/language.modifier.escape + * @link https://www.smarty.net/docs/en/language.modifier.escape * @author Monte Ohrt * * @param string $string input string @@ -23,98 +23,25 @@ */ function smarty_modifier_escape($string, $esc_type = 'html', $char_set = null, $double_encode = true) { - static $_double_encode = null; static $is_loaded_1 = false; static $is_loaded_2 = false; - if ($_double_encode === null) { - $_double_encode = version_compare(PHP_VERSION, '5.2.3', '>='); - } if (!$char_set) { $char_set = Smarty::$_CHARSET; } + + $string = (string)$string; + switch ($esc_type) { case 'html': - if ($_double_encode) { - // php >=5.3.2 - go native - return htmlspecialchars($string, ENT_QUOTES, $char_set, $double_encode); - } else { - if ($double_encode) { - // php <5.2.3 - only handle double encoding - return htmlspecialchars($string, ENT_QUOTES, $char_set); - } else { - // php <5.2.3 - prevent double encoding - $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string); - $string = htmlspecialchars($string, ENT_QUOTES, $char_set); - $string = str_replace( - array( - '%%%SMARTY_START%%%', - '%%%SMARTY_END%%%' - ), - array( - '&', - ';' - ), - $string - ); - return $string; - } - } + return htmlspecialchars($string, ENT_QUOTES, $char_set, $double_encode); // no break case 'htmlall': if (Smarty::$_MBSTRING) { - // mb_convert_encoding ignores htmlspecialchars() - if ($_double_encode) { - // php >=5.3.2 - go native - $string = htmlspecialchars($string, ENT_QUOTES, $char_set, $double_encode); - } else { - if ($double_encode) { - // php <5.2.3 - only handle double encoding - $string = htmlspecialchars($string, ENT_QUOTES, $char_set); - } else { - // php <5.2.3 - prevent double encoding - $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string); - $string = htmlspecialchars($string, ENT_QUOTES, $char_set); - $string = - str_replace( - array( - '%%%SMARTY_START%%%', - '%%%SMARTY_END%%%' - ), - array( - '&', - ';' - ), - $string - ); - return $string; - } - } - // htmlentities() won't convert everything, so use mb_convert_encoding - return mb_convert_encoding($string, 'HTML-ENTITIES', $char_set); + $string = mb_convert_encoding($string, 'UTF-8', $char_set); + return htmlentities($string, ENT_QUOTES, 'UTF-8', $double_encode); } // no MBString fallback - if ($_double_encode) { - return htmlentities($string, ENT_QUOTES, $char_set, $double_encode); - } else { - if ($double_encode) { - return htmlentities($string, ENT_QUOTES, $char_set); - } else { - $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string); - $string = htmlentities($string, ENT_QUOTES, $char_set); - $string = str_replace( - array( - '%%%SMARTY_START%%%', - '%%%SMARTY_END%%%' - ), - array( - '&', - ';' - ), - $string - ); - return $string; - } - } + return htmlentities($string, ENT_QUOTES, $char_set, $double_encode); // no break case 'url': return rawurlencode($string); @@ -184,7 +111,13 @@ 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 + '#ms', '', $source); // capture html elements not to be messed with $_offset = 0; @@ -62,7 +62,7 @@ function smarty_outputfilter_trimwhitespace($source) } } $expressions = array(// replace multiple spaces between tags by a single space - // can't remove them entirely, becaue that might break poorly implemented CSS display:inline-block elements + // can't remove them entirely, because that might break poorly implemented CSS display:inline-block elements '#(:SMARTY@!@|>)\s+(?=@!@SMARTY:|<)#s' => '\1 \2', // remove spaces between attributes (but not in attribute values!) '#(([a-z0-9]\s*=\s*("[^"]*?")|(\'[^\']*?\'))|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \5', diff --git a/tools/smarty/plugins/shared.escape_special_chars.php b/tools/smarty/plugins/shared.escape_special_chars.php index 6b18d3eec..355b02b57 100644 --- a/tools/smarty/plugins/shared.escape_special_chars.php +++ b/tools/smarty/plugins/shared.escape_special_chars.php @@ -20,13 +20,7 @@ function smarty_function_escape_special_chars($string) { if (!is_array($string)) { - if (version_compare(PHP_VERSION, '5.2.3', '>=')) { - $string = htmlspecialchars($string, ENT_COMPAT, Smarty::$_CHARSET, false); - } else { - $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string); - $string = htmlspecialchars($string); - $string = str_replace(array('%%%SMARTY_START%%%', '%%%SMARTY_END%%%'), array('&', ';'), $string); - } + $string = htmlspecialchars((string) $string, ENT_COMPAT, Smarty::$_CHARSET, false); } return $string; } diff --git a/tools/smarty/plugins/shared.mb_str_replace.php b/tools/smarty/plugins/shared.mb_str_replace.php index 206cf9ea6..7e85f7aae 100644 --- a/tools/smarty/plugins/shared.mb_str_replace.php +++ b/tools/smarty/plugins/shared.mb_str_replace.php @@ -44,9 +44,43 @@ if (!function_exists('smarty_mb_str_replace')) { } } } else { - $parts = mb_split(preg_quote($search), $subject); + $mb_reg_charset = mb_regex_encoding(); + // Check if mbstring regex is using UTF-8 + $reg_is_unicode = !strcasecmp($mb_reg_charset, "UTF-8"); + if(!$reg_is_unicode) { + // ...and set to UTF-8 if not + mb_regex_encoding("UTF-8"); + } + + // See if charset used by Smarty is matching one used by regex... + $current_charset = mb_regex_encoding(); + $convert_result = (bool)strcasecmp(Smarty::$_CHARSET, $current_charset); + if($convert_result) { + // ...convert to it if not. + $subject = mb_convert_encoding($subject, $current_charset, Smarty::$_CHARSET); + $search = mb_convert_encoding($search, $current_charset, Smarty::$_CHARSET); + $replace = mb_convert_encoding($replace, $current_charset, Smarty::$_CHARSET); + } + + $parts = mb_split(preg_quote($search), $subject ?? "") ?: array(); + // If original regex encoding was not unicode... + if(!$reg_is_unicode) { + // ...restore original regex encoding to avoid breaking the system. + mb_regex_encoding($mb_reg_charset); + } + if($parts === false) { + // This exception is thrown if call to mb_split failed. + // Usually it happens, when $search or $replace are not valid for given mb_regex_encoding(). + // There may be other cases for it to fail, please file an issue if you find a reproducible one. + throw new SmartyException("Source string is not a valid $current_charset sequence (probably)"); + } + $count = count($parts) - 1; $subject = implode($replace, $parts); + // Convert results back to charset used by Smarty, if needed. + if($convert_result) { + $subject = mb_convert_encoding($subject, Smarty::$_CHARSET, $current_charset); + } } return $subject; } diff --git a/tools/smarty/plugins/variablefilter.htmlspecialchars.php b/tools/smarty/plugins/variablefilter.htmlspecialchars.php index 3c85295db..2eb12d20a 100644 --- a/tools/smarty/plugins/variablefilter.htmlspecialchars.php +++ b/tools/smarty/plugins/variablefilter.htmlspecialchars.php @@ -15,5 +15,5 @@ */ function smarty_variablefilter_htmlspecialchars($source, Smarty_Internal_Template $template) { - return htmlspecialchars($source, ENT_QUOTES, Smarty::$_CHARSET); + return htmlspecialchars((string) $source, ENT_QUOTES, Smarty::$_CHARSET); } diff --git a/tools/smarty/sysplugins/index.php b/tools/smarty/sysplugins/index.php deleted file mode 100644 index b1297ac0b..000000000 --- a/tools/smarty/sysplugins/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2020 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/smarty/sysplugins/smarty_cacheresource.php b/tools/smarty/sysplugins/smarty_cacheresource.php index 91e9f3924..8a801b4d2 100644 --- a/tools/smarty/sysplugins/smarty_cacheresource.php +++ b/tools/smarty/sysplugins/smarty_cacheresource.php @@ -44,15 +44,15 @@ abstract class Smarty_CacheResource /** * Read the cached template and process header * - * @param Smarty_Internal_Template $_template template object - * @param Smarty_Template_Cached $cached cached object - * @param boolean $update flag if called because cache update + * @param Smarty_Internal_Template $_template template object + * @param Smarty_Template_Cached|null $cached cached object + * @param boolean $update flag if called because cache update * * @return boolean true or false if the cached content does not exist */ abstract public function process( Smarty_Internal_Template $_template, - Smarty_Template_Cached $cached = null, + ?Smarty_Template_Cached $cached = null, $update = false ); @@ -205,11 +205,11 @@ abstract class Smarty_CacheResource } // try sysplugins dir if (isset(self::$sysplugins[ $type ])) { - $cache_resource_class = 'Smarty_Internal_CacheResource_' . ucfirst($type); + $cache_resource_class = 'Smarty_Internal_CacheResource_' . smarty_ucfirst_ascii($type); return $smarty->_cache[ 'cacheresource_handlers' ][ $type ] = new $cache_resource_class(); } // try plugins dir - $cache_resource_class = 'Smarty_CacheResource_' . ucfirst($type); + $cache_resource_class = 'Smarty_CacheResource_' . smarty_ucfirst_ascii($type); if ($smarty->loadPlugin($cache_resource_class)) { return $smarty->_cache[ 'cacheresource_handlers' ][ $type ] = new $cache_resource_class(); } diff --git a/tools/smarty/sysplugins/smarty_cacheresource_custom.php b/tools/smarty/sysplugins/smarty_cacheresource_custom.php index 68ad11289..af2274815 100644 --- a/tools/smarty/sysplugins/smarty_cacheresource_custom.php +++ b/tools/smarty/sysplugins/smarty_cacheresource_custom.php @@ -124,15 +124,15 @@ abstract class Smarty_CacheResource_Custom extends Smarty_CacheResource /** * Read the cached template and process the header * - * @param \Smarty_Internal_Template $_smarty_tpl do not change variable name, is used by compiled template - * @param Smarty_Template_Cached $cached cached object - * @param boolean $update flag if called because cache update + * @param \Smarty_Internal_Template $_smarty_tpl do not change variable name, is used by compiled template + * @param Smarty_Template_Cached|null $cached cached object + * @param boolean $update flag if called because cache update * * @return boolean true or false if the cached content does not exist */ public function process( Smarty_Internal_Template $_smarty_tpl, - Smarty_Template_Cached $cached = null, + ?Smarty_Template_Cached $cached = null, $update = false ) { if (!$cached) { diff --git a/tools/smarty/sysplugins/smarty_cacheresource_keyvaluestore.php b/tools/smarty/sysplugins/smarty_cacheresource_keyvaluestore.php index 59bf1d4a8..92c699ebc 100644 --- a/tools/smarty/sysplugins/smarty_cacheresource_keyvaluestore.php +++ b/tools/smarty/sysplugins/smarty_cacheresource_keyvaluestore.php @@ -88,15 +88,15 @@ abstract class Smarty_CacheResource_KeyValueStore extends Smarty_CacheResource /** * Read the cached template and process the header * - * @param \Smarty_Internal_Template $_smarty_tpl do not change variable name, is used by compiled template - * @param Smarty_Template_Cached $cached cached object - * @param boolean $update flag if called because cache update + * @param \Smarty_Internal_Template $_smarty_tpl do not change variable name, is used by compiled template + * @param Smarty_Template_Cached|null $cached cached object + * @param boolean $update flag if called because cache update * * @return boolean true or false if the cached content does not exist */ public function process( Smarty_Internal_Template $_smarty_tpl, - Smarty_Template_Cached $cached = null, + ?Smarty_Template_Cached $cached = null, $update = false ) { if (!$cached) { @@ -244,7 +244,7 @@ abstract class Smarty_CacheResource_KeyValueStore extends Smarty_CacheResource */ protected function sanitize($string) { - $string = trim($string, '|'); + $string = trim((string)$string, '|'); if (!$string) { return ''; } @@ -428,7 +428,7 @@ abstract class Smarty_CacheResource_KeyValueStore extends Smarty_CacheResource $t[] = 'IVK#COMPILE' . $_compile; } $_name .= '#'; - $cid = trim($cache_id, '|'); + $cid = trim((string)$cache_id, '|'); if (!$cid) { return $t; } diff --git a/tools/smarty/sysplugins/smarty_internal_cacheresource_file.php b/tools/smarty/sysplugins/smarty_internal_cacheresource_file.php index 61618449d..9d64c5a3e 100644 --- a/tools/smarty/sysplugins/smarty_internal_cacheresource_file.php +++ b/tools/smarty/sysplugins/smarty_internal_cacheresource_file.php @@ -88,15 +88,15 @@ class Smarty_Internal_CacheResource_File extends Smarty_CacheResource /** * Read the cached template and process its header * - * @param \Smarty_Internal_Template $_smarty_tpl do not change variable name, is used by compiled template - * @param Smarty_Template_Cached $cached cached object - * @param bool $update flag if called because cache update + * @param \Smarty_Internal_Template $_smarty_tpl do not change variable name, is used by compiled template + * @param Smarty_Template_Cached|null $cached cached object + * @param bool $update flag if called because cache update * * @return boolean true or false if the cached content does not exist */ public function process( Smarty_Internal_Template $_smarty_tpl, - Smarty_Template_Cached $cached = null, + ?Smarty_Template_Cached $cached = null, $update = false ) { $_smarty_tpl->cached->valid = false; @@ -196,12 +196,8 @@ class Smarty_Internal_CacheResource_File extends Smarty_CacheResource */ public function hasLock(Smarty $smarty, Smarty_Template_Cached $cached) { - if (version_compare(PHP_VERSION, '5.3.0', '>=')) { - clearstatcache(true, $cached->lock_id); - } else { - clearstatcache(); - } - if (is_file($cached->lock_id)) { + clearstatcache(true, $cached->lock_id ?? ''); + if (null !== $cached->lock_id && is_file($cached->lock_id)) { $t = filemtime($cached->lock_id); return $t && (time() - $t < $smarty->locking_timeout); } else { diff --git a/tools/smarty/sysplugins/smarty_internal_compile_block.php b/tools/smarty/sysplugins/smarty_internal_compile_block.php index 8ff15d8e5..cbaccd2b3 100644 --- a/tools/smarty/sysplugins/smarty_internal_compile_block.php +++ b/tools/smarty/sysplugins/smarty_internal_compile_block.php @@ -125,7 +125,7 @@ class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_Compile_Shared_ // setup buffer for template function code $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template(); $output = "cStyleComment(" {block {$_name}} ") . "\n"; $output .= "class {$_className} extends Smarty_Internal_Block\n"; $output .= "{\n"; foreach ($_block as $property => $value) { @@ -155,7 +155,7 @@ class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_Compile_Shared_ } $output .= "}\n"; $output .= "}\n"; - $output .= "/* {/block {$_name}} */\n\n"; + $output .= $compiler->cStyleComment(" {/block {$_name}} ") . "\n\n"; $output .= "?>\n"; $compiler->parser->current_buffer->append_subtree( $compiler->parser, diff --git a/tools/smarty/sysplugins/smarty_internal_compile_extends.php b/tools/smarty/sysplugins/smarty_internal_compile_extends.php index d72d2b76f..69a7b5521 100644 --- a/tools/smarty/sysplugins/smarty_internal_compile_extends.php +++ b/tools/smarty/sysplugins/smarty_internal_compile_extends.php @@ -30,7 +30,7 @@ class Smarty_Internal_Compile_Extends extends Smarty_Internal_Compile_Shared_Inh * * @var array */ - public $optional_attributes = array('extends_resource'); + public $optional_attributes = array(); /** * Attribute definition: Overwrites base class. @@ -62,29 +62,7 @@ class Smarty_Internal_Compile_Extends extends Smarty_Internal_Compile_Shared_Inh } // add code to initialize inheritance $this->registerInit($compiler, true); - $file = trim($_attr[ 'file' ], '\'"'); - if (strlen($file) > 8 && substr($file, 0, 8) === 'extends:') { - // generate code for each template - $files = array_reverse(explode('|', substr($file, 8))); - $i = 0; - foreach ($files as $file) { - if ($file[ 0 ] === '"') { - $file = trim($file, '".'); - } else { - $file = "'{$file}'"; - } - $i++; - if ($i === count($files) && isset($_attr[ 'extends_resource' ])) { - $this->compileEndChild($compiler); - } - $this->compileInclude($compiler, $file); - } - if (!isset($_attr[ 'extends_resource' ])) { - $this->compileEndChild($compiler); - } - } else { - $this->compileEndChild($compiler, $_attr[ 'file' ]); - } + $this->compileEndChild($compiler, $_attr[ 'file' ]); $compiler->has_code = false; return ''; } @@ -115,44 +93,4 @@ class Smarty_Internal_Compile_Extends extends Smarty_Internal_Compile_Shared_Inh '') . ");\n?>" ); } - - /** - * Add code for including subtemplate to end of template - * - * @param \Smarty_Internal_TemplateCompilerBase $compiler - * @param string $template subtemplate name - * - * @throws \SmartyCompilerException - * @throws \SmartyException - */ - private function compileInclude(Smarty_Internal_TemplateCompilerBase $compiler, $template) - { - $compiler->parser->template_postfix[] = new Smarty_Internal_ParseTree_Tag( - $compiler->parser, - $compiler->compileTag( - 'include', - array( - $template, - array('scope' => 'parent') - ) - ) - ); - } - - /** - * Create source code for {extends} from source components array - * - * @param \Smarty_Internal_Template $template - * - * @return string - */ - public static function extendsSourceArrayCode(Smarty_Internal_Template $template) - { - $resources = array(); - foreach ($template->source->components as $source) { - $resources[] = $source->resource; - } - return $template->smarty->left_delimiter . 'extends file=\'extends:' . join('|', $resources) . - '\' extends_resource=true' . $template->smarty->right_delimiter; - } } diff --git a/tools/smarty/sysplugins/smarty_internal_compile_for.php b/tools/smarty/sysplugins/smarty_internal_compile_for.php index 3f113e56d..969e22c1a 100644 --- a/tools/smarty/sysplugins/smarty_internal_compile_for.php +++ b/tools/smarty/sysplugins/smarty_internal_compile_for.php @@ -18,7 +18,7 @@ class Smarty_Internal_Compile_For extends Smarty_Internal_CompileBase { /** * Compiles code for the {for} tag - * Smarty 3 does implement two different syntax's: + * Smarty supports two different syntax's: * - {for $var in $array} * For looping over arrays or iterators * - {for $x=0; $x<$y; $x++} diff --git a/tools/smarty/sysplugins/smarty_internal_compile_foreach.php b/tools/smarty/sysplugins/smarty_internal_compile_foreach.php index a68da5409..edfe358be 100644 --- a/tools/smarty/sysplugins/smarty_internal_compile_foreach.php +++ b/tools/smarty/sysplugins/smarty_internal_compile_foreach.php @@ -219,9 +219,9 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_Compile_Private_Fo if (isset($itemAttr[ 'index' ])) { $output .= "{$itemVar}->index = -1;\n"; } - $output .= "{$itemVar}->do_else = true;\n"; + $output .= "{$itemVar}->do_else = true;\n"; $output .= "if (\$_from !== null) foreach (\$_from as {$keyTerm}{$itemVar}->value) {\n"; - $output .= "{$itemVar}->do_else = false;\n"; + $output .= "{$itemVar}->do_else = false;\n"; if (isset($attributes[ 'key' ]) && isset($itemAttr[ 'key' ])) { $output .= "\$_smarty_tpl->tpl_vars['{$key}']->value = {$itemVar}->key;\n"; } diff --git a/tools/smarty/sysplugins/smarty_internal_compile_function.php b/tools/smarty/sysplugins/smarty_internal_compile_function.php index d0f2b0f4a..b05a82b74 100644 --- a/tools/smarty/sysplugins/smarty_internal_compile_function.php +++ b/tools/smarty/sysplugins/smarty_internal_compile_function.php @@ -134,7 +134,7 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase if ($compiler->template->compiled->has_nocache_code) { $compiler->parent_compiler->tpl_function[ $_name ][ 'call_name_caching' ] = $_funcNameCaching; $output = "cStyleComment(" {$_funcNameCaching} ") . "\n"; $output .= "if (!function_exists('{$_funcNameCaching}')) {\n"; $output .= "function {$_funcNameCaching} (Smarty_Internal_Template \$_smarty_tpl,\$params) {\n"; $output .= "ob_start();\n"; @@ -157,9 +157,9 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase $output = "template->compiled->nocache_hash}%%*/smarty->ext->_tplFunction->restoreTemplateVariables(\\\$_smarty_tpl, '{$_name}');?>\n"; $output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\";\n?>"; - $output .= "template->compiled->nocache_hash}', \$_smarty_tpl->compiled->nocache_hash, ob_get_clean());\n"; + $output .= "template->compiled->nocache_hash}', \$_smarty_tpl->compiled->nocache_hash ?? '', ob_get_clean());\n"; $output .= "}\n}\n"; - $output .= "/*/ {$_funcName}_nocache */\n\n"; + $output .= $compiler->cStyleComment("/ {$_funcName}_nocache ") . "\n\n"; $output .= "?>\n"; $compiler->parser->current_buffer->append_subtree( $compiler->parser, @@ -179,7 +179,7 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase } $compiler->parent_compiler->tpl_function[ $_name ][ 'call_name' ] = $_funcName; $output = "cStyleComment(" {$_funcName} ") . "\n"; $output .= "if (!function_exists('{$_funcName}')) {\n"; $output .= "function {$_funcName}(Smarty_Internal_Template \$_smarty_tpl,\$params) {\n"; $output .= $_paramsCode; @@ -196,7 +196,7 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase ); $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); $output = "cStyleComment("/ {$_funcName} ") . "\n\n"; $output .= "?>\n"; $compiler->parser->current_buffer->append_subtree( $compiler->parser, diff --git a/tools/smarty/sysplugins/smarty_internal_compile_include.php b/tools/smarty/sysplugins/smarty_internal_compile_include.php index 716c91d49..bf62461bc 100644 --- a/tools/smarty/sysplugins/smarty_internal_compile_include.php +++ b/tools/smarty/sysplugins/smarty_internal_compile_include.php @@ -318,14 +318,14 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase } // get compiled code $compiled_code = "cStyleComment(" Start inline template \"{$sourceInfo}\" =============================") . "\n"; $compiled_code .= "function {$tpl->compiled->unifunc} (Smarty_Internal_Template \$_smarty_tpl) {\n"; $compiled_code .= "?>\n" . $tpl->compiler->compileTemplateSource($tpl, null, $compiler->parent_compiler); $compiled_code .= "\n"; $compiled_code .= $tpl->compiler->postFilter($tpl->compiler->blockOrFunctionCode); $compiled_code .= "cStyleComment(" End inline template \"{$sourceInfo}\" =============================") . "\n"; $compiled_code .= '?>'; unset($tpl->compiler); if ($tpl->compiled->has_nocache_code) { diff --git a/tools/smarty/sysplugins/smarty_internal_compile_include_php.php b/tools/smarty/sysplugins/smarty_internal_compile_include_php.php deleted file mode 100644 index 1b0fdaad3..000000000 --- a/tools/smarty/sysplugins/smarty_internal_compile_include_php.php +++ /dev/null @@ -1,110 +0,0 @@ -smarty instanceof SmartyBC)) { - throw new SmartyException("{include_php} is deprecated, use SmartyBC class to enable"); - } - // check and get attributes - $_attr = $this->getAttributes($compiler, $args); - /** - * - * - * @var Smarty_Internal_Template $_smarty_tpl - * used in evaluated code - */ - $_smarty_tpl = $compiler->template; - $_filepath = false; - $_file = null; - eval('$_file = @' . $_attr[ 'file' ] . ';'); - if (!isset($compiler->smarty->security_policy) && file_exists($_file)) { - $_filepath = $compiler->smarty->_realpath($_file, true); - } else { - if (isset($compiler->smarty->security_policy)) { - $_dir = $compiler->smarty->security_policy->trusted_dir; - } else { - $_dir = $compiler->smarty->trusted_dir; - } - if (!empty($_dir)) { - foreach ((array)$_dir as $_script_dir) { - $_path = $compiler->smarty->_realpath($_script_dir . DIRECTORY_SEPARATOR . $_file, true); - if (file_exists($_path)) { - $_filepath = $_path; - break; - } - } - } - } - if ($_filepath === false) { - $compiler->trigger_template_error("{include_php} file '{$_file}' is not readable", null, true); - } - if (isset($compiler->smarty->security_policy)) { - $compiler->smarty->security_policy->isTrustedPHPDir($_filepath); - } - if (isset($_attr[ 'assign' ])) { - // output will be stored in a smarty variable instead of being displayed - $_assign = $_attr[ 'assign' ]; - } - $_once = '_once'; - if (isset($_attr[ 'once' ])) { - if ($_attr[ 'once' ] === 'false') { - $_once = ''; - } - } - if (isset($_assign)) { - return "assign({$_assign},ob_get_clean());\n?>"; - } else { - return "\n"; - } - } -} diff --git a/tools/smarty/sysplugins/smarty_internal_compile_insert.php b/tools/smarty/sysplugins/smarty_internal_compile_insert.php index 4bdc3952e..29031d910 100644 --- a/tools/smarty/sysplugins/smarty_internal_compile_insert.php +++ b/tools/smarty/sysplugins/smarty_internal_compile_insert.php @@ -89,11 +89,11 @@ class Smarty_Internal_Compile_Insert extends Smarty_Internal_CompileBase if (isset($compiler->smarty->security_policy)) { $_dir = $compiler->smarty->security_policy->trusted_dir; } else { - $_dir = $compiler->smarty instanceof SmartyBC ? $compiler->smarty->trusted_dir : null; + $_dir = null; } if (!empty($_dir)) { foreach ((array)$_dir as $_script_dir) { - $_script_dir = rtrim($_script_dir, '/\\') . DIRECTORY_SEPARATOR; + $_script_dir = rtrim($_script_dir ?? '', '/\\') . DIRECTORY_SEPARATOR; if (file_exists($_script_dir . $_script)) { $_filepath = $_script_dir . $_script; break; diff --git a/tools/smarty/sysplugins/smarty_internal_compile_private_foreachsection.php b/tools/smarty/sysplugins/smarty_internal_compile_private_foreachsection.php index d3aab24bb..246350dc8 100644 --- a/tools/smarty/sysplugins/smarty_internal_compile_private_foreachsection.php +++ b/tools/smarty/sysplugins/smarty_internal_compile_private_foreachsection.php @@ -143,7 +143,7 @@ class Smarty_Internal_Compile_Private_ForeachSection extends Smarty_Internal_Com foreach ($this->resultOffsets as $key => $offset) { foreach ($match[ $offset ] as $m) { if (!empty($m)) { - $this->matchResults[ $key ][ strtolower($m) ] = true; + $this->matchResults[ $key ][ smarty_strtolower_ascii($m) ] = true; } } } @@ -213,12 +213,12 @@ class Smarty_Internal_Compile_Private_ForeachSection extends Smarty_Internal_Com */ public function compileSpecialVariable($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) { - $tag = strtolower(trim($parameter[ 0 ], '"\'')); + $tag = smarty_strtolower_ascii(trim($parameter[ 0 ], '"\'')); $name = isset($parameter[ 1 ]) ? $compiler->getId($parameter[ 1 ]) : false; if (!$name) { $compiler->trigger_template_error("missing or illegal \$smarty.{$tag} name attribute", null, true); } - $property = isset($parameter[ 2 ]) ? strtolower($compiler->getId($parameter[ 2 ])) : false; + $property = isset($parameter[ 2 ]) ? smarty_strtolower_ascii($compiler->getId($parameter[ 2 ])) : false; if (!$property || !in_array($property, $this->nameProperties)) { $compiler->trigger_template_error("missing or illegal \$smarty.{$tag} property attribute", null, true); } diff --git a/tools/smarty/sysplugins/smarty_internal_compile_private_modifier.php b/tools/smarty/sysplugins/smarty_internal_compile_private_modifier.php index 72773fff8..0eead3429 100644 --- a/tools/smarty/sysplugins/smarty_internal_compile_private_modifier.php +++ b/tools/smarty/sysplugins/smarty_internal_compile_private_modifier.php @@ -109,6 +109,11 @@ class Smarty_Internal_Compile_Private_Modifier extends Smarty_Internal_CompileBa if (!is_object($compiler->smarty->security_policy) || $compiler->smarty->security_policy->isTrustedPhpModifier($modifier, $compiler) ) { + if (!in_array($modifier, ['time', 'join', 'is_array', 'in_array'])) { + // trigger_error('Using unregistered function "' . $modifier . '" in a template is deprecated and will be ' . + // 'removed in a future release. Use Smarty::registerPlugin to explicitly register ' . + // 'a custom modifier.', E_USER_DEPRECATED); + } $output = "{$modifier}({$params})"; } $compiler->known_modifier_type[ $modifier ] = $type; diff --git a/tools/smarty/sysplugins/smarty_internal_compile_private_php.php b/tools/smarty/sysplugins/smarty_internal_compile_private_php.php deleted file mode 100644 index ff48c6fbc..000000000 --- a/tools/smarty/sysplugins/smarty_internal_compile_private_php.php +++ /dev/null @@ -1,253 +0,0 @@ -getAttributes($compiler, $args); - $compiler->has_code = false; - if ($_attr[ 'type' ] === 'xml') { - $compiler->tag_nocache = true; - $output = addcslashes($_attr[ 'code' ], "'\\"); - $compiler->parser->current_buffer->append_subtree( - $compiler->parser, - new Smarty_Internal_ParseTree_Tag( - $compiler->parser, - $compiler->processNocacheCode( - "\n", - true - ) - ) - ); - return ''; - } - if ($_attr[ 'type' ] !== 'tag') { - if ($compiler->php_handling === Smarty::PHP_REMOVE) { - return ''; - } elseif ($compiler->php_handling === Smarty::PHP_QUOTE) { - $output = - preg_replace_callback( - '#(<\?(?:php|=)?)|(<%)|()|(\?>)|(%>)|(<\/script>)#i', - array($this, 'quote'), - $_attr[ 'code' ] - ); - $compiler->parser->current_buffer->append_subtree( - $compiler->parser, - new Smarty_Internal_ParseTree_Text($output) - ); - return ''; - } elseif ($compiler->php_handling === Smarty::PHP_PASSTHRU || $_attr[ 'type' ] === 'unmatched') { - $compiler->tag_nocache = true; - $output = addcslashes($_attr[ 'code' ], "'\\"); - $compiler->parser->current_buffer->append_subtree( - $compiler->parser, - new Smarty_Internal_ParseTree_Tag( - $compiler->parser, - $compiler->processNocacheCode( - "\n", - true - ) - ) - ); - return ''; - } elseif ($compiler->php_handling === Smarty::PHP_ALLOW) { - if (!($compiler->smarty instanceof SmartyBC)) { - $compiler->trigger_template_error( - '$smarty->php_handling PHP_ALLOW not allowed. Use SmartyBC to enable it', - null, - true - ); - } - $compiler->has_code = true; - return $_attr[ 'code' ]; - } else { - $compiler->trigger_template_error('Illegal $smarty->php_handling value', null, true); - } - } else { - $compiler->has_code = true; - if (!($compiler->smarty instanceof SmartyBC)) { - $compiler->trigger_template_error( - '{php}{/php} tags not allowed. Use SmartyBC to enable them', - null, - true - ); - } - $ldel = preg_quote($compiler->smarty->left_delimiter, '#'); - $rdel = preg_quote($compiler->smarty->right_delimiter, '#'); - preg_match("#^({$ldel}php\\s*)((.)*?)({$rdel})#", $_attr[ 'code' ], $match); - if (!empty($match[ 2 ])) { - if ('nocache' === trim($match[ 2 ])) { - $compiler->tag_nocache = true; - } else { - $compiler->trigger_template_error("illegal value of option flag '{$match[2]}'", null, true); - } - } - return preg_replace( - array("#^{$ldel}\\s*php\\s*(.)*?{$rdel}#", "#{$ldel}\\s*/\\s*php\\s*{$rdel}$#"), - array(''), - $_attr[ 'code' ] - ); - } - } - - /** - * Lexer code for PHP tags - * - * This code has been moved from lexer here fo easier debugging and maintenance - * - * @param Smarty_Internal_Templatelexer $lex - * - * @throws \SmartyCompilerException - */ - public function parsePhp(Smarty_Internal_Templatelexer $lex) - { - $lex->token = Smarty_Internal_Templateparser::TP_PHP; - $close = 0; - $lex->taglineno = $lex->line; - $closeTag = '?>'; - if (strpos($lex->value, 'is_xml = true; - $lex->phpType = 'xml'; - return; - } elseif (strpos($lex->value, 'phpType = 'php'; - } elseif (strpos($lex->value, '<%') === 0) { - $lex->phpType = 'asp'; - $closeTag = '%>'; - } elseif (strpos($lex->value, '%>') === 0) { - $lex->phpType = 'unmatched'; - } elseif (strpos($lex->value, '?>') === 0) { - if ($lex->is_xml) { - $lex->is_xml = false; - $lex->phpType = 'xml'; - return; - } - $lex->phpType = 'unmatched'; - } elseif (strpos($lex->value, 'phpType = 'script'; - $closeTag = ''; - } elseif (strpos($lex->value, $lex->smarty->left_delimiter) === 0) { - if ($lex->isAutoLiteral()) { - $lex->token = Smarty_Internal_Templateparser::TP_TEXT; - return; - } - $closeTag = "{$lex->smarty->left_delimiter}/php{$lex->smarty->right_delimiter}"; - if ($lex->value === $closeTag) { - $lex->compiler->trigger_template_error("unexpected closing tag '{$closeTag}'"); - } - $lex->phpType = 'tag'; - } - if ($lex->phpType === 'unmatched') { - return; - } - if (($lex->phpType === 'php' || $lex->phpType === 'asp') - && - ($lex->compiler->php_handling === Smarty::PHP_PASSTHRU || - $lex->compiler->php_handling === Smarty::PHP_QUOTE) - ) { - return; - } - $start = $lex->counter + strlen($lex->value); - $body = true; - if (preg_match('~' . preg_quote($closeTag, '~') . '~i', $lex->data, $match, PREG_OFFSET_CAPTURE, $start)) { - $close = $match[ 0 ][ 1 ]; - } else { - $lex->compiler->trigger_template_error("missing closing tag '{$closeTag}'"); - } - while ($body) { - if (preg_match( - '~([/][*])|([/][/][^\n]*)|(\'[^\'\\\\]*(?:\\.[^\'\\\\]*)*\')|("[^"\\\\]*(?:\\.[^"\\\\]*)*")~', - $lex->data, - $match, - PREG_OFFSET_CAPTURE, - $start - ) - ) { - $value = $match[ 0 ][ 0 ]; - $from = $pos = $match[ 0 ][ 1 ]; - if ($pos > $close) { - $body = false; - } else { - $start = $pos + strlen($value); - $phpCommentStart = $value === '/*'; - if ($phpCommentStart) { - $phpCommentEnd = preg_match('~([*][/])~', $lex->data, $match, PREG_OFFSET_CAPTURE, $start); - if ($phpCommentEnd) { - $pos2 = $match[ 0 ][ 1 ]; - $start = $pos2 + strlen($match[ 0 ][ 0 ]); - } - } - while ($close > $pos && $close < $start) { - if (preg_match( - '~' . preg_quote($closeTag, '~') . '~i', - $lex->data, - $match, - PREG_OFFSET_CAPTURE, - $from - ) - ) { - $close = $match[ 0 ][ 1 ]; - $from = $close + strlen($match[ 0 ][ 0 ]); - } else { - $lex->compiler->trigger_template_error("missing closing tag '{$closeTag}'"); - } - } - if ($phpCommentStart && (!$phpCommentEnd || $pos2 > $close)) { - $lex->taglineno = $lex->line + substr_count(substr($lex->data, $lex->counter, $start), "\n"); - $lex->compiler->trigger_template_error("missing PHP comment closing tag '*/'"); - } - } - } else { - $body = false; - } - } - $lex->value = substr($lex->data, $lex->counter, $close + strlen($closeTag) - $lex->counter); - } - - /* - * Call back function for $php_handling = PHP_QUOTE - * - */ - /** - * @param $match - * - * @return string - */ - private function quote($match) - { - return htmlspecialchars($match[ 0 ], ENT_QUOTES); - } -} diff --git a/tools/smarty/sysplugins/smarty_internal_compile_private_print_expression.php b/tools/smarty/sysplugins/smarty_internal_compile_private_print_expression.php index 23cae8aef..78f1c0763 100644 --- a/tools/smarty/sysplugins/smarty_internal_compile_private_print_expression.php +++ b/tools/smarty/sysplugins/smarty_internal_compile_private_print_expression.php @@ -93,7 +93,7 @@ class Smarty_Internal_Compile_Private_Print_Expression extends Smarty_Internal_C } // autoescape html if ($compiler->template->smarty->escape_html) { - $output = "htmlspecialchars({$output}, ENT_QUOTES, '" . addslashes(Smarty::$_CHARSET) . "')"; + $output = "htmlspecialchars((string) ({$output}), ENT_QUOTES, '" . addslashes(Smarty::$_CHARSET) . "')"; } // loop over registered filters if (!empty($compiler->template->smarty->registered_filters[ Smarty::FILTER_VARIABLE ])) { diff --git a/tools/smarty/sysplugins/smarty_internal_compile_private_special_variable.php b/tools/smarty/sysplugins/smarty_internal_compile_private_special_variable.php index d53ef51ff..590cba5af 100644 --- a/tools/smarty/sysplugins/smarty_internal_compile_private_special_variable.php +++ b/tools/smarty/sysplugins/smarty_internal_compile_private_special_variable.php @@ -29,7 +29,7 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) { $_index = preg_split("/\]\[/", substr($parameter, 1, strlen($parameter) - 2)); - $variable = strtolower($compiler->getId($_index[ 0 ])); + $variable = smarty_strtolower_ascii($compiler->getId($_index[ 0 ])); if ($variable === false) { $compiler->trigger_template_error("special \$Smarty variable name index can not be variable", null, true); } @@ -40,7 +40,7 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C case 'foreach': case 'section': if (!isset(Smarty_Internal_TemplateCompilerBase::$_tag_objects[ $variable ])) { - $class = 'Smarty_Internal_Compile_' . ucfirst($variable); + $class = 'Smarty_Internal_Compile_' . smarty_ucfirst_ascii($variable); Smarty_Internal_TemplateCompilerBase::$_tag_objects[ $variable ] = new $class; } return Smarty_Internal_TemplateCompilerBase::$_tag_objects[ $variable ]->compileSpecialVariable( @@ -76,7 +76,7 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C $compiler->trigger_template_error("(secure mode) super globals not permitted"); break; } - $compiled_ref = '$_' . strtoupper($variable); + $compiled_ref = '$_' . smarty_strtoupper_ascii($variable); break; case 'template': return 'basename($_smarty_tpl->source->filepath)'; diff --git a/tools/smarty/sysplugins/smarty_internal_config_file_compiler.php b/tools/smarty/sysplugins/smarty_internal_config_file_compiler.php index 90c5dcefa..469b9667a 100644 --- a/tools/smarty/sysplugins/smarty_internal_config_file_compiler.php +++ b/tools/smarty/sysplugins/smarty_internal_config_file_compiler.php @@ -157,10 +157,12 @@ class Smarty_Internal_Config_File_Compiler $this->smarty->_debug->end_compile($this->template); } // template header code - $template_header = - "template->source->filepath}' */ ?>\n"; + $template_header = sprintf( + "\n", + Smarty::SMARTY_VERSION, + date("Y-m-d H:i:s"), + str_replace('*/', '* /' , $this->template->source->filepath) + ); $code = 'smarty->ext->configLoad->_loadConfigVars($_smarty_tpl, ' . var_export($this->config_data, true) . '); ?>'; return $template_header . $this->template->smarty->ext->_codeFrame->create($this->template, $code); diff --git a/tools/smarty/sysplugins/smarty_internal_data.php b/tools/smarty/sysplugins/smarty_internal_data.php index 98e3e57b3..c7ce61595 100644 --- a/tools/smarty/sysplugins/smarty_internal_data.php +++ b/tools/smarty/sysplugins/smarty_internal_data.php @@ -121,7 +121,7 @@ abstract class Smarty_Internal_Data * appends values to template variables * * @api Smarty::append() - * @link http://www.smarty.net/docs/en/api.append.tpl + * @link https://www.smarty.net/docs/en/api.append.tpl * * @param array|string $tpl_var the template variable name(s) * @param mixed $value the value to append @@ -182,7 +182,7 @@ abstract class Smarty_Internal_Data * Returns a single or all template variables * * @api Smarty::getTemplateVars() - * @link http://www.smarty.net/docs/en/api.get.template.vars.tpl + * @link https://www.smarty.net/docs/en/api.get.template.vars.tpl * * @param string $varName variable name or null * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty $_ptr optional pointer to data object @@ -190,37 +190,17 @@ abstract class Smarty_Internal_Data * * @return mixed variable value or or array of variables */ - public function getTemplateVars($varName = null, Smarty_Internal_Data $_ptr = null, $searchParents = true) + public function getTemplateVars($varName = null, ?Smarty_Internal_Data $_ptr = null, $searchParents = true) { return $this->ext->getTemplateVars->getTemplateVars($this, $varName, $_ptr, $searchParents); } - /** - * gets the object of a Smarty variable - * - * @param string $variable the name of the Smarty variable - * @param Smarty_Internal_Data $_ptr optional pointer to data object - * @param boolean $searchParents search also in parent data - * @param bool $error_enable - * - * @return Smarty_Variable|Smarty_Undefined_Variable the object of the variable - * @deprecated since 3.1.28 please use Smarty_Internal_Data::getTemplateVars() instead. - */ - public function getVariable( - $variable = null, - Smarty_Internal_Data $_ptr = null, - $searchParents = true, - $error_enable = true - ) { - return $this->ext->getTemplateVars->_getVariable($this, $variable, $_ptr, $searchParents, $error_enable); - } - /** * Follow the parent chain an merge template and config variables * * @param \Smarty_Internal_Data|null $data */ - public function _mergeVars(Smarty_Internal_Data $data = null) + public function _mergeVars(?Smarty_Internal_Data $data = null) { if (isset($data)) { if (!empty($this->tpl_vars)) { diff --git a/tools/smarty/sysplugins/smarty_internal_debug.php b/tools/smarty/sysplugins/smarty_internal_debug.php index 24b233e26..da67904c5 100644 --- a/tools/smarty/sysplugins/smarty_internal_debug.php +++ b/tools/smarty/sysplugins/smarty_internal_debug.php @@ -210,7 +210,7 @@ class Smarty_Internal_Debug extends Smarty_Internal_Data // copy the working dirs from application $debObj->setCompileDir($smarty->getCompileDir()); // init properties by hand as user may have edited the original Smarty class - $debObj->setPluginsDir(is_dir(dirname(__FILE__) . '/../plugins') ? dirname(__FILE__) . + $debObj->setPluginsDir(is_dir(__DIR__ . '/../plugins') ? __DIR__ . '/../plugins' : $smarty->getPluginsDir()); $debObj->force_compile = false; $debObj->compile_check = Smarty::COMPILECHECK_ON; @@ -221,7 +221,7 @@ class Smarty_Internal_Debug extends Smarty_Internal_Data $debObj->debugging_ctrl = 'NONE'; $debObj->error_reporting = E_ALL & ~E_NOTICE; $debObj->debug_tpl = - isset($smarty->debug_tpl) ? $smarty->debug_tpl : 'file:' . dirname(__FILE__) . '/../debug.tpl'; + isset($smarty->debug_tpl) ? $smarty->debug_tpl : 'file:' . __DIR__ . '/../debug.tpl'; $debObj->registered_plugins = array(); $debObj->registered_resources = array(); $debObj->registered_filters = array(); @@ -238,9 +238,12 @@ class Smarty_Internal_Debug extends Smarty_Internal_Data $_config_vars = $ptr->config_vars; ksort($_config_vars); $debugging = $smarty->debugging; + $templateName = $obj->source->type . ':' . $obj->source->name; + $displayMode = $debugging === 2 || !$full; + $offset = $this->offset * 50; $_template = new Smarty_Internal_Template($debObj->debug_tpl, $debObj); if ($obj->_isTplObj()) { - $_template->assign('template_name', $obj->source->type . ':' . $obj->source->name); + $_template->assign('template_name', $templateName); } if ($obj->_objType === 1 || $full) { $_template->assign('template_data', $this->template_data[ $this->index ]); @@ -250,8 +253,8 @@ class Smarty_Internal_Debug extends Smarty_Internal_Data $_template->assign('assigned_vars', $_assigned_vars); $_template->assign('config_vars', $_config_vars); $_template->assign('execution_time', microtime(true) - $smarty->start_time); - $_template->assign('display_mode', $debugging === 2 || !$full); - $_template->assign('offset', $this->offset * 50); + $_template->assign('targetWindow', $displayMode ? md5("$offset$templateName") : '__Smarty__'); + $_template->assign('offset', $offset); echo $_template->fetch(); if (isset($full)) { $this->index--; diff --git a/tools/smarty/sysplugins/smarty_internal_errorhandler.php b/tools/smarty/sysplugins/smarty_internal_errorhandler.php index 56dca18fa..4ddcfcd11 100644 --- a/tools/smarty/sysplugins/smarty_internal_errorhandler.php +++ b/tools/smarty/sysplugins/smarty_internal_errorhandler.php @@ -1,61 +1,72 @@ propName} where propName is undefined. + * @var bool */ - public static function muteExpectedErrors() - { + public $allowUndefinedProperties = true; + + /** + * Allows {$foo.bar} where bar is unset and {$foo.bar1.bar2} where either bar1 or bar2 is unset. + * @var bool + */ + public $allowUndefinedArrayKeys = true; + + /** + * Allows {$foo->bar} where bar is not an object (e.g. null or false). + * @var bool + */ + public $allowDereferencingNonObjects = true; + + private $previousErrorHandler = null; + + /** + * Enable error handler to intercept errors + */ + public function activate() { /* - error muting is done because some people implemented custom error_handlers using - http://php.net/set_error_handler and for some reason did not understand the following paragraph: + Error muting is done because some people implemented custom error_handlers using + https://php.net/set_error_handler and for some reason did not understand the following paragraph: - It is important to remember that the standard PHP error handler is completely bypassed for the - error types specified by error_types unless the callback function returns FALSE. - error_reporting() settings will have no effect and your error handler will be called regardless - - however you are still able to read the current value of error_reporting and act appropriately. - Of particular note is that this value will be 0 if the statement that caused the error was - prepended by the @ error-control operator. - - Smarty deliberately uses @filemtime() over file_exists() and filemtime() in some places. Reasons include - - @filemtime() is almost twice as fast as using an additional file_exists() - - between file_exists() and filemtime() a possible race condition is opened, - which does not exist using the simple @filemtime() approach. + It is important to remember that the standard PHP error handler is completely bypassed for the + error types specified by error_types unless the callback function returns FALSE. + error_reporting() settings will have no effect and your error handler will be called regardless - + however you are still able to read the current value of error_reporting and act appropriately. + Of particular note is that this value will be 0 if the statement that caused the error was + prepended by the @ error-control operator. */ - $error_handler = array('Smarty_Internal_ErrorHandler', 'mutingErrorHandler'); - $previous = set_error_handler($error_handler); - // avoid dead loops - if ($previous !== $error_handler) { - self::$previousErrorHandler = $previous; - } + $this->previousErrorHandler = set_error_handler([$this, 'handleError']); + } + + /** + * Disable error handler + */ + public function deactivate() { + restore_error_handler(); + $this->previousErrorHandler = null; } /** * Error Handler to mute expected messages * - * @link http://php.net/set_error_handler + * @link https://php.net/set_error_handler * * @param integer $errno Error level * @param $errstr @@ -65,49 +76,39 @@ class Smarty_Internal_ErrorHandler * * @return bool */ - public static function mutingErrorHandler($errno, $errstr, $errfile, $errline, $errcontext = array()) + public function handleError($errno, $errstr, $errfile, $errline, $errcontext = []) { - $_is_muted_directory = false; - // add the SMARTY_DIR to the list of muted directories - if (!isset(self::$mutedDirectories[ SMARTY_DIR ])) { - $smarty_dir = realpath(SMARTY_DIR); - if ($smarty_dir !== false) { - self::$mutedDirectories[ SMARTY_DIR ] = - array('file' => $smarty_dir, 'length' => strlen($smarty_dir),); - } + + if ($this->allowUndefinedVars && preg_match( + '/^(Attempt to read property "value" on null|Trying to get property (\'value\' )?of non-object)/', + $errstr + )) { + return; // suppresses this error } - // walk the muted directories and test against $errfile - foreach (self::$mutedDirectories as $key => &$dir) { - if (!$dir) { - // resolve directory and length for speedy comparisons - $file = realpath($key); - if ($file === false) { - // this directory does not exist, remove and skip it - unset(self::$mutedDirectories[ $key ]); - continue; - } - $dir = array('file' => $file, 'length' => strlen($file),); - } - if (!strncmp($errfile, $dir[ 'file' ], $dir[ 'length' ])) { - $_is_muted_directory = true; - break; - } + + if ($this->allowUndefinedProperties && preg_match( + '/^(Undefined property)/', + $errstr + )) { + return; // suppresses this error } - // pass to next error handler if this error did not occur inside SMARTY_DIR - // or the error was within smarty but masked to be ignored - if (!$_is_muted_directory || ($errno && $errno & error_reporting())) { - if (self::$previousErrorHandler) { - return call_user_func( - self::$previousErrorHandler, - $errno, - $errstr, - $errfile, - $errline, - $errcontext - ); - } else { - return false; - } + + if ($this->allowUndefinedArrayKeys && preg_match( + '/^(Undefined index|Undefined array key|Trying to access array offset on)/', + $errstr + )) { + return; // suppresses this error } + + if ($this->allowDereferencingNonObjects && preg_match( + '/^Attempt to read property ".+?" on/', + $errstr + )) { + return; // suppresses this error + } + + // pass all other errors through to the previous error handler or to the default PHP error handler + return $this->previousErrorHandler ? + call_user_func($this->previousErrorHandler, $errno, $errstr, $errfile, $errline, $errcontext) : false; } } diff --git a/tools/smarty/sysplugins/smarty_internal_extension_handler.php b/tools/smarty/sysplugins/smarty_internal_extension_handler.php index b07615526..3ef040ab1 100644 --- a/tools/smarty/sysplugins/smarty_internal_extension_handler.php +++ b/tools/smarty/sysplugins/smarty_internal_extension_handler.php @@ -36,6 +36,7 @@ * @property Smarty_Internal_Method_RegisterPlugin $registerPlugin * @property mixed|\Smarty_Template_Cached configLoad */ +#[\AllowDynamicProperties] class Smarty_Internal_Extension_Handler { public $objType = null; @@ -88,20 +89,19 @@ class Smarty_Internal_Extension_Handler $objType = $data->_objType; $propertyType = false; if (!isset($this->resolvedProperties[ $match[ 0 ] ][ $objType ])) { - $property = isset($this->resolvedProperties[ 'property' ][ $basename ]) ? - $this->resolvedProperties[ 'property' ][ $basename ] : - $property = $this->resolvedProperties[ 'property' ][ $basename ] = strtolower( - join( - '_', - preg_split( - '/([A-Z][^A-Z]*)/', - $basename, - -1, - PREG_SPLIT_NO_EMPTY | - PREG_SPLIT_DELIM_CAPTURE - ) + $property = $this->resolvedProperties['property'][$basename] ?? + $this->resolvedProperties['property'][$basename] = smarty_strtolower_ascii( + join( + '_', + preg_split( + '/([A-Z][^A-Z]*)/', + $basename, + -1, + PREG_SPLIT_NO_EMPTY | + PREG_SPLIT_DELIM_CAPTURE ) - ); + ) + ); if ($property !== false) { if (property_exists($data, $property)) { $propertyType = $this->resolvedProperties[ $match[ 0 ] ][ $objType ] = 1; @@ -145,7 +145,7 @@ class Smarty_Internal_Extension_Handler public function upperCase($name) { $_name = explode('_', $name); - $_name = array_map('ucfirst', $_name); + $_name = array_map('smarty_ucfirst_ascii', $_name); return implode('_', $_name); } diff --git a/tools/smarty/sysplugins/smarty_internal_method_append.php b/tools/smarty/sysplugins/smarty_internal_method_append.php index 881375efe..e207734e8 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_append.php +++ b/tools/smarty/sysplugins/smarty_internal_method_append.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_Append * appends values to template variables * * @api Smarty::append() - * @link http://www.smarty.net/docs/en/api.append.tpl + * @link https://www.smarty.net/docs/en/api.append.tpl * * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty $data * @param array|string $tpl_var the template variable name(s) diff --git a/tools/smarty/sysplugins/smarty_internal_method_appendbyref.php b/tools/smarty/sysplugins/smarty_internal_method_appendbyref.php index c95904460..b5be69b54 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_appendbyref.php +++ b/tools/smarty/sysplugins/smarty_internal_method_appendbyref.php @@ -15,7 +15,7 @@ class Smarty_Internal_Method_AppendByRef * appends values to template variables by reference * * @api Smarty::appendByRef() - * @link http://www.smarty.net/docs/en/api.append.by.ref.tpl + * @link https://www.smarty.net/docs/en/api.append.by.ref.tpl * * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty $data * @param string $tpl_var the template variable name diff --git a/tools/smarty/sysplugins/smarty_internal_method_clearallassign.php b/tools/smarty/sysplugins/smarty_internal_method_clearallassign.php index 29ff2ffb0..6fb0c8f3d 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_clearallassign.php +++ b/tools/smarty/sysplugins/smarty_internal_method_clearallassign.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_ClearAllAssign * clear all the assigned template variables. * * @api Smarty::clearAllAssign() - * @link http://www.smarty.net/docs/en/api.clear.all.assign.tpl + * @link https://www.smarty.net/docs/en/api.clear.all.assign.tpl * * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty $data * diff --git a/tools/smarty/sysplugins/smarty_internal_method_clearallcache.php b/tools/smarty/sysplugins/smarty_internal_method_clearallcache.php index 30d55f7d2..b74d30580 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_clearallcache.php +++ b/tools/smarty/sysplugins/smarty_internal_method_clearallcache.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_ClearAllCache * Empty cache folder * * @api Smarty::clearAllCache() - * @link http://www.smarty.net/docs/en/api.clear.all.cache.tpl + * @link https://www.smarty.net/docs/en/api.clear.all.cache.tpl * * @param \Smarty $smarty * @param integer $exp_time expiration time diff --git a/tools/smarty/sysplugins/smarty_internal_method_clearassign.php b/tools/smarty/sysplugins/smarty_internal_method_clearassign.php index 22bfa2d31..12b755c06 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_clearassign.php +++ b/tools/smarty/sysplugins/smarty_internal_method_clearassign.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_ClearAssign * clear the given assigned template variable(s). * * @api Smarty::clearAssign() - * @link http://www.smarty.net/docs/en/api.clear.assign.tpl + * @link https://www.smarty.net/docs/en/api.clear.assign.tpl * * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty $data * @param string|array $tpl_var the template variable(s) to clear diff --git a/tools/smarty/sysplugins/smarty_internal_method_clearcache.php b/tools/smarty/sysplugins/smarty_internal_method_clearcache.php index a5dd4e26e..df766eee8 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_clearcache.php +++ b/tools/smarty/sysplugins/smarty_internal_method_clearcache.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_ClearCache * Empty cache for a specific template * * @api Smarty::clearCache() - * @link http://www.smarty.net/docs/en/api.clear.cache.tpl + * @link https://www.smarty.net/docs/en/api.clear.cache.tpl * * @param \Smarty $smarty * @param string $template_name template name diff --git a/tools/smarty/sysplugins/smarty_internal_method_clearcompiledtemplate.php b/tools/smarty/sysplugins/smarty_internal_method_clearcompiledtemplate.php index bf4929807..db0a49b00 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_clearcompiledtemplate.php +++ b/tools/smarty/sysplugins/smarty_internal_method_clearcompiledtemplate.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_ClearCompiledTemplate * Delete compiled template file * * @api Smarty::clearCompiledTemplate() - * @link http://www.smarty.net/docs/en/api.clear.compiled.template.tpl + * @link https://www.smarty.net/docs/en/api.clear.compiled.template.tpl * * @param \Smarty $smarty * @param string $resource_name template name diff --git a/tools/smarty/sysplugins/smarty_internal_method_clearconfig.php b/tools/smarty/sysplugins/smarty_internal_method_clearconfig.php index 15bf492a1..d1b730322 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_clearconfig.php +++ b/tools/smarty/sysplugins/smarty_internal_method_clearconfig.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_ClearConfig * clear a single or all config variables * * @api Smarty::clearConfig() - * @link http://www.smarty.net/docs/en/api.clear.config.tpl + * @link https://www.smarty.net/docs/en/api.clear.config.tpl * * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty $data * @param string|null $name variable name or null diff --git a/tools/smarty/sysplugins/smarty_internal_method_configload.php b/tools/smarty/sysplugins/smarty_internal_method_configload.php index 2e6254880..c3174d2d0 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_configload.php +++ b/tools/smarty/sysplugins/smarty_internal_method_configload.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_ConfigLoad * load a config file, optionally load just selected sections * * @api Smarty::configLoad() - * @link http://www.smarty.net/docs/en/api.config.load.tpl + * @link https://www.smarty.net/docs/en/api.config.load.tpl * * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty $data * @param string $config_file filename @@ -42,7 +42,7 @@ class Smarty_Internal_Method_ConfigLoad * load a config file, optionally load just selected sections * * @api Smarty::configLoad() - * @link http://www.smarty.net/docs/en/api.config.load.tpl + * @link https://www.smarty.net/docs/en/api.config.load.tpl * * @param \Smarty|\Smarty_Internal_Data|\Smarty_Internal_Template $data * @param string $config_file filename diff --git a/tools/smarty/sysplugins/smarty_internal_method_createdata.php b/tools/smarty/sysplugins/smarty_internal_method_createdata.php index f95097519..59027203b 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_createdata.php +++ b/tools/smarty/sysplugins/smarty_internal_method_createdata.php @@ -22,16 +22,16 @@ class Smarty_Internal_Method_CreateData * creates a data object * * @api Smarty::createData() - * @link http://www.smarty.net/docs/en/api.create.data.tpl + * @link https://www.smarty.net/docs/en/api.create.data.tpl * - * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj - * @param \Smarty_Internal_Template|\Smarty_Internal_Data|\Smarty_Data|\Smarty $parent next higher level of Smarty - * variables - * @param string $name optional data block name + * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj + * @param \Smarty_Internal_Template|\Smarty_Internal_Data|\Smarty_Data|\Smarty|null $parent next higher level of Smarty + * variables + * @param string $name optional data block name * * @return \Smarty_Data data object */ - public function createData(Smarty_Internal_TemplateBase $obj, Smarty_Internal_Data $parent = null, $name = null) + public function createData(Smarty_Internal_TemplateBase $obj, ?Smarty_Internal_Data $parent = null, $name = null) { /* @var Smarty $smarty */ $smarty = $obj->_getSmartyObj(); diff --git a/tools/smarty/sysplugins/smarty_internal_method_getconfigvars.php b/tools/smarty/sysplugins/smarty_internal_method_getconfigvars.php index 1d11e44c1..763bdf989 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_getconfigvars.php +++ b/tools/smarty/sysplugins/smarty_internal_method_getconfigvars.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_GetConfigVars * Returns a single or all config variables * * @api Smarty::getConfigVars() - * @link http://www.smarty.net/docs/en/api.get.config.vars.tpl + * @link https://www.smarty.net/docs/en/api.get.config.vars.tpl * * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty $data * @param string $varname variable name or null diff --git a/tools/smarty/sysplugins/smarty_internal_method_getregisteredobject.php b/tools/smarty/sysplugins/smarty_internal_method_getregisteredobject.php index df6ede130..0b3a071d3 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_getregisteredobject.php +++ b/tools/smarty/sysplugins/smarty_internal_method_getregisteredobject.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_GetRegisteredObject * return a reference to a registered object * * @api Smarty::getRegisteredObject() - * @link http://www.smarty.net/docs/en/api.get.registered.object.tpl + * @link https://www.smarty.net/docs/en/api.get.registered.object.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param string $object_name object name diff --git a/tools/smarty/sysplugins/smarty_internal_method_gettags.php b/tools/smarty/sysplugins/smarty_internal_method_gettags.php index c07ae07ec..0d1335a8d 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_gettags.php +++ b/tools/smarty/sysplugins/smarty_internal_method_gettags.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_GetTags * Return array of tag/attributes of all tags used by an template * * @api Smarty::getTags() - * @link http://www.smarty.net/docs/en/api.get.tags.tpl + * @link https://www.smarty.net/docs/en/api.get.tags.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param null|string|Smarty_Internal_Template $template diff --git a/tools/smarty/sysplugins/smarty_internal_method_gettemplatevars.php b/tools/smarty/sysplugins/smarty_internal_method_gettemplatevars.php index 9ef7d46bb..bac17f5bf 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_gettemplatevars.php +++ b/tools/smarty/sysplugins/smarty_internal_method_gettemplatevars.php @@ -22,19 +22,19 @@ class Smarty_Internal_Method_GetTemplateVars * Returns a single or all template variables * * @api Smarty::getTemplateVars() - * @link http://www.smarty.net/docs/en/api.get.template.vars.tpl + * @link https://www.smarty.net/docs/en/api.get.template.vars.tpl * - * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty $data - * @param string $varName variable name or null - * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty $_ptr optional pointer to data object - * @param bool $searchParents include parent templates? + * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty $data + * @param string $varName variable name or null + * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty|null $_ptr optional pointer to data object + * @param bool $searchParents include parent templates? * * @return mixed variable value or or array of variables */ public function getTemplateVars( Smarty_Internal_Data $data, $varName = null, - Smarty_Internal_Data $_ptr = null, + ?Smarty_Internal_Data $_ptr = null, $searchParents = true ) { if (isset($varName)) { @@ -87,7 +87,7 @@ class Smarty_Internal_Method_GetTemplateVars public function _getVariable( Smarty_Internal_Data $data, $varName, - Smarty_Internal_Data $_ptr = null, + ?Smarty_Internal_Data $_ptr = null, $searchParents = true, $errorEnable = true ) { diff --git a/tools/smarty/sysplugins/smarty_internal_method_loadfilter.php b/tools/smarty/sysplugins/smarty_internal_method_loadfilter.php index 66d80d474..af788a24e 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_loadfilter.php +++ b/tools/smarty/sysplugins/smarty_internal_method_loadfilter.php @@ -30,7 +30,7 @@ class Smarty_Internal_Method_LoadFilter * * @api Smarty::loadFilter() * - * @link http://www.smarty.net/docs/en/api.load.filter.tpl + * @link https://www.smarty.net/docs/en/api.load.filter.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param string $type filter type diff --git a/tools/smarty/sysplugins/smarty_internal_method_loadplugin.php b/tools/smarty/sysplugins/smarty_internal_method_loadplugin.php index 3bd659cb8..6ddcaec94 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_loadplugin.php +++ b/tools/smarty/sysplugins/smarty_internal_method_loadplugin.php @@ -40,7 +40,7 @@ class Smarty_Internal_Method_LoadPlugin throw new SmartyException("plugin {$plugin_name} is not a valid name format"); } if (!empty($match[ 2 ])) { - $file = SMARTY_SYSPLUGINS_DIR . strtolower($plugin_name) . '.php'; + $file = SMARTY_SYSPLUGINS_DIR . smarty_strtolower_ascii($plugin_name) . '.php'; if (isset($this->plugin_files[ $file ])) { if ($this->plugin_files[ $file ] !== false) { return $this->plugin_files[ $file ]; @@ -60,7 +60,7 @@ class Smarty_Internal_Method_LoadPlugin } // plugin filename is expected to be: [type].[name].php $_plugin_filename = "{$match[1]}.{$match[4]}.php"; - $_lower_filename = strtolower($_plugin_filename); + $_lower_filename = smarty_strtolower_ascii($_plugin_filename); if (isset($this->plugin_files)) { if (isset($this->plugin_files[ 'plugins_dir' ][ $_lower_filename ])) { if (!$smarty->use_include_path || $this->plugin_files[ 'plugins_dir' ][ $_lower_filename ] !== false) { diff --git a/tools/smarty/sysplugins/smarty_internal_method_mustcompile.php b/tools/smarty/sysplugins/smarty_internal_method_mustcompile.php index 39318838e..381346c8f 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_mustcompile.php +++ b/tools/smarty/sysplugins/smarty_internal_method_mustcompile.php @@ -32,7 +32,7 @@ class Smarty_Internal_Method_MustCompile { if (!$_template->source->exists) { if ($_template->_isSubTpl()) { - $parent_resource = " in '$_template->parent->template_resource}'"; + $parent_resource = " in '{$_template->parent->template_resource}'"; } else { $parent_resource = ''; } diff --git a/tools/smarty/sysplugins/smarty_internal_method_registercacheresource.php b/tools/smarty/sysplugins/smarty_internal_method_registercacheresource.php index 648365619..5608b3fd0 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_registercacheresource.php +++ b/tools/smarty/sysplugins/smarty_internal_method_registercacheresource.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_RegisterCacheResource * Registers a resource to fetch a template * * @api Smarty::registerCacheResource() - * @link http://www.smarty.net/docs/en/api.register.cacheresource.tpl + * @link https://www.smarty.net/docs/en/api.register.cacheresource.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param string $name name of resource type diff --git a/tools/smarty/sysplugins/smarty_internal_method_registerclass.php b/tools/smarty/sysplugins/smarty_internal_method_registerclass.php index 8d18547e2..76a69c6e5 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_registerclass.php +++ b/tools/smarty/sysplugins/smarty_internal_method_registerclass.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_RegisterClass * Registers static classes to be used in templates * * @api Smarty::registerClass() - * @link http://www.smarty.net/docs/en/api.register.class.tpl + * @link https://www.smarty.net/docs/en/api.register.class.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param string $class_name diff --git a/tools/smarty/sysplugins/smarty_internal_method_registerdefaultpluginhandler.php b/tools/smarty/sysplugins/smarty_internal_method_registerdefaultpluginhandler.php index a9fb78dc6..4cda5b056 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_registerdefaultpluginhandler.php +++ b/tools/smarty/sysplugins/smarty_internal_method_registerdefaultpluginhandler.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_RegisterDefaultPluginHandler * Registers a default plugin handler * * @api Smarty::registerDefaultPluginHandler() - * @link http://www.smarty.net/docs/en/api.register.default.plugin.handler.tpl + * @link https://www.smarty.net/docs/en/api.register.default.plugin.handler.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param callable $callback class/method name diff --git a/tools/smarty/sysplugins/smarty_internal_method_registerfilter.php b/tools/smarty/sysplugins/smarty_internal_method_registerfilter.php index c0f9fff10..9719eb2b6 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_registerfilter.php +++ b/tools/smarty/sysplugins/smarty_internal_method_registerfilter.php @@ -30,7 +30,7 @@ class Smarty_Internal_Method_RegisterFilter * * @api Smarty::registerFilter() * - * @link http://www.smarty.net/docs/en/api.register.filter.tpl + * @link https://www.smarty.net/docs/en/api.register.filter.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param string $type filter type diff --git a/tools/smarty/sysplugins/smarty_internal_method_registerobject.php b/tools/smarty/sysplugins/smarty_internal_method_registerobject.php index 4646e4f22..8e6fe0521 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_registerobject.php +++ b/tools/smarty/sysplugins/smarty_internal_method_registerobject.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_RegisterObject * Registers object to be used in templates * * @api Smarty::registerObject() - * @link http://www.smarty.net/docs/en/api.register.object.tpl + * @link https://www.smarty.net/docs/en/api.register.object.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param string $object_name diff --git a/tools/smarty/sysplugins/smarty_internal_method_registerplugin.php b/tools/smarty/sysplugins/smarty_internal_method_registerplugin.php index ed18d84bb..74c0ae908 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_registerplugin.php +++ b/tools/smarty/sysplugins/smarty_internal_method_registerplugin.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_RegisterPlugin * Registers plugin to be used in templates * * @api Smarty::registerPlugin() - * @link http://www.smarty.net/docs/en/api.register.plugin.tpl + * @link https://www.smarty.net/docs/en/api.register.plugin.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param string $type plugin type diff --git a/tools/smarty/sysplugins/smarty_internal_method_registerresource.php b/tools/smarty/sysplugins/smarty_internal_method_registerresource.php index 7c7d0f78a..302657ae0 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_registerresource.php +++ b/tools/smarty/sysplugins/smarty_internal_method_registerresource.php @@ -22,25 +22,18 @@ class Smarty_Internal_Method_RegisterResource * Registers a resource to fetch a template * * @api Smarty::registerResource() - * @link http://www.smarty.net/docs/en/api.register.resource.tpl + * @link https://www.smarty.net/docs/en/api.register.resource.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param string $name name of resource type - * @param Smarty_Resource|array $resource_handler or instance of - * Smarty_Resource, - * or array of - * callbacks to - * handle - * resource - * (deprecated) + * @param Smarty_Resource $resource_handler instance of Smarty_Resource * * @return \Smarty|\Smarty_Internal_Template */ - public function registerResource(Smarty_Internal_TemplateBase $obj, $name, $resource_handler) + public function registerResource(Smarty_Internal_TemplateBase $obj, $name, Smarty_Resource $resource_handler) { $smarty = $obj->_getSmartyObj(); - $smarty->registered_resources[ $name ] = - $resource_handler instanceof Smarty_Resource ? $resource_handler : array($resource_handler, false); + $smarty->registered_resources[ $name ] = $resource_handler; return $obj; } } diff --git a/tools/smarty/sysplugins/smarty_internal_method_unloadfilter.php b/tools/smarty/sysplugins/smarty_internal_method_unloadfilter.php index 55e1596be..e41e8dffc 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_unloadfilter.php +++ b/tools/smarty/sysplugins/smarty_internal_method_unloadfilter.php @@ -16,7 +16,7 @@ class Smarty_Internal_Method_UnloadFilter extends Smarty_Internal_Method_LoadFil * * @api Smarty::unloadFilter() * - * @link http://www.smarty.net/docs/en/api.unload.filter.tpl + * @link https://www.smarty.net/docs/en/api.unload.filter.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param string $type filter type diff --git a/tools/smarty/sysplugins/smarty_internal_method_unregistercacheresource.php b/tools/smarty/sysplugins/smarty_internal_method_unregistercacheresource.php index b99903867..377397e97 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_unregistercacheresource.php +++ b/tools/smarty/sysplugins/smarty_internal_method_unregistercacheresource.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_UnregisterCacheResource * Registers a resource to fetch a template * * @api Smarty::unregisterCacheResource() - * @link http://www.smarty.net/docs/en/api.unregister.cacheresource.tpl + * @link https://www.smarty.net/docs/en/api.unregister.cacheresource.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param $name diff --git a/tools/smarty/sysplugins/smarty_internal_method_unregisterfilter.php b/tools/smarty/sysplugins/smarty_internal_method_unregisterfilter.php index 9cb494a52..ebc9337d0 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_unregisterfilter.php +++ b/tools/smarty/sysplugins/smarty_internal_method_unregisterfilter.php @@ -16,7 +16,7 @@ class Smarty_Internal_Method_UnregisterFilter extends Smarty_Internal_Method_Reg * * @api Smarty::unregisterFilter() * - * @link http://www.smarty.net/docs/en/api.unregister.filter.tpl + * @link https://www.smarty.net/docs/en/api.unregister.filter.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param string $type filter type diff --git a/tools/smarty/sysplugins/smarty_internal_method_unregisterobject.php b/tools/smarty/sysplugins/smarty_internal_method_unregisterobject.php index 1e592b339..77d619637 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_unregisterobject.php +++ b/tools/smarty/sysplugins/smarty_internal_method_unregisterobject.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_UnregisterObject * Registers plugin to be used in templates * * @api Smarty::unregisterObject() - * @link http://www.smarty.net/docs/en/api.unregister.object.tpl + * @link https://www.smarty.net/docs/en/api.unregister.object.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param string $object_name name of object diff --git a/tools/smarty/sysplugins/smarty_internal_method_unregisterplugin.php b/tools/smarty/sysplugins/smarty_internal_method_unregisterplugin.php index f39e31678..2431d5c23 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_unregisterplugin.php +++ b/tools/smarty/sysplugins/smarty_internal_method_unregisterplugin.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_UnregisterPlugin * Registers plugin to be used in templates * * @api Smarty::unregisterPlugin() - * @link http://www.smarty.net/docs/en/api.unregister.plugin.tpl + * @link https://www.smarty.net/docs/en/api.unregister.plugin.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param string $type plugin type diff --git a/tools/smarty/sysplugins/smarty_internal_method_unregisterresource.php b/tools/smarty/sysplugins/smarty_internal_method_unregisterresource.php index a79db4299..bbb6a861d 100644 --- a/tools/smarty/sysplugins/smarty_internal_method_unregisterresource.php +++ b/tools/smarty/sysplugins/smarty_internal_method_unregisterresource.php @@ -22,7 +22,7 @@ class Smarty_Internal_Method_UnregisterResource * Registers a resource to fetch a template * * @api Smarty::unregisterResource() - * @link http://www.smarty.net/docs/en/api.unregister.resource.tpl + * @link https://www.smarty.net/docs/en/api.unregister.resource.tpl * * @param \Smarty_Internal_TemplateBase|\Smarty_Internal_Template|\Smarty $obj * @param string $type name of resource type diff --git a/tools/smarty/sysplugins/smarty_internal_parsetree_template.php b/tools/smarty/sysplugins/smarty_internal_parsetree_template.php index ab4c3ec3b..829c420fe 100644 --- a/tools/smarty/sysplugins/smarty_internal_parsetree_template.php +++ b/tools/smarty/sysplugins/smarty_internal_parsetree_template.php @@ -87,83 +87,83 @@ class Smarty_Internal_ParseTree_Template extends Smarty_Internal_ParseTree $code = ''; foreach ($this->getChunkedSubtrees() as $chunk) { - $text = ''; - switch ($chunk['mode']) { - case 'textstripped': - foreach ($chunk['subtrees'] as $subtree) { - $text .= $subtree->to_smarty_php($parser); - } - $code .= preg_replace( - '/((<%)|(%>)|(<\?php)|(<\?)|(\?>)|(<\/?script))/', - "\n", - $parser->compiler->processText($text) - ); - break; - case 'text': - foreach ($chunk['subtrees'] as $subtree) { - $text .= $subtree->to_smarty_php($parser); - } - $code .= preg_replace( - '/((<%)|(%>)|(<\?php)|(<\?)|(\?>)|(<\/?script))/', - "\n", - $text - ); - break; - case 'tag': - foreach ($chunk['subtrees'] as $subtree) { - $text = $parser->compiler->appendCode($text, $subtree->to_smarty_php($parser)); - } - $code .= $text; - break; - default: - foreach ($chunk['subtrees'] as $subtree) { - $text = $subtree->to_smarty_php($parser); - } - $code .= $text; + $text = ''; + switch ($chunk['mode']) { + case 'textstripped': + foreach ($chunk['subtrees'] as $subtree) { + $text .= $subtree->to_smarty_php($parser); + } + $code .= preg_replace( + '/((<%)|(%>)|(<\?php)|(<\?)|(\?>)|(<\/?script))/', + "\n", + $parser->compiler->processText($text) + ); + break; + case 'text': + foreach ($chunk['subtrees'] as $subtree) { + $text .= $subtree->to_smarty_php($parser); + } + $code .= preg_replace( + '/((<%)|(%>)|(<\?php)|(<\?)|(\?>)|(<\/?script))/', + "\n", + $text + ); + break; + case 'tag': + foreach ($chunk['subtrees'] as $subtree) { + $text = $parser->compiler->appendCode($text, $subtree->to_smarty_php($parser)); + } + $code .= $text; + break; + default: + foreach ($chunk['subtrees'] as $subtree) { + $text = $subtree->to_smarty_php($parser); + } + $code .= $text; - } + } } return $code; } private function getChunkedSubtrees() { - $chunks = array(); - $currentMode = null; - $currentChunk = array(); - for ($key = 0, $cnt = count($this->subtrees); $key < $cnt; $key++) { + $chunks = array(); + $currentMode = null; + $currentChunk = array(); + for ($key = 0, $cnt = count($this->subtrees); $key < $cnt; $key++) { - if ($this->subtrees[ $key ]->data === '' && in_array($currentMode, array('textstripped', 'text', 'tag'))) { - continue; - } + if ($this->subtrees[ $key ]->data === '' && in_array($currentMode, array('textstripped', 'text', 'tag'))) { + continue; + } - if ($this->subtrees[ $key ] instanceof Smarty_Internal_ParseTree_Text - && $this->subtrees[ $key ]->isToBeStripped()) { - $newMode = 'textstripped'; - } elseif ($this->subtrees[ $key ] instanceof Smarty_Internal_ParseTree_Text) { - $newMode = 'text'; - } elseif ($this->subtrees[ $key ] instanceof Smarty_Internal_ParseTree_Tag) { - $newMode = 'tag'; - } else { - $newMode = 'other'; - } + if ($this->subtrees[ $key ] instanceof Smarty_Internal_ParseTree_Text + && $this->subtrees[ $key ]->isToBeStripped()) { + $newMode = 'textstripped'; + } elseif ($this->subtrees[ $key ] instanceof Smarty_Internal_ParseTree_Text) { + $newMode = 'text'; + } elseif ($this->subtrees[ $key ] instanceof Smarty_Internal_ParseTree_Tag) { + $newMode = 'tag'; + } else { + $newMode = 'other'; + } - if ($newMode == $currentMode) { - $currentChunk[] = $this->subtrees[ $key ]; - } else { - $chunks[] = array( - 'mode' => $currentMode, - 'subtrees' => $currentChunk - ); - $currentMode = $newMode; - $currentChunk = array($this->subtrees[ $key ]); - } - } - if ($currentMode && $currentChunk) { - $chunks[] = array( - 'mode' => $currentMode, - 'subtrees' => $currentChunk - ); - } - return $chunks; + if ($newMode == $currentMode) { + $currentChunk[] = $this->subtrees[ $key ]; + } else { + $chunks[] = array( + 'mode' => $currentMode, + 'subtrees' => $currentChunk + ); + $currentMode = $newMode; + $currentChunk = array($this->subtrees[ $key ]); + } + } + if ($currentMode && $currentChunk) { + $chunks[] = array( + 'mode' => $currentMode, + 'subtrees' => $currentChunk + ); + } + return $chunks; } } diff --git a/tools/smarty/sysplugins/smarty_internal_parsetree_text.php b/tools/smarty/sysplugins/smarty_internal_parsetree_text.php index 399e84941..58116c811 100644 --- a/tools/smarty/sysplugins/smarty_internal_parsetree_text.php +++ b/tools/smarty/sysplugins/smarty_internal_parsetree_text.php @@ -17,30 +17,30 @@ class Smarty_Internal_ParseTree_Text extends Smarty_Internal_ParseTree { - /** - * Wether this section should be stripped on output to smarty php - * @var bool - */ - private $toBeStripped = false; + /** + * Wether this section should be stripped on output to smarty php + * @var bool + */ + private $toBeStripped = false; - /** - * Create template text buffer - * - * @param string $data text - * @param bool $toBeStripped wether this section should be stripped on output to smarty php - */ + /** + * Create template text buffer + * + * @param string $data text + * @param bool $toBeStripped wether this section should be stripped on output to smarty php + */ public function __construct($data, $toBeStripped = false) { $this->data = $data; $this->toBeStripped = $toBeStripped; } - /** - * Wether this section should be stripped on output to smarty php - * @return bool - */ - public function isToBeStripped() { - return $this->toBeStripped; + /** + * Wether this section should be stripped on output to smarty php + * @return bool + */ + public function isToBeStripped() { + return $this->toBeStripped; } /** diff --git a/tools/smarty/sysplugins/smarty_internal_resource_eval.php b/tools/smarty/sysplugins/smarty_internal_resource_eval.php index 3b552a589..ba306444e 100644 --- a/tools/smarty/sysplugins/smarty_internal_resource_eval.php +++ b/tools/smarty/sysplugins/smarty_internal_resource_eval.php @@ -22,11 +22,11 @@ class Smarty_Internal_Resource_Eval extends Smarty_Resource_Recompiled * populate Source Object with meta data from Resource * * @param Smarty_Template_Source $source source object - * @param Smarty_Internal_Template $_template template object + * @param Smarty_Internal_Template|null $_template template object * * @return void */ - public function populate(Smarty_Template_Source $source, Smarty_Internal_Template $_template = null) + public function populate(Smarty_Template_Source $source, ?Smarty_Internal_Template $_template = null) { $source->uid = $source->filepath = sha1($source->name); $source->timestamp = $source->exists = true; diff --git a/tools/smarty/sysplugins/smarty_internal_resource_extends.php b/tools/smarty/sysplugins/smarty_internal_resource_extends.php index 80946932e..2b2253246 100644 --- a/tools/smarty/sysplugins/smarty_internal_resource_extends.php +++ b/tools/smarty/sysplugins/smarty_internal_resource_extends.php @@ -28,11 +28,11 @@ class Smarty_Internal_Resource_Extends extends Smarty_Resource * populate Source Object with meta data from Resource * * @param Smarty_Template_Source $source source object - * @param Smarty_Internal_Template $_template template object + * @param Smarty_Internal_Template|null $_template template object * * @throws SmartyException */ - public function populate(Smarty_Template_Source $source, Smarty_Internal_Template $_template = null) + public function populate(Smarty_Template_Source $source, ?Smarty_Internal_Template $_template = null) { $uid = ''; $sources = array(); diff --git a/tools/smarty/sysplugins/smarty_internal_resource_file.php b/tools/smarty/sysplugins/smarty_internal_resource_file.php index ae2060673..fd0befd53 100644 --- a/tools/smarty/sysplugins/smarty_internal_resource_file.php +++ b/tools/smarty/sysplugins/smarty_internal_resource_file.php @@ -21,11 +21,11 @@ class Smarty_Internal_Resource_File extends Smarty_Resource * populate Source Object with meta data from Resource * * @param Smarty_Template_Source $source source object - * @param Smarty_Internal_Template $_template template object + * @param Smarty_Internal_Template|null $_template template object * * @throws \SmartyException */ - public function populate(Smarty_Template_Source $source, Smarty_Internal_Template $_template = null) + public function populate(Smarty_Template_Source $source, ?Smarty_Internal_Template $_template = null) { $source->filepath = $this->buildFilepath($source, $_template); if ($source->filepath !== false) { @@ -93,12 +93,12 @@ class Smarty_Internal_Resource_File extends Smarty_Resource * build template filepath by traversing the template_dir array * * @param Smarty_Template_Source $source source object - * @param Smarty_Internal_Template $_template template object + * @param Smarty_Internal_Template|null $_template template object * * @return string fully qualified filepath * @throws SmartyException */ - protected function buildFilepath(Smarty_Template_Source $source, Smarty_Internal_Template $_template = null) + protected function buildFilepath(Smarty_Template_Source $source, ?Smarty_Internal_Template $_template = null) { $file = $source->name; // absolute file ? diff --git a/tools/smarty/sysplugins/smarty_internal_resource_registered.php b/tools/smarty/sysplugins/smarty_internal_resource_registered.php deleted file mode 100644 index df526101f..000000000 --- a/tools/smarty/sysplugins/smarty_internal_resource_registered.php +++ /dev/null @@ -1,101 +0,0 @@ -filepath = $source->type . ':' . $source->name; - $source->uid = sha1($source->filepath . $source->smarty->_joined_template_dir); - $source->timestamp = $this->getTemplateTimestamp($source); - $source->exists = !!$source->timestamp; - } - - /** - * populate Source Object with timestamp and exists from Resource - * - * @param Smarty_Template_Source $source source object - * - * @return void - */ - public function populateTimestamp(Smarty_Template_Source $source) - { - $source->timestamp = $this->getTemplateTimestamp($source); - $source->exists = !!$source->timestamp; - } - - /** - * Get timestamp (epoch) the template source was modified - * - * @param Smarty_Template_Source $source source object - * - * @return integer|boolean timestamp (epoch) the template was modified, false if resources has no timestamp - */ - public function getTemplateTimestamp(Smarty_Template_Source $source) - { - // return timestamp - $time_stamp = false; - call_user_func_array( - $source->smarty->registered_resources[ $source->type ][ 0 ][ 1 ], - array($source->name, &$time_stamp, $source->smarty) - ); - return is_numeric($time_stamp) ? (int)$time_stamp : $time_stamp; - } - - /** - * Load template's source by invoking the registered callback into current template object - * - * @param Smarty_Template_Source $source source object - * - * @return string template source - * @throws SmartyException if source cannot be loaded - */ - public function getContent(Smarty_Template_Source $source) - { - // return template string - $content = null; - $t = call_user_func_array( - $source->smarty->registered_resources[ $source->type ][ 0 ][ 0 ], - array($source->name, &$content, $source->smarty) - ); - if (is_bool($t) && !$t) { - throw new SmartyException("Unable to read template {$source->type} '{$source->name}'"); - } - return $content; - } - - /** - * Determine basename for compiled filename - * - * @param Smarty_Template_Source $source source object - * - * @return string resource's basename - */ - public function getBasename(Smarty_Template_Source $source) - { - return basename($source->name); - } -} diff --git a/tools/smarty/sysplugins/smarty_internal_resource_stream.php b/tools/smarty/sysplugins/smarty_internal_resource_stream.php index 9956bd073..632e58f42 100644 --- a/tools/smarty/sysplugins/smarty_internal_resource_stream.php +++ b/tools/smarty/sysplugins/smarty_internal_resource_stream.php @@ -13,7 +13,7 @@ * Smarty Internal Plugin Resource Stream * Implements the streams as resource for Smarty template * - * @link http://php.net/streams + * @link https://php.net/streams * @package Smarty * @subpackage TemplateResources */ @@ -23,11 +23,11 @@ class Smarty_Internal_Resource_Stream extends Smarty_Resource_Recompiled * populate Source Object with meta data from Resource * * @param Smarty_Template_Source $source source object - * @param Smarty_Internal_Template $_template template object + * @param Smarty_Internal_Template|null $_template template object * * @return void */ - public function populate(Smarty_Template_Source $source, Smarty_Internal_Template $_template = null) + public function populate(Smarty_Template_Source $source, ?Smarty_Internal_Template $_template = null) { if (strpos($source->resource, '://') !== false) { $source->filepath = $source->resource; diff --git a/tools/smarty/sysplugins/smarty_internal_resource_string.php b/tools/smarty/sysplugins/smarty_internal_resource_string.php index 3fecbb7ef..7b69faa9a 100644 --- a/tools/smarty/sysplugins/smarty_internal_resource_string.php +++ b/tools/smarty/sysplugins/smarty_internal_resource_string.php @@ -22,11 +22,11 @@ class Smarty_Internal_Resource_String extends Smarty_Resource * populate Source Object with meta data from Resource * * @param Smarty_Template_Source $source source object - * @param Smarty_Internal_Template $_template template object + * @param Smarty_Internal_Template|null $_template template object * * @return void */ - public function populate(Smarty_Template_Source $source, Smarty_Internal_Template $_template = null) + public function populate(Smarty_Template_Source $source, ?Smarty_Internal_Template $_template = null) { $source->uid = $source->filepath = sha1($source->name . $source->smarty->_joined_template_dir); $source->timestamp = $source->exists = true; diff --git a/tools/smarty/sysplugins/smarty_internal_runtime_codeframe.php b/tools/smarty/sysplugins/smarty_internal_runtime_codeframe.php index 983ca6180..37a881092 100644 --- a/tools/smarty/sysplugins/smarty_internal_runtime_codeframe.php +++ b/tools/smarty/sysplugins/smarty_internal_runtime_codeframe.php @@ -17,11 +17,11 @@ class Smarty_Internal_Runtime_CodeFrame /** * Create code frame for compiled and cached templates * - * @param Smarty_Internal_Template $_template - * @param string $content optional template content - * @param string $functions compiled template function and block code - * @param bool $cache flag for cache file - * @param \Smarty_Internal_TemplateCompilerBase $compiler + * @param Smarty_Internal_Template $_template + * @param string $content optional template content + * @param string $functions compiled template function and block code + * @param bool $cache flag for cache file + * @param \Smarty_Internal_TemplateCompilerBase|null $compiler * * @return string */ @@ -30,7 +30,7 @@ class Smarty_Internal_Runtime_CodeFrame $content = '', $functions = '', $cache = false, - Smarty_Internal_TemplateCompilerBase $compiler = null + ?Smarty_Internal_TemplateCompilerBase $compiler = null ) { // build property code $properties[ 'version' ] = Smarty::SMARTY_VERSION; @@ -44,9 +44,12 @@ class Smarty_Internal_Runtime_CodeFrame $properties[ 'file_dependency' ] = $_template->cached->file_dependency; $properties[ 'cache_lifetime' ] = $_template->cache_lifetime; } - $output = "source->filepath) . "' */\n\n"; + $output = sprintf( + "source->filepath) + ); $output .= "/* @var Smarty_Internal_Template \$_smarty_tpl */\n"; $dec = "\$_smarty_tpl->_decodeProperties(\$_smarty_tpl, " . var_export($properties, true) . ',' . ($cache ? 'true' : 'false') . ')'; diff --git a/tools/smarty/sysplugins/smarty_internal_runtime_inheritance.php b/tools/smarty/sysplugins/smarty_internal_runtime_inheritance.php index 8f7f02d59..52faf5a4e 100644 --- a/tools/smarty/sysplugins/smarty_internal_runtime_inheritance.php +++ b/tools/smarty/sysplugins/smarty_internal_runtime_inheritance.php @@ -168,7 +168,7 @@ class Smarty_Internal_Runtime_Inheritance public function process( Smarty_Internal_Template $tpl, Smarty_Internal_Block $block, - Smarty_Internal_Block $parent = null + ?Smarty_Internal_Block $parent = null ) { if ($block->hide && !isset($block->child)) { return; diff --git a/tools/smarty/sysplugins/smarty_internal_runtime_make_nocache.php b/tools/smarty/sysplugins/smarty_internal_runtime_make_nocache.php index 53069148d..7994aa048 100644 --- a/tools/smarty/sysplugins/smarty_internal_runtime_make_nocache.php +++ b/tools/smarty/sysplugins/smarty_internal_runtime_make_nocache.php @@ -22,7 +22,7 @@ class Smarty_Internal_Runtime_Make_Nocache { if (isset($tpl->tpl_vars[ $var ])) { $export = - preg_replace('/^Smarty_Variable::__set_state[(]|[)]$/', '', var_export($tpl->tpl_vars[ $var ], true)); + preg_replace('/^\\\\?Smarty_Variable::__set_state[(]|[)]$/', '', var_export($tpl->tpl_vars[ $var ], true)); if (preg_match('/(\w+)::__set_state/', $export, $match)) { throw new SmartyException("{make_nocache \${$var}} in template '{$tpl->source->name}': variable does contain object '{$match[1]}' not implementing method '__set_state'"); } diff --git a/tools/smarty/sysplugins/smarty_internal_runtime_writefile.php b/tools/smarty/sysplugins/smarty_internal_runtime_writefile.php index 4383e6f38..492d5eb25 100644 --- a/tools/smarty/sysplugins/smarty_internal_runtime_writefile.php +++ b/tools/smarty/sysplugins/smarty_internal_runtime_writefile.php @@ -29,12 +29,6 @@ class Smarty_Internal_Runtime_WriteFile { $_error_reporting = error_reporting(); error_reporting($_error_reporting & ~E_NOTICE & ~E_WARNING); - $_file_perms = property_exists($smarty, '_file_perms') ? $smarty->_file_perms : 0644; - $_dir_perms = - property_exists($smarty, '_dir_perms') ? (isset($smarty->_dir_perms) ? $smarty->_dir_perms : 0777) : 0771; - if ($_file_perms !== null) { - $old_umask = umask(0); - } $_dirpath = dirname($_filepath); // if subdirs, create dir structure if ($_dirpath !== '.') { @@ -42,7 +36,7 @@ class Smarty_Internal_Runtime_WriteFile // loop if concurrency problem occurs // see https://bugs.php.net/bug.php?id=35326 while (!is_dir($_dirpath)) { - if (@mkdir($_dirpath, $_dir_perms, true)) { + if (@mkdir($_dirpath, 0777, true)) { break; } clearstatcache(); @@ -89,11 +83,8 @@ class Smarty_Internal_Runtime_WriteFile error_reporting($_error_reporting); throw new SmartyException("unable to write file {$_filepath}"); } - if ($_file_perms !== null) { - // set file permissions - chmod($_filepath, $_file_perms); - umask($old_umask); - } + // set file permissions + @chmod($_filepath, 0666 & ~umask()); error_reporting($_error_reporting); return true; } diff --git a/tools/smarty/sysplugins/smarty_internal_template.php b/tools/smarty/sysplugins/smarty_internal_template.php index bae22a7d5..93731a5d1 100644 --- a/tools/smarty/sysplugins/smarty_internal_template.php +++ b/tools/smarty/sysplugins/smarty_internal_template.php @@ -24,6 +24,7 @@ * * @method bool mustCompile() */ +#[\AllowDynamicProperties] class Smarty_Internal_Template extends Smarty_Internal_TemplateBase { /** @@ -148,7 +149,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase public function __construct( $template_resource, Smarty $smarty, - Smarty_Internal_Data $_parent = null, + ?Smarty_Internal_Data $_parent = null, $_cache_id = null, $_compile_id = null, $_caching = null, @@ -292,7 +293,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase $smarty = &$this->smarty; $_templateId = $smarty->_getTemplateId($template, $cache_id, $compile_id, $caching, $tpl); // recursive call ? - if (isset($tpl->templateId) ? $tpl->templateId : $tpl->_getTemplateId() !== $_templateId) { + if ((isset($tpl->templateId) ? $tpl->templateId : $tpl->_getTemplateId()) !== $_templateId) { // already in template cache? if (isset(self::$tplObjCache[ $_templateId ])) { // copy data from cached object @@ -358,7 +359,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase } if ($tpl->caching === 9999) { if (!isset($tpl->compiled)) { - $this->loadCompiled(true); + $tpl->loadCompiled(true); } if ($tpl->compiled->has_nocache_code) { $this->cached->hashes[ $tpl->compiled->nocache_hash ] = true; diff --git a/tools/smarty/sysplugins/smarty_internal_templatebase.php b/tools/smarty/sysplugins/smarty_internal_templatebase.php index 200c11bb5..918362e91 100644 --- a/tools/smarty/sysplugins/smarty_internal_templatebase.php +++ b/tools/smarty/sysplugins/smarty_internal_templatebase.php @@ -138,7 +138,7 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data * test if cache is valid * * @api Smarty::isCached() - * @link http://www.smarty.net/docs/en/api.is.cached.tpl + * @link https://www.smarty.net/docs/en/api.is.cached.tpl * * @param null|string|\Smarty_Internal_Template $template the resource handle of the template file or template * object @@ -199,6 +199,12 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data try { $_smarty_old_error_level = isset($smarty->error_reporting) ? error_reporting($smarty->error_reporting) : null; + + if ($smarty->isMutingUndefinedOrNullWarnings()) { + $errorHandler = new Smarty_Internal_ErrorHandler(); + $errorHandler->activate(); + } + if ($this->_objType === 2) { /* @var Smarty_Internal_Template $this */ $template->tplFunctions = $this->tplFunctions; @@ -242,14 +248,23 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data } } } + + if (isset($errorHandler)) { + $errorHandler->deactivate(); + } + if (isset($_smarty_old_error_level)) { error_reporting($_smarty_old_error_level); } return $result; - } catch (Exception $e) { + } catch (Throwable $e) { while (ob_get_level() > $level) { ob_end_clean(); } + if (isset($errorHandler)) { + $errorHandler->deactivate(); + } + if (isset($_smarty_old_error_level)) { error_reporting($_smarty_old_error_level); } @@ -261,7 +276,7 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data * Registers plugin to be used in templates * * @api Smarty::registerPlugin() - * @link http://www.smarty.net/docs/en/api.register.plugin.tpl + * @link https://www.smarty.net/docs/en/api.register.plugin.tpl * * @param string $type plugin type * @param string $name name of template tag @@ -281,7 +296,7 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data * load a filter of specified type and name * * @api Smarty::loadFilter() - * @link http://www.smarty.net/docs/en/api.load.filter.tpl + * @link https://www.smarty.net/docs/en/api.load.filter.tpl * * @param string $type filter type * @param string $name filter name @@ -298,7 +313,7 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data * Registers a filter function * * @api Smarty::registerFilter() - * @link http://www.smarty.net/docs/en/api.register.filter.tpl + * @link https://www.smarty.net/docs/en/api.register.filter.tpl * * @param string $type filter type * @param callable $callback @@ -316,7 +331,7 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data * Registers object to be used in templates * * @api Smarty::registerObject() - * @link http://www.smarty.net/docs/en/api.register.object.tpl + * @link https://www.smarty.net/docs/en/api.register.object.tpl * * @param string $object_name * @param object $object the referenced PHP object to register diff --git a/tools/smarty/sysplugins/smarty_internal_templatecompilerbase.php b/tools/smarty/sysplugins/smarty_internal_templatecompilerbase.php index 3cc957dec..d8415bfaf 100644 --- a/tools/smarty/sysplugins/smarty_internal_templatecompilerbase.php +++ b/tools/smarty/sysplugins/smarty_internal_templatecompilerbase.php @@ -203,13 +203,6 @@ abstract class Smarty_Internal_TemplateCompilerBase */ public $blockOrFunctionCode = ''; - /** - * php_handling setting either from Smarty or security - * - * @var int - */ - public $php_handling = 0; - /** * flags for used modifier plugins * @@ -393,7 +386,7 @@ abstract class Smarty_Internal_TemplateCompilerBase public function compileTemplate( Smarty_Internal_Template $template, $nocache = null, - Smarty_Internal_TemplateCompilerBase $parent_compiler = null + ?Smarty_Internal_TemplateCompilerBase $parent_compiler = null ) { // get code frame of compiled template $_compiled_code = $template->smarty->ext->_codeFrame->create( @@ -414,9 +407,9 @@ abstract class Smarty_Internal_TemplateCompilerBase /** * Compile template source and run optional post filter * - * @param \Smarty_Internal_Template $template - * @param null|bool $nocache flag if template must be compiled in nocache mode - * @param \Smarty_Internal_TemplateCompilerBase $parent_compiler + * @param \Smarty_Internal_Template $template + * @param null|bool $nocache flag if template must be compiled in nocache mode + * @param \Smarty_Internal_TemplateCompilerBase|null $parent_compiler * * @return string * @throws \Exception @@ -424,25 +417,17 @@ abstract class Smarty_Internal_TemplateCompilerBase public function compileTemplateSource( Smarty_Internal_Template $template, $nocache = null, - Smarty_Internal_TemplateCompilerBase $parent_compiler = null + ?Smarty_Internal_TemplateCompilerBase $parent_compiler = null ) { try { // save template object in compiler class $this->template = $template; - if (property_exists($this->template->smarty, 'plugin_search_order')) { - $this->plugin_search_order = $this->template->smarty->plugin_search_order; - } if ($this->smarty->debugging) { if (!isset($this->smarty->_debug)) { $this->smarty->_debug = new Smarty_Internal_Debug(); } $this->smarty->_debug->start_compile($this->template); } - if (isset($this->template->smarty->security_policy)) { - $this->php_handling = $this->template->smarty->security_policy->php_handling; - } else { - $this->php_handling = $this->template->smarty->php_handling; - } $this->parent_compiler = $parent_compiler ? $parent_compiler : $this; $nocache = isset($nocache) ? $nocache : false; if (empty($template->compiled->nocache_hash)) { @@ -470,15 +455,29 @@ abstract class Smarty_Internal_TemplateCompilerBase $this->smarty->_current_file = $this->template->source->filepath; // get template source if (!empty($this->template->source->components)) { - // we have array of inheritance templates by extends: resource - // generate corresponding source code sequence - $_content = - Smarty_Internal_Compile_Extends::extendsSourceArrayCode($this->template); + $_compiled_code = '_loadInheritance(); $_smarty_tpl->inheritance->init($_smarty_tpl, true); ?>'; + + $i = 0; + $reversed_components = array_reverse($this->template->getSource()->components); + foreach ($reversed_components as $source) { + $i++; + if ($i === count($reversed_components)) { + $_compiled_code .= 'inheritance->endChild($_smarty_tpl); ?>'; + } + $_compiled_code .= $this->compileTag( + 'include', + [ + var_export($source->resource, true), + ['scope' => 'parent'], + ] + ); + } + $_compiled_code = $this->postFilter($_compiled_code, $this->template); } else { // get template source $_content = $this->template->source->getContent(); + $_compiled_code = $this->postFilter($this->doCompile($this->preFilter($_content), true)); } - $_compiled_code = $this->postFilter($this->doCompile($this->preFilter($_content), true)); if (!empty($this->required_plugins[ 'compiled' ]) || !empty($this->required_plugins[ 'nocache' ])) { $_compiled_code = 'compileRequiredPlugins() . "?>\n" . $_compiled_code; } @@ -620,18 +619,18 @@ abstract class Smarty_Internal_TemplateCompilerBase if (strcasecmp($name, 'isset') === 0 || strcasecmp($name, 'empty') === 0 || strcasecmp($name, 'array') === 0 || is_callable($name) ) { - $func_name = strtolower($name); + $func_name = smarty_strtolower_ascii($name); if ($func_name === 'isset') { if (count($parameter) === 0) { $this->trigger_template_error('Illegal number of parameter in "isset()"'); } - $pa = array(); - foreach ($parameter as $p) { - $pa[] = $this->syntaxMatchesVariable($p) ? 'isset(' . $p . ')' : '(' . $p . ' !== null )'; - } - return '(' . implode(' && ', $pa) . ')'; + $pa = array(); + foreach ($parameter as $p) { + $pa[] = $this->syntaxMatchesVariable($p) ? 'isset(' . $p . ')' : '(' . $p . ' !== null )'; + } + return '(' . implode(' && ', $pa) . ')'; } elseif (in_array( $func_name, @@ -649,17 +648,24 @@ abstract class Smarty_Internal_TemplateCompilerBase $this->trigger_template_error("Illegal number of parameter in '{$func_name()}'"); } if ($func_name === 'empty') { - if (!$this->syntaxMatchesVariable($parameter[0]) && version_compare(PHP_VERSION, '5.5.0', '<')) { - return '(' . $parameter[ 0 ] . ' === false )'; - } else { - return $func_name . '(' . - str_replace("')->value", "',null,true,false)->value", $parameter[ 0 ]) . ')'; - } + return $func_name . '(' . + str_replace("')->value", "',null,true,false)->value", $parameter[ 0 ]) . ')'; } else { return $func_name . '(' . $parameter[ 0 ] . ')'; } } else { - return $name . '(' . implode(',', $parameter) . ')'; + + if ( + !$this->smarty->loadPlugin('smarty_modifiercompiler_' . $name) + && !isset($this->smarty->registered_plugins[Smarty::PLUGIN_MODIFIER][$name]) + && !in_array($name, ['time', 'join', 'is_array', 'in_array', 'count']) + ) { + // trigger_error('Using unregistered function "' . $name . '" in a template is deprecated and will be ' . + // 'removed in a future release. Use Smarty::registerPlugin to explicitly register ' . + // 'a custom modifier.', E_USER_DEPRECATED); + } + + return $name . '(' . implode(',', $parameter) . ')'; } } else { $this->trigger_template_error("unknown function '{$name}'"); @@ -667,16 +673,16 @@ abstract class Smarty_Internal_TemplateCompilerBase } } - /** - * Determines whether the passed string represents a valid (PHP) variable. - * This is important, because `isset()` only works on variables and `empty()` can only be passed - * a variable prior to php5.5 - * @param $string - * @return bool - */ - private function syntaxMatchesVariable($string) { - static $regex_pattern = '/^\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*((->)[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*|\[.*]*\])*$/'; - return 1 === preg_match($regex_pattern, trim($string)); + /** + * Determines whether the passed string represents a valid (PHP) variable. + * This is important, because `isset()` only works on variables and `empty()` can only be passed + * a variable prior to php5.5 + * @param $string + * @return bool + */ + private function syntaxMatchesVariable($string) { + static $regex_pattern = '/^\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*((->)[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*|\[.*]*\])*$/'; + return 1 === preg_match($regex_pattern, trim($string)); } /** @@ -691,11 +697,11 @@ abstract class Smarty_Internal_TemplateCompilerBase { if (strpos($text, '<') === false) { - return preg_replace($this->stripRegEx, '', $text); + return preg_replace($this->stripRegEx, '', $text); } - $store = array(); - $_store = 0; + $store = array(); + $_store = 0; // capture html elements not to be messed with $_offset = 0; @@ -784,7 +790,7 @@ abstract class Smarty_Internal_TemplateCompilerBase if (!isset(self::$_tag_objects[ $tag ])) { // lazy load internal compiler plugin $_tag = explode('_', $tag); - $_tag = array_map('ucfirst', $_tag); + $_tag = array_map('smarty_ucfirst_ascii', $_tag); $class_name = 'Smarty_Internal_Compile_' . implode('_', $_tag); if (class_exists($class_name) && (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) @@ -1150,8 +1156,12 @@ abstract class Smarty_Internal_TemplateCompilerBase echo ob_get_clean(); flush(); } - $e = new SmartyCompilerException($error_text); - $e->line = $line; + $e = new SmartyCompilerException( + $error_text, + 0, + $this->template->source->filepath, + $line + ); $e->source = trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ])); $e->desc = $args; $e->template = $this->template->source->filepath; @@ -1455,6 +1465,10 @@ abstract class Smarty_Internal_TemplateCompilerBase */ abstract protected function doCompile($_content, $isTemplateSource = false); + public function cStyleComment($string) { + return '/*' . str_replace('*/', '* /' , $string) . '*/'; + } + /** * Compile Tag * diff --git a/tools/smarty/sysplugins/smarty_internal_templatelexer.php b/tools/smarty/sysplugins/smarty_internal_templatelexer.php index 867a31d26..5ca482058 100644 --- a/tools/smarty/sysplugins/smarty_internal_templatelexer.php +++ b/tools/smarty/sysplugins/smarty_internal_templatelexer.php @@ -18,12 +18,6 @@ */ class Smarty_Internal_Templatelexer { - const TEXT = 1; - const TAG = 2; - const TAGBODY = 3; - const LITERAL = 4; - const DOUBLEQUOTEDSTRING = 5; - /** * Source * @@ -80,7 +74,7 @@ class Smarty_Internal_Templatelexer */ public $phpType = ''; - /** + /** * state number * * @var int @@ -229,10 +223,6 @@ class Smarty_Internal_Templatelexer */ private $yy_global_literal = null; - private $_yy_state = 1; - - private $_yy_stack = array(); - /** * constructor * @@ -245,14 +235,14 @@ class Smarty_Internal_Templatelexer $this->dataLength = strlen($this->data); $this->counter = 0; if (preg_match('/^\xEF\xBB\xBF/i', $this->data, $match)) { - $this->counter += strlen($match[ 0 ]); + $this->counter += strlen($match[0]); } $this->line = 1; $this->smarty = $compiler->template->smarty; $this->compiler = $compiler; $this->compiler->initDelimiterPreg(); - $this->smarty_token_names[ 'LDEL' ] = $this->smarty->getLeftDelimiter(); - $this->smarty_token_names[ 'RDEL' ] = $this->smarty->getRightDelimiter(); + $this->smarty_token_names['LDEL'] = $this->smarty->getLeftDelimiter(); + $this->smarty_token_names['RDEL'] = $this->smarty->getRightDelimiter(); } /** @@ -265,17 +255,17 @@ class Smarty_Internal_Templatelexer $this->yyTracePrompt = '
'; } - /** + /** * replace placeholders with runtime preg code * * @param string $preg * * @return string */ - public function replace($preg) - { + public function replace($preg) + { return $this->compiler->replaceDelimiter($preg); - } + } /** * check if current value is an autoliteral left delimiter @@ -286,7 +276,11 @@ class Smarty_Internal_Templatelexer { return $this->smarty->getAutoLiteral() && isset($this->value[ $this->compiler->getLdelLength() ]) ? strpos(" \n\t\r", $this->value[ $this->compiler->getLdelLength() ]) !== false : false; - } // end function + } + + + private $_yy_state = 1; + private $_yy_stack = array(); public function yylex() { @@ -296,62 +290,60 @@ class Smarty_Internal_Templatelexer public function yypushstate($state) { if ($this->yyTraceFILE) { - fprintf($this->yyTraceFILE, "%sState push %s\n", $this->yyTracePrompt, - isset($this->state_name[ $this->_yy_state ]) ? $this->state_name[ $this->_yy_state ] : $this->_yy_state); + fprintf($this->yyTraceFILE, "%sState push %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state); } array_push($this->_yy_stack, $this->_yy_state); $this->_yy_state = $state; if ($this->yyTraceFILE) { - fprintf($this->yyTraceFILE, "%snew State %s\n", $this->yyTracePrompt, - isset($this->state_name[ $this->_yy_state ]) ? $this->state_name[ $this->_yy_state ] : $this->_yy_state); + fprintf($this->yyTraceFILE, "%snew State %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state); } } public function yypopstate() { - if ($this->yyTraceFILE) { - fprintf($this->yyTraceFILE, "%sState pop %s\n", $this->yyTracePrompt, - isset($this->state_name[ $this->_yy_state ]) ? $this->state_name[ $this->_yy_state ] : $this->_yy_state); + if ($this->yyTraceFILE) { + fprintf($this->yyTraceFILE, "%sState pop %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state); } - $this->_yy_state = array_pop($this->_yy_stack); + $this->_yy_state = array_pop($this->_yy_stack); if ($this->yyTraceFILE) { - fprintf($this->yyTraceFILE, "%snew State %s\n", $this->yyTracePrompt, - isset($this->state_name[ $this->_yy_state ]) ? $this->state_name[ $this->_yy_state ] : $this->_yy_state); + fprintf($this->yyTraceFILE, "%snew State %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state); } + } public function yybegin($state) { - $this->_yy_state = $state; + $this->_yy_state = $state; if ($this->yyTraceFILE) { - fprintf($this->yyTraceFILE, "%sState set %s\n", $this->yyTracePrompt, - isset($this->state_name[ $this->_yy_state ]) ? $this->state_name[ $this->_yy_state ] : $this->_yy_state); + fprintf($this->yyTraceFILE, "%sState set %s\n", $this->yyTracePrompt, isset($this->state_name[$this->_yy_state]) ? $this->state_name[$this->_yy_state] : $this->_yy_state); } } + + public function yylex1() { if (!isset($this->yy_global_pattern1)) { - $this->yy_global_pattern1 = - $this->replace("/\G([{][}])|\G((SMARTYldel)SMARTYal[*])|\G((SMARTYldel)SMARTYalphp([ ].*?)?SMARTYrdel|(SMARTYldel)SMARTYal[\/]phpSMARTYrdel)|\G((SMARTYldel)SMARTYautoliteral\\s+SMARTYliteral)|\G((SMARTYldel)SMARTYalliteral\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/]literal\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal)|\G([<][?]((php\\s+|=)|\\s+)|[<][%]|[<][?]xml\\s+|[<]script\\s+language\\s*=\\s*[\"']?\\s*php\\s*[\"']?\\s*[>]|[?][>]|[%][>])|\G([\S\s])/isS"); + $this->yy_global_pattern1 = $this->replace("/\G([{][}])|\G((SMARTYldel)SMARTYal[*])|\G((SMARTYldel)SMARTYautoliteral\\s+SMARTYliteral)|\G((SMARTYldel)SMARTYalliteral\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/]literal\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal)|\G([\S\s])/isS"); } if (!isset($this->dataLength)) { $this->dataLength = strlen($this->data); } - if ($this->counter >= $this->dataLength) { + if ($this->counter >= $this->dataLength) { return false; // end of input } + do { - if (preg_match($this->yy_global_pattern1, $this->data, $yymatches, 0, $this->counter)) { - if (!isset($yymatches[ 0 ][ 1 ])) { - $yymatches = preg_grep("/(.|\s)+/", $yymatches); + if (preg_match($this->yy_global_pattern1,$this->data, $yymatches, 0, $this->counter)) { + if (!isset($yymatches[ 0 ][1])) { + $yymatches = preg_grep("/(.|\s)+/", $yymatches); } else { $yymatches = array_filter($yymatches); } if (empty($yymatches)) { throw new Exception('Error: lexing failed because a rule matched' . - ' an empty string. Input "' . substr($this->data, - $this->counter, 5) . '... state TEXT'); + ' an empty string. Input "' . substr($this->data, + $this->counter, 5) . '... state TEXT'); } next($yymatches); // skip global match $this->token = key($yymatches); // token number @@ -369,110 +361,102 @@ class Smarty_Internal_Templatelexer } elseif ($r === false) { $this->counter += strlen($this->value); $this->line += substr_count($this->value, "\n"); - if ($this->counter >= $this->dataLength) { + if ($this->counter >= $this->dataLength) { return false; // end of input } // skip this token continue; - } - } else { - throw new Exception('Unexpected input at line ' . $this->line . - ': ' . $this->data[ $this->counter ]); + } } else { + throw new Exception('Unexpected input at line' . $this->line . + ': ' . $this->data[$this->counter]); } break; } while (true); - } - public function yy_r1_1() - { - $this->token = Smarty_Internal_Templateparser::TP_TEXT; - } - - public function yy_r1_2() - { - $to = $this->dataLength; - preg_match("/[*]{$this->compiler->getRdelPreg()}[\n]?/", $this->data, $match, PREG_OFFSET_CAPTURE, - $this->counter); - if (isset($match[ 0 ][ 1 ])) { - $to = $match[ 0 ][ 1 ] + strlen($match[ 0 ][ 0 ]); - } else { - $this->compiler->trigger_template_error("missing or misspelled comment closing tag '{$this->smarty->getRightDelimiter()}'"); - } - $this->value = substr($this->data, $this->counter, $to - $this->counter); - return false; - } - - public function yy_r1_4() - { - $this->compiler->getTagCompiler('private_php')->parsePhp($this); - } - - public function yy_r1_8() - { - $this->token = Smarty_Internal_Templateparser::TP_TEXT; - } - - public function yy_r1_10() - { - $this->token = Smarty_Internal_Templateparser::TP_LITERALSTART; - $this->yypushstate(self::LITERAL); - } - - public function yy_r1_12() - { - $this->token = Smarty_Internal_Templateparser::TP_LITERALEND; - $this->yypushstate(self::LITERAL); } // end function - public function yy_r1_14() + + const TEXT = 1; + public function yy_r1_1() { + + $this->token = Smarty_Internal_Templateparser::TP_TEXT; + } + public function yy_r1_2() + { + + $to = $this->dataLength; + preg_match("/[*]{$this->compiler->getRdelPreg()}[\n]?/",$this->data,$match,PREG_OFFSET_CAPTURE,$this->counter); + if (isset($match[0][1])) { + $to = $match[0][1] + strlen($match[0][0]); + } else { + $this->compiler->trigger_template_error ("missing or misspelled comment closing tag '{$this->smarty->getRightDelimiter()}'"); + } + $this->value = substr($this->data,$this->counter,$to-$this->counter); + return false; + } + public function yy_r1_4() + { + + $this->token = Smarty_Internal_Templateparser::TP_TEXT; + } + public function yy_r1_6() + { + + $this->token = Smarty_Internal_Templateparser::TP_LITERALSTART; + $this->yypushstate(self::LITERAL); + } + public function yy_r1_8() + { + + $this->token = Smarty_Internal_Templateparser::TP_LITERALEND; + $this->yypushstate(self::LITERAL); + } + public function yy_r1_10() + { + $this->yypushstate(self::TAG); return true; - } - - public function yy_r1_16() + } + public function yy_r1_12() { - $this->compiler->getTagCompiler('private_php')->parsePhp($this); - } - public function yy_r1_19() - { - if (!isset($this->yy_global_text)) { - $this->yy_global_text = - $this->replace('/(SMARTYldel)SMARTYal|[<][?]((php\s+|=)|\s+)|[<][%]|[<][?]xml\s+|[<]script\s+language\s*=\s*["\']?\s*php\s*["\']?\s*[>]|[?][>]|[%][>]SMARTYliteral/isS'); - } - $to = $this->dataLength; - preg_match($this->yy_global_text, $this->data, $match, PREG_OFFSET_CAPTURE, $this->counter); - if (isset($match[ 0 ][ 1 ])) { - $to = $match[ 0 ][ 1 ]; - } - $this->value = substr($this->data, $this->counter, $to - $this->counter); - $this->token = Smarty_Internal_Templateparser::TP_TEXT; - } + if (!isset($this->yy_global_text)) { + $this->yy_global_text = $this->replace('/(SMARTYldel)SMARTYal/isS'); + } + $to = $this->dataLength; + preg_match($this->yy_global_text, $this->data,$match,PREG_OFFSET_CAPTURE,$this->counter); + if (isset($match[0][1])) { + $to = $match[0][1]; + } + $this->value = substr($this->data,$this->counter,$to-$this->counter); + $this->token = Smarty_Internal_Templateparser::TP_TEXT; + } + public function yylex2() { if (!isset($this->yy_global_pattern2)) { - $this->yy_global_pattern2 = - $this->replace("/\G((SMARTYldel)SMARTYal(if|elseif|else if|while)\\s+)|\G((SMARTYldel)SMARTYalfor\\s+)|\G((SMARTYldel)SMARTYalforeach(?![^\s]))|\G((SMARTYldel)SMARTYalsetfilter\\s+)|\G((SMARTYldel)SMARTYalmake_nocache\\s+)|\G((SMARTYldel)SMARTYal[0-9]*[a-zA-Z_]\\w*(\\s+nocache)?\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[$]smarty\\.block\\.(child|parent)\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/][0-9]*[a-zA-Z_]\\w*\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[$][0-9]*[a-zA-Z_]\\w*(\\s+nocache)?\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/])|\G((SMARTYldel)SMARTYal)/isS"); + $this->yy_global_pattern2 = $this->replace("/\G((SMARTYldel)SMARTYal(if|elseif|else if|while)\\s+)|\G((SMARTYldel)SMARTYalfor\\s+)|\G((SMARTYldel)SMARTYalforeach(?![^\s]))|\G((SMARTYldel)SMARTYalsetfilter\\s+)|\G((SMARTYldel)SMARTYalmake_nocache\\s+)|\G((SMARTYldel)SMARTYal[0-9]*[a-zA-Z_]\\w*(\\s+nocache)?\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[$]smarty\\.block\\.(child|parent)\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/][0-9]*[a-zA-Z_]\\w*\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[$][0-9]*[a-zA-Z_]\\w*(\\s+nocache)?\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/])|\G((SMARTYldel)SMARTYal)/isS"); } if (!isset($this->dataLength)) { $this->dataLength = strlen($this->data); } - if ($this->counter >= $this->dataLength) { + if ($this->counter >= $this->dataLength) { return false; // end of input } + do { - if (preg_match($this->yy_global_pattern2, $this->data, $yymatches, 0, $this->counter)) { - if (!isset($yymatches[ 0 ][ 1 ])) { - $yymatches = preg_grep("/(.|\s)+/", $yymatches); + if (preg_match($this->yy_global_pattern2,$this->data, $yymatches, 0, $this->counter)) { + if (!isset($yymatches[ 0 ][1])) { + $yymatches = preg_grep("/(.|\s)+/", $yymatches); } else { $yymatches = array_filter($yymatches); } if (empty($yymatches)) { throw new Exception('Error: lexing failed because a rule matched' . - ' an empty string. Input "' . substr($this->data, - $this->counter, 5) . '... state TAG'); + ' an empty string. Input "' . substr($this->data, + $this->counter, 5) . '... state TAG'); } next($yymatches); // skip global match $this->token = key($yymatches); // token number @@ -490,79 +474,82 @@ class Smarty_Internal_Templatelexer } elseif ($r === false) { $this->counter += strlen($this->value); $this->line += substr_count($this->value, "\n"); - if ($this->counter >= $this->dataLength) { + if ($this->counter >= $this->dataLength) { return false; // end of input } // skip this token continue; - } - } else { - throw new Exception('Unexpected input at line ' . $this->line . - ': ' . $this->data[ $this->counter ]); + } } else { + throw new Exception('Unexpected input at line' . $this->line . + ': ' . $this->data[$this->counter]); } break; } while (true); - } + } // end function + + + const TAG = 2; public function yy_r2_1() { + $this->token = Smarty_Internal_Templateparser::TP_LDELIF; $this->yybegin(self::TAGBODY); $this->taglineno = $this->line; - } - + } public function yy_r2_4() { + $this->token = Smarty_Internal_Templateparser::TP_LDELFOR; $this->yybegin(self::TAGBODY); $this->taglineno = $this->line; - } - + } public function yy_r2_6() { + $this->token = Smarty_Internal_Templateparser::TP_LDELFOREACH; $this->yybegin(self::TAGBODY); $this->taglineno = $this->line; - } - + } public function yy_r2_8() { + $this->token = Smarty_Internal_Templateparser::TP_LDELSETFILTER; $this->yybegin(self::TAGBODY); $this->taglineno = $this->line; - } - + } public function yy_r2_10() { + $this->token = Smarty_Internal_Templateparser::TP_LDELMAKENOCACHE; $this->yybegin(self::TAGBODY); $this->taglineno = $this->line; - } - + } public function yy_r2_12() { + $this->yypopstate(); $this->token = Smarty_Internal_Templateparser::TP_SIMPLETAG; $this->taglineno = $this->line; - } - + } public function yy_r2_15() { - $this->yypopstate(); - $this->token = Smarty_Internal_Templateparser::TP_SMARTYBLOCKCHILDPARENT; - $this->taglineno = $this->line; - } + $this->yypopstate(); + $this->token = Smarty_Internal_Templateparser::TP_SMARTYBLOCKCHILDPARENT; + $this->taglineno = $this->line; + } public function yy_r2_18() { + $this->yypopstate(); $this->token = Smarty_Internal_Templateparser::TP_CLOSETAG; $this->taglineno = $this->line; - } - + } public function yy_r2_20() { - if ($this->_yy_stack[ count($this->_yy_stack) - 1 ] === self::TEXT) { + + if ($this->_yy_stack[count($this->_yy_stack)-1] === self::TEXT) { $this->yypopstate(); $this->token = Smarty_Internal_Templateparser::TP_SIMPELOUTPUT; $this->taglineno = $this->line; @@ -572,45 +559,46 @@ class Smarty_Internal_Templatelexer $this->yybegin(self::TAGBODY); $this->taglineno = $this->line; } - } // end function - + } public function yy_r2_23() { + $this->token = Smarty_Internal_Templateparser::TP_LDELSLASH; $this->yybegin(self::TAGBODY); $this->taglineno = $this->line; - } - + } public function yy_r2_25() { + $this->token = Smarty_Internal_Templateparser::TP_LDEL; $this->yybegin(self::TAGBODY); $this->taglineno = $this->line; - } + } + public function yylex3() { if (!isset($this->yy_global_pattern3)) { - $this->yy_global_pattern3 = - $this->replace("/\G(\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal)|\G([\"])|\G('[^'\\\\]*(?:\\\\.[^'\\\\]*)*')|\G([$][0-9]*[a-zA-Z_]\\w*)|\G([$])|\G(\\s+is\\s+in\\s+)|\G(\\s+as\\s+)|\G(\\s+to\\s+)|\G(\\s+step\\s+)|\G(\\s+instanceof\\s+)|\G(\\s*([!=][=]{1,2}|[<][=>]?|[>][=]?|[&|]{2})\\s*)|\G(\\s+(eq|ne|neq|gt|ge|gte|lt|le|lte|mod|and|or|xor)\\s+)|\G(\\s+is\\s+(not\\s+)?(odd|even|div)\\s+by\\s+)|\G(\\s+is\\s+(not\\s+)?(odd|even))|\G([!]\\s*|not\\s+)|\G([(](int(eger)?|bool(ean)?|float|double|real|string|binary|array|object)[)]\\s*)|\G(\\s*[(]\\s*)|\G(\\s*[)])|\G(\\[\\s*)|\G(\\s*\\])|\G(\\s*[-][>]\\s*)|\G(\\s*[=][>]\\s*)|\G(\\s*[=]\\s*)|\G(([+]|[-]){2})|\G(\\s*([+]|[-])\\s*)|\G(\\s*([*]{1,2}|[%\/^&]|[<>]{2})\\s*)|\G([@])|\G(array\\s*[(]\\s*)|\G([#])|\G(\\s+[0-9]*[a-zA-Z_][a-zA-Z0-9_\-:]*\\s*[=]\\s*)|\G(([0-9]*[a-zA-Z_]\\w*)?(\\\\[0-9]*[a-zA-Z_]\\w*)+)|\G([0-9]*[a-zA-Z_]\\w*)|\G(\\d+)|\G([`])|\G([|][@]?)|\G([.])|\G(\\s*[,]\\s*)|\G(\\s*[;]\\s*)|\G([:]{2})|\G(\\s*[:]\\s*)|\G(\\s*[?]\\s*)|\G(0[xX][0-9a-fA-F]+)|\G(\\s+)|\G([\S\s])/isS"); + $this->yy_global_pattern3 = $this->replace("/\G(\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal)|\G([\"])|\G('[^'\\\\]*(?:\\\\.[^'\\\\]*)*')|\G([$][0-9]*[a-zA-Z_]\\w*)|\G([$])|\G(\\s+is\\s+in\\s+)|\G(\\s+as\\s+)|\G(\\s+to\\s+)|\G(\\s+step\\s+)|\G(\\s+instanceof\\s+)|\G(\\s*([!=][=]{1,2}|[<][=>]?|[>][=]?|[&|]{2})\\s*)|\G(\\s+(eq|ne|neq|gt|ge|gte|lt|le|lte|mod|and|or|xor)\\s+)|\G(\\s+is\\s+(not\\s+)?(odd|even|div)\\s+by\\s+)|\G(\\s+is\\s+(not\\s+)?(odd|even))|\G([!]\\s*|not\\s+)|\G([(](int(eger)?|bool(ean)?|float|double|real|string|binary|array|object)[)]\\s*)|\G(\\s*[(]\\s*)|\G(\\s*[)])|\G(\\[\\s*)|\G(\\s*\\])|\G(\\s*[-][>]\\s*)|\G(\\s*[=][>]\\s*)|\G(\\s*[=]\\s*)|\G(([+]|[-]){2})|\G(\\s*([+]|[-])\\s*)|\G(\\s*([*]{1,2}|[%\/^&]|[<>]{2})\\s*)|\G([@])|\G(array\\s*[(]\\s*)|\G([#])|\G(\\s+[0-9]*[a-zA-Z_][a-zA-Z0-9_\-:]*\\s*[=]\\s*)|\G(([0-9]*[a-zA-Z_]\\w*)?(\\\\[0-9]*[a-zA-Z_]\\w*)+)|\G([0-9]*[a-zA-Z_]\\w*)|\G(\\d+)|\G([`])|\G([|][@]?)|\G([.])|\G(\\s*[,]\\s*)|\G(\\s*[;]\\s*)|\G([:]{2})|\G(\\s*[:]\\s*)|\G(\\s*[?]\\s*)|\G(0[xX][0-9a-fA-F]+)|\G(\\s+)|\G([\S\s])/isS"); } if (!isset($this->dataLength)) { $this->dataLength = strlen($this->data); } - if ($this->counter >= $this->dataLength) { + if ($this->counter >= $this->dataLength) { return false; // end of input } + do { - if (preg_match($this->yy_global_pattern3, $this->data, $yymatches, 0, $this->counter)) { - if (!isset($yymatches[ 0 ][ 1 ])) { - $yymatches = preg_grep("/(.|\s)+/", $yymatches); + if (preg_match($this->yy_global_pattern3,$this->data, $yymatches, 0, $this->counter)) { + if (!isset($yymatches[ 0 ][1])) { + $yymatches = preg_grep("/(.|\s)+/", $yymatches); } else { $yymatches = array_filter($yymatches); } if (empty($yymatches)) { throw new Exception('Error: lexing failed because a rule matched' . - ' an empty string. Input "' . substr($this->data, - $this->counter, 5) . '... state TAGBODY'); + ' an empty string. Input "' . substr($this->data, + $this->counter, 5) . '... state TAGBODY'); } next($yymatches); // skip global match $this->token = key($yymatches); // token number @@ -628,281 +616,285 @@ class Smarty_Internal_Templatelexer } elseif ($r === false) { $this->counter += strlen($this->value); $this->line += substr_count($this->value, "\n"); - if ($this->counter >= $this->dataLength) { + if ($this->counter >= $this->dataLength) { return false; // end of input } // skip this token continue; - } - } else { - throw new Exception('Unexpected input at line ' . $this->line . - ': ' . $this->data[ $this->counter ]); + } } else { + throw new Exception('Unexpected input at line' . $this->line . + ': ' . $this->data[$this->counter]); } break; } while (true); - } + } // end function + + + const TAGBODY = 3; public function yy_r3_1() { + $this->token = Smarty_Internal_Templateparser::TP_RDEL; $this->yypopstate(); - } - + } public function yy_r3_2() { + $this->yypushstate(self::TAG); return true; - } - + } public function yy_r3_4() { + $this->token = Smarty_Internal_Templateparser::TP_QUOTE; $this->yypushstate(self::DOUBLEQUOTEDSTRING); $this->compiler->enterDoubleQuote(); - } - + } public function yy_r3_5() { - $this->token = Smarty_Internal_Templateparser::TP_SINGLEQUOTESTRING; - } + $this->token = Smarty_Internal_Templateparser::TP_SINGLEQUOTESTRING; + } public function yy_r3_6() { - $this->token = Smarty_Internal_Templateparser::TP_DOLLARID; - } + $this->token = Smarty_Internal_Templateparser::TP_DOLLARID; + } public function yy_r3_7() { - $this->token = Smarty_Internal_Templateparser::TP_DOLLAR; - } + $this->token = Smarty_Internal_Templateparser::TP_DOLLAR; + } public function yy_r3_8() { - $this->token = Smarty_Internal_Templateparser::TP_ISIN; - } + $this->token = Smarty_Internal_Templateparser::TP_ISIN; + } public function yy_r3_9() { - $this->token = Smarty_Internal_Templateparser::TP_AS; - } + $this->token = Smarty_Internal_Templateparser::TP_AS; + } public function yy_r3_10() { - $this->token = Smarty_Internal_Templateparser::TP_TO; - } + $this->token = Smarty_Internal_Templateparser::TP_TO; + } public function yy_r3_11() { - $this->token = Smarty_Internal_Templateparser::TP_STEP; - } + $this->token = Smarty_Internal_Templateparser::TP_STEP; + } public function yy_r3_12() { - $this->token = Smarty_Internal_Templateparser::TP_INSTANCEOF; - } + $this->token = Smarty_Internal_Templateparser::TP_INSTANCEOF; + } public function yy_r3_13() { - $this->token = Smarty_Internal_Templateparser::TP_LOGOP; - } + $this->token = Smarty_Internal_Templateparser::TP_LOGOP; + } public function yy_r3_15() { - $this->token = Smarty_Internal_Templateparser::TP_SLOGOP; - } + $this->token = Smarty_Internal_Templateparser::TP_SLOGOP; + } public function yy_r3_17() { - $this->token = Smarty_Internal_Templateparser::TP_TLOGOP; - } + $this->token = Smarty_Internal_Templateparser::TP_TLOGOP; + } public function yy_r3_20() { - $this->token = Smarty_Internal_Templateparser::TP_SINGLECOND; - } + $this->token = Smarty_Internal_Templateparser::TP_SINGLECOND; + } public function yy_r3_23() { - $this->token = Smarty_Internal_Templateparser::TP_NOT; - } + $this->token = Smarty_Internal_Templateparser::TP_NOT; + } public function yy_r3_24() { - $this->token = Smarty_Internal_Templateparser::TP_TYPECAST; - } + $this->token = Smarty_Internal_Templateparser::TP_TYPECAST; + } public function yy_r3_28() { - $this->token = Smarty_Internal_Templateparser::TP_OPENP; - } + $this->token = Smarty_Internal_Templateparser::TP_OPENP; + } public function yy_r3_29() { - $this->token = Smarty_Internal_Templateparser::TP_CLOSEP; - } + $this->token = Smarty_Internal_Templateparser::TP_CLOSEP; + } public function yy_r3_30() { - $this->token = Smarty_Internal_Templateparser::TP_OPENB; - } + $this->token = Smarty_Internal_Templateparser::TP_OPENB; + } public function yy_r3_31() { - $this->token = Smarty_Internal_Templateparser::TP_CLOSEB; - } + $this->token = Smarty_Internal_Templateparser::TP_CLOSEB; + } public function yy_r3_32() { - $this->token = Smarty_Internal_Templateparser::TP_PTR; - } + $this->token = Smarty_Internal_Templateparser::TP_PTR; + } public function yy_r3_33() { - $this->token = Smarty_Internal_Templateparser::TP_APTR; - } + $this->token = Smarty_Internal_Templateparser::TP_APTR; + } public function yy_r3_34() { - $this->token = Smarty_Internal_Templateparser::TP_EQUAL; - } + $this->token = Smarty_Internal_Templateparser::TP_EQUAL; + } public function yy_r3_35() { - $this->token = Smarty_Internal_Templateparser::TP_INCDEC; - } + $this->token = Smarty_Internal_Templateparser::TP_INCDEC; + } public function yy_r3_37() { - $this->token = Smarty_Internal_Templateparser::TP_UNIMATH; - } + $this->token = Smarty_Internal_Templateparser::TP_UNIMATH; + } public function yy_r3_39() { - $this->token = Smarty_Internal_Templateparser::TP_MATH; - } + $this->token = Smarty_Internal_Templateparser::TP_MATH; + } public function yy_r3_41() { - $this->token = Smarty_Internal_Templateparser::TP_AT; - } + $this->token = Smarty_Internal_Templateparser::TP_AT; + } public function yy_r3_42() { - $this->token = Smarty_Internal_Templateparser::TP_ARRAYOPEN; - } + $this->token = Smarty_Internal_Templateparser::TP_ARRAYOPEN; + } public function yy_r3_43() { - $this->token = Smarty_Internal_Templateparser::TP_HATCH; - } + $this->token = Smarty_Internal_Templateparser::TP_HATCH; + } public function yy_r3_44() { + // resolve conflicts with shorttag and right_delimiter starting with '=' - if (substr($this->data, $this->counter + strlen($this->value) - 1, $this->compiler->getRdelLength()) === - $this->smarty->getRightDelimiter()) { - preg_match('/\s+/', $this->value, $match); - $this->value = $match[ 0 ]; + if (substr($this->data, $this->counter + strlen($this->value) - 1, $this->compiler->getRdelLength()) === $this->smarty->getRightDelimiter()) { + preg_match('/\s+/',$this->value,$match); + $this->value = $match[0]; $this->token = Smarty_Internal_Templateparser::TP_SPACE; } else { $this->token = Smarty_Internal_Templateparser::TP_ATTR; } - } - + } public function yy_r3_45() { - $this->token = Smarty_Internal_Templateparser::TP_NAMESPACE; - } + $this->token = Smarty_Internal_Templateparser::TP_NAMESPACE; + } public function yy_r3_48() { - $this->token = Smarty_Internal_Templateparser::TP_ID; - } + $this->token = Smarty_Internal_Templateparser::TP_ID; + } public function yy_r3_49() { - $this->token = Smarty_Internal_Templateparser::TP_INTEGER; - } + $this->token = Smarty_Internal_Templateparser::TP_INTEGER; + } public function yy_r3_50() { + $this->token = Smarty_Internal_Templateparser::TP_BACKTICK; $this->yypopstate(); - } - + } public function yy_r3_51() { - $this->token = Smarty_Internal_Templateparser::TP_VERT; - } + $this->token = Smarty_Internal_Templateparser::TP_VERT; + } public function yy_r3_52() { - $this->token = Smarty_Internal_Templateparser::TP_DOT; - } + $this->token = Smarty_Internal_Templateparser::TP_DOT; + } public function yy_r3_53() { - $this->token = Smarty_Internal_Templateparser::TP_COMMA; - } + $this->token = Smarty_Internal_Templateparser::TP_COMMA; + } public function yy_r3_54() { - $this->token = Smarty_Internal_Templateparser::TP_SEMICOLON; - } + $this->token = Smarty_Internal_Templateparser::TP_SEMICOLON; + } public function yy_r3_55() { - $this->token = Smarty_Internal_Templateparser::TP_DOUBLECOLON; - } + $this->token = Smarty_Internal_Templateparser::TP_DOUBLECOLON; + } public function yy_r3_56() { - $this->token = Smarty_Internal_Templateparser::TP_COLON; - } + $this->token = Smarty_Internal_Templateparser::TP_COLON; + } public function yy_r3_57() { - $this->token = Smarty_Internal_Templateparser::TP_QMARK; - } + $this->token = Smarty_Internal_Templateparser::TP_QMARK; + } public function yy_r3_58() { - $this->token = Smarty_Internal_Templateparser::TP_HEX; - } + $this->token = Smarty_Internal_Templateparser::TP_HEX; + } public function yy_r3_59() { - $this->token = Smarty_Internal_Templateparser::TP_SPACE; - } // end function + $this->token = Smarty_Internal_Templateparser::TP_SPACE; + } public function yy_r3_60() { - $this->token = Smarty_Internal_Templateparser::TP_TEXT; - } + $this->token = Smarty_Internal_Templateparser::TP_TEXT; + } + + + public function yylex4() { if (!isset($this->yy_global_pattern4)) { - $this->yy_global_pattern4 = - $this->replace("/\G((SMARTYldel)SMARTYalliteral\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/]literal\\s*SMARTYrdel)|\G([\S\s])/isS"); + $this->yy_global_pattern4 = $this->replace("/\G((SMARTYldel)SMARTYalliteral\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/]literal\\s*SMARTYrdel)|\G([\S\s])/isS"); } if (!isset($this->dataLength)) { $this->dataLength = strlen($this->data); } - if ($this->counter >= $this->dataLength) { + if ($this->counter >= $this->dataLength) { return false; // end of input } + do { - if (preg_match($this->yy_global_pattern4, $this->data, $yymatches, 0, $this->counter)) { - if (!isset($yymatches[ 0 ][ 1 ])) { - $yymatches = preg_grep("/(.|\s)+/", $yymatches); + if (preg_match($this->yy_global_pattern4,$this->data, $yymatches, 0, $this->counter)) { + if (!isset($yymatches[ 0 ][1])) { + $yymatches = preg_grep("/(.|\s)+/", $yymatches); } else { $yymatches = array_filter($yymatches); } if (empty($yymatches)) { throw new Exception('Error: lexing failed because a rule matched' . - ' an empty string. Input "' . substr($this->data, - $this->counter, 5) . '... state LITERAL'); + ' an empty string. Input "' . substr($this->data, + $this->counter, 5) . '... state LITERAL'); } next($yymatches); // skip global match $this->token = key($yymatches); // token number @@ -920,76 +912,80 @@ class Smarty_Internal_Templatelexer } elseif ($r === false) { $this->counter += strlen($this->value); $this->line += substr_count($this->value, "\n"); - if ($this->counter >= $this->dataLength) { + if ($this->counter >= $this->dataLength) { return false; // end of input } // skip this token continue; - } - } else { - throw new Exception('Unexpected input at line ' . $this->line . - ': ' . $this->data[ $this->counter ]); + } } else { + throw new Exception('Unexpected input at line' . $this->line . + ': ' . $this->data[$this->counter]); } break; } while (true); - } + } // end function + + + const LITERAL = 4; public function yy_r4_1() { + $this->literal_cnt++; $this->token = Smarty_Internal_Templateparser::TP_LITERAL; - } - + } public function yy_r4_3() { + if ($this->literal_cnt) { - $this->literal_cnt--; + $this->literal_cnt--; $this->token = Smarty_Internal_Templateparser::TP_LITERAL; } else { $this->token = Smarty_Internal_Templateparser::TP_LITERALEND; $this->yypopstate(); } - } - + } public function yy_r4_5() { - if (!isset($this->yy_global_literal)) { - $this->yy_global_literal = $this->replace('/(SMARTYldel)SMARTYal[\/]?literalSMARTYrdel/isS'); - } - $to = $this->dataLength; - preg_match($this->yy_global_literal, $this->data, $match, PREG_OFFSET_CAPTURE, $this->counter); - if (isset($match[ 0 ][ 1 ])) { - $to = $match[ 0 ][ 1 ]; - } else { - $this->compiler->trigger_template_error("missing or misspelled literal closing tag"); - } - $this->value = substr($this->data, $this->counter, $to - $this->counter); - $this->token = Smarty_Internal_Templateparser::TP_LITERAL; - } // end function + if (!isset($this->yy_global_literal)) { + $this->yy_global_literal = $this->replace('/(SMARTYldel)SMARTYal[\/]?literalSMARTYrdel/isS'); + } + $to = $this->dataLength; + preg_match($this->yy_global_literal, $this->data,$match,PREG_OFFSET_CAPTURE,$this->counter); + if (isset($match[0][1])) { + $to = $match[0][1]; + } else { + $this->compiler->trigger_template_error ("missing or misspelled literal closing tag"); + } + $this->value = substr($this->data,$this->counter,$to-$this->counter); + $this->token = Smarty_Internal_Templateparser::TP_LITERAL; + } + + public function yylex5() { if (!isset($this->yy_global_pattern5)) { - $this->yy_global_pattern5 = - $this->replace("/\G((SMARTYldel)SMARTYautoliteral\\s+SMARTYliteral)|\G((SMARTYldel)SMARTYalliteral\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/]literal\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/])|\G((SMARTYldel)SMARTYal[0-9]*[a-zA-Z_]\\w*)|\G((SMARTYldel)SMARTYal)|\G([\"])|\G([`][$])|\G([$][0-9]*[a-zA-Z_]\\w*)|\G([$])|\G(([^\"\\\\]*?)((?:\\\\.[^\"\\\\]*?)*?)(?=((SMARTYldel)SMARTYal|\\$|`\\$|\"SMARTYliteral)))|\G([\S\s])/isS"); + $this->yy_global_pattern5 = $this->replace("/\G((SMARTYldel)SMARTYautoliteral\\s+SMARTYliteral)|\G((SMARTYldel)SMARTYalliteral\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/]literal\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/])|\G((SMARTYldel)SMARTYal[0-9]*[a-zA-Z_]\\w*)|\G((SMARTYldel)SMARTYal)|\G([\"])|\G([`][$])|\G([$][0-9]*[a-zA-Z_]\\w*)|\G([$])|\G(([^\"\\\\]*?)((?:\\\\.[^\"\\\\]*?)*?)(?=((SMARTYldel)SMARTYal|\\$|`\\$|\"SMARTYliteral)))|\G([\S\s])/isS"); } if (!isset($this->dataLength)) { $this->dataLength = strlen($this->data); } - if ($this->counter >= $this->dataLength) { + if ($this->counter >= $this->dataLength) { return false; // end of input } + do { - if (preg_match($this->yy_global_pattern5, $this->data, $yymatches, 0, $this->counter)) { - if (!isset($yymatches[ 0 ][ 1 ])) { - $yymatches = preg_grep("/(.|\s)+/", $yymatches); + if (preg_match($this->yy_global_pattern5,$this->data, $yymatches, 0, $this->counter)) { + if (!isset($yymatches[ 0 ][1])) { + $yymatches = preg_grep("/(.|\s)+/", $yymatches); } else { $yymatches = array_filter($yymatches); } if (empty($yymatches)) { throw new Exception('Error: lexing failed because a rule matched' . - ' an empty string. Input "' . substr($this->data, - $this->counter, 5) . '... state DOUBLEQUOTEDSTRING'); + ' an empty string. Input "' . substr($this->data, + $this->counter, 5) . '... state DOUBLEQUOTEDSTRING'); } next($yymatches); // skip global match $this->token = key($yymatches); // token number @@ -1007,89 +1003,93 @@ class Smarty_Internal_Templatelexer } elseif ($r === false) { $this->counter += strlen($this->value); $this->line += substr_count($this->value, "\n"); - if ($this->counter >= $this->dataLength) { + if ($this->counter >= $this->dataLength) { return false; // end of input } // skip this token continue; - } - } else { - throw new Exception('Unexpected input at line ' . $this->line . - ': ' . $this->data[ $this->counter ]); + } } else { + throw new Exception('Unexpected input at line' . $this->line . + ': ' . $this->data[$this->counter]); } break; } while (true); - } + } // end function + + + const DOUBLEQUOTEDSTRING = 5; public function yy_r5_1() { - $this->token = Smarty_Internal_Templateparser::TP_TEXT; - } + $this->token = Smarty_Internal_Templateparser::TP_TEXT; + } public function yy_r5_3() { - $this->token = Smarty_Internal_Templateparser::TP_TEXT; - } + $this->token = Smarty_Internal_Templateparser::TP_TEXT; + } public function yy_r5_5() { - $this->token = Smarty_Internal_Templateparser::TP_TEXT; - } + $this->token = Smarty_Internal_Templateparser::TP_TEXT; + } public function yy_r5_7() { + $this->yypushstate(self::TAG); return true; - } - + } public function yy_r5_9() { + $this->yypushstate(self::TAG); return true; - } - + } public function yy_r5_11() { + $this->token = Smarty_Internal_Templateparser::TP_LDEL; $this->taglineno = $this->line; $this->yypushstate(self::TAGBODY); - } - + } public function yy_r5_13() { + $this->token = Smarty_Internal_Templateparser::TP_QUOTE; $this->yypopstate(); - } - + } public function yy_r5_14() { + $this->token = Smarty_Internal_Templateparser::TP_BACKTICK; - $this->value = substr($this->value, 0, -1); + $this->value = substr($this->value,0,-1); $this->yypushstate(self::TAGBODY); $this->taglineno = $this->line; - } - + } public function yy_r5_15() { - $this->token = Smarty_Internal_Templateparser::TP_DOLLARID; - } + $this->token = Smarty_Internal_Templateparser::TP_DOLLARID; + } public function yy_r5_16() { - $this->token = Smarty_Internal_Templateparser::TP_TEXT; - } + $this->token = Smarty_Internal_Templateparser::TP_TEXT; + } public function yy_r5_17() { - $this->token = Smarty_Internal_Templateparser::TP_TEXT; - } + $this->token = Smarty_Internal_Templateparser::TP_TEXT; + } public function yy_r5_22() { - $to = $this->dataLength; - $this->value = substr($this->data, $this->counter, $to - $this->counter); - $this->token = Smarty_Internal_Templateparser::TP_TEXT; - } -} - + $to = $this->dataLength; + $this->value = substr($this->data,$this->counter,$to-$this->counter); + $this->token = Smarty_Internal_Templateparser::TP_TEXT; + } + + } + + \ No newline at end of file diff --git a/tools/smarty/sysplugins/smarty_internal_templateparser.php b/tools/smarty/sysplugins/smarty_internal_templateparser.php index aaeae63b7..c5516efcf 100644 --- a/tools/smarty/sysplugins/smarty_internal_templateparser.php +++ b/tools/smarty/sysplugins/smarty_internal_templateparser.php @@ -7,1598 +7,25 @@ class TP_yyStackEntry ** number for the token at this stack level */ public $minor; /* The user-supplied minor token value. This ** is the value of the token */ -} +}; + // line 11 "../smarty/lexer/smarty_internal_templateparser.y" /** - * Smarty Template Parser Class - * - * This is the template parser. - * It is generated from the smarty_internal_templateparser.y file - * - * @author Uwe Tews - */ +* Smarty Template Parser Class +* +* This is the template parser. +* It is generated from the smarty_internal_templateparser.y file +* +* @author Uwe Tews +*/ class Smarty_Internal_Templateparser { - // line 23 "../smarty/lexer/smarty_internal_templateparser.y" - const ERR1 = 'Security error: Call to private object member not allowed'; - const ERR2 = 'Security error: Call to dynamic object member not allowed'; - const ERR3 = 'PHP in template not allowed. Use SmartyBC to enable it'; - const TP_VERT = 1; - const TP_COLON = 2; - const TP_PHP = 3; - const TP_TEXT = 4; - const TP_STRIPON = 5; - const TP_STRIPOFF = 6; - const TP_LITERALSTART = 7; - const TP_LITERALEND = 8; - const TP_LITERAL = 9; - const TP_SIMPELOUTPUT = 10; - const TP_SIMPLETAG = 11; - const TP_SMARTYBLOCKCHILDPARENT = 12; - const TP_LDEL = 13; - const TP_RDEL = 14; - const TP_DOLLARID = 15; - const TP_EQUAL = 16; - const TP_ID = 17; - const TP_PTR = 18; - const TP_LDELMAKENOCACHE = 19; - const TP_LDELIF = 20; - const TP_LDELFOR = 21; - const TP_SEMICOLON = 22; - const TP_INCDEC = 23; - const TP_TO = 24; - const TP_STEP = 25; - const TP_LDELFOREACH = 26; - const TP_SPACE = 27; - const TP_AS = 28; - const TP_APTR = 29; - const TP_LDELSETFILTER = 30; - const TP_CLOSETAG = 31; - const TP_LDELSLASH = 32; - const TP_ATTR = 33; - const TP_INTEGER = 34; - const TP_COMMA = 35; - const TP_OPENP = 36; - const TP_CLOSEP = 37; - const TP_MATH = 38; - const TP_UNIMATH = 39; - const TP_ISIN = 40; - const TP_QMARK = 41; - const TP_NOT = 42; - const TP_TYPECAST = 43; - const TP_HEX = 44; - const TP_DOT = 45; - const TP_INSTANCEOF = 46; - const TP_SINGLEQUOTESTRING = 47; - const TP_DOUBLECOLON = 48; - const TP_NAMESPACE = 49; - const TP_AT = 50; - const TP_HATCH = 51; - const TP_OPENB = 52; - const TP_CLOSEB = 53; - const TP_DOLLAR = 54; - const TP_LOGOP = 55; - const TP_SLOGOP = 56; - const TP_TLOGOP = 57; - const TP_SINGLECOND = 58; - const TP_ARRAYOPEN = 59; - const TP_QUOTE = 60; - const TP_BACKTICK = 61; - const YY_NO_ACTION = 516; - const YY_ACCEPT_ACTION = 515; - const YY_ERROR_ACTION = 514; - const YY_SZ_ACTTAB = 2071; - const YY_SHIFT_USE_DFLT = -31; - const YY_SHIFT_MAX = 230; - const YY_REDUCE_USE_DFLT = -91; - const YY_REDUCE_MAX = 178; - const YYNOCODE = 110; - const YYSTACKDEPTH = 500; - const YYNSTATE = 327; - const YYNRULE = 187; - const YYERRORSYMBOL = 62; - const YYERRSYMDT = 'yy0'; - const YYFALLBACK = 0; +// line 23 "../smarty/lexer/smarty_internal_templateparser.y" - public static $yy_action = array( - 251, 234, 237, 1, 144, 127, 428, 184, 199, 212, - 10, 54, 19, 175, 282, 215, 109, 389, 428, 428, - 224, 321, 223, 303, 203, 389, 13, 389, 281, 43, - 389, 428, 41, 40, 266, 225, 389, 213, 389, 194, - 389, 52, 4, 308, 301, 383, 34, 209, 222, 3, - 50, 153, 251, 234, 237, 1, 199, 131, 383, 198, - 305, 212, 10, 54, 383, 16, 199, 428, 109, 385, - 132, 18, 224, 321, 223, 222, 221, 12, 32, 428, - 116, 43, 385, 262, 41, 40, 266, 225, 385, 233, - 95, 194, 16, 52, 4, 131, 301, 252, 18, 265, - 164, 3, 50, 324, 251, 234, 237, 1, 23, 130, - 229, 198, 150, 212, 10, 54, 326, 11, 170, 284, - 109, 42, 22, 239, 224, 321, 223, 193, 221, 261, - 13, 52, 157, 43, 301, 286, 41, 40, 266, 225, - 205, 233, 5, 194, 96, 52, 4, 263, 301, 301, - 99, 349, 96, 3, 50, 199, 251, 234, 237, 1, - 238, 130, 241, 181, 349, 212, 10, 54, 382, 240, - 349, 36, 109, 185, 104, 256, 224, 321, 223, 132, - 191, 382, 13, 49, 91, 43, 12, 382, 41, 40, - 266, 225, 257, 233, 152, 194, 457, 52, 4, 457, - 301, 301, 228, 457, 282, 3, 50, 285, 251, 234, - 237, 1, 301, 131, 441, 198, 238, 212, 10, 54, - 349, 441, 325, 175, 109, 30, 349, 273, 224, 321, - 223, 20, 221, 295, 32, 211, 457, 39, 166, 49, - 41, 40, 266, 225, 87, 233, 205, 194, 279, 52, - 4, 24, 301, 204, 200, 280, 99, 3, 50, 199, - 251, 234, 237, 1, 31, 130, 96, 198, 205, 212, - 10, 54, 350, 55, 293, 207, 109, 283, 99, 96, - 224, 321, 223, 199, 180, 350, 13, 134, 230, 43, - 222, 350, 41, 40, 266, 225, 104, 233, 316, 194, - 279, 52, 4, 24, 301, 165, 284, 280, 85, 3, - 50, 25, 251, 234, 237, 1, 131, 129, 210, 198, - 14, 212, 10, 54, 269, 270, 301, 116, 109, 295, - 216, 211, 224, 321, 223, 171, 221, 95, 13, 28, - 219, 43, 323, 9, 41, 40, 266, 225, 151, 233, - 324, 194, 52, 52, 4, 301, 301, 30, 282, 302, - 178, 3, 50, 7, 251, 234, 237, 1, 136, 130, - 304, 179, 238, 212, 10, 54, 279, 175, 282, 24, - 109, 238, 429, 280, 224, 321, 223, 177, 221, 270, - 13, 255, 281, 43, 429, 49, 41, 40, 266, 225, - 275, 233, 318, 194, 49, 52, 4, 276, 301, 163, - 26, 199, 8, 3, 50, 119, 251, 234, 237, 1, - 11, 93, 291, 51, 107, 212, 10, 54, 226, 428, - 206, 201, 109, 148, 178, 322, 224, 321, 223, 441, - 221, 428, 13, 282, 9, 43, 441, 115, 41, 40, - 266, 225, 167, 233, 227, 194, 457, 52, 4, 457, - 301, 96, 158, 457, 101, 3, 50, 271, 251, 234, - 237, 1, 282, 130, 235, 186, 135, 212, 10, 54, - 199, 37, 119, 315, 109, 165, 284, 176, 224, 321, - 223, 104, 221, 149, 13, 281, 146, 43, 281, 300, - 41, 40, 266, 225, 30, 233, 289, 194, 21, 52, - 4, 272, 301, 211, 18, 301, 161, 3, 50, 110, - 251, 234, 237, 1, 137, 128, 282, 198, 268, 212, - 10, 54, 222, 169, 515, 92, 109, 172, 284, 31, - 224, 321, 223, 29, 221, 238, 6, 260, 53, 43, - 232, 139, 41, 40, 266, 225, 154, 233, 178, 194, - 168, 52, 4, 214, 301, 145, 99, 33, 49, 3, - 50, 245, 208, 211, 320, 282, 90, 111, 311, 183, - 98, 70, 309, 297, 236, 178, 95, 319, 142, 258, - 247, 267, 249, 264, 250, 195, 231, 199, 246, 324, - 317, 253, 254, 259, 126, 137, 133, 251, 234, 237, - 1, 326, 290, 105, 143, 156, 212, 10, 54, 88, - 84, 83, 484, 109, 322, 282, 37, 224, 321, 223, - 245, 208, 211, 320, 281, 90, 111, 298, 182, 98, - 56, 245, 298, 211, 178, 95, 103, 147, 258, 197, - 102, 75, 141, 250, 195, 231, 95, 246, 324, 258, - 279, 242, 89, 24, 250, 195, 231, 280, 246, 324, - 298, 298, 298, 298, 298, 298, 298, 16, 298, 192, - 277, 298, 298, 18, 294, 44, 45, 38, 298, 298, - 251, 234, 237, 2, 298, 296, 298, 298, 298, 212, - 10, 54, 310, 312, 313, 314, 109, 162, 298, 298, - 224, 321, 223, 298, 298, 298, 294, 282, 298, 42, - 22, 239, 251, 234, 237, 2, 298, 296, 298, 298, - 298, 212, 10, 54, 298, 159, 298, 298, 109, 298, - 298, 17, 224, 321, 223, 282, 298, 42, 22, 239, - 298, 298, 245, 298, 211, 278, 298, 103, 111, 298, - 183, 98, 70, 298, 298, 298, 298, 95, 298, 298, - 258, 298, 292, 17, 298, 250, 195, 231, 279, 246, - 324, 24, 298, 395, 245, 280, 211, 298, 298, 103, - 298, 298, 197, 102, 75, 16, 298, 140, 298, 95, - 298, 18, 258, 298, 298, 298, 298, 250, 195, 231, - 298, 246, 324, 298, 298, 298, 298, 428, 298, 395, - 395, 395, 202, 277, 298, 245, 298, 211, 298, 428, - 103, 298, 298, 197, 120, 69, 395, 395, 395, 395, - 95, 298, 298, 258, 298, 298, 298, 160, 250, 195, - 231, 86, 246, 324, 245, 16, 211, 282, 298, 103, - 196, 18, 197, 120, 69, 298, 44, 45, 38, 95, - 298, 298, 258, 298, 298, 298, 178, 250, 195, 231, - 298, 246, 324, 310, 312, 313, 314, 298, 298, 190, - 245, 298, 211, 298, 298, 103, 298, 298, 197, 102, - 75, 298, 298, 298, 298, 95, 298, 298, 258, 298, - 298, 298, 298, 250, 195, 231, 298, 246, 324, 298, - 298, 298, 245, 298, 211, 298, 199, 100, 298, 288, - 197, 120, 47, 298, 106, 298, 298, 95, 298, 353, - 258, 155, 298, 218, 298, 250, 195, 231, 298, 246, - 324, 282, 16, 42, 22, 239, 298, 245, 18, 211, - 298, 428, 103, 298, 298, 197, 120, 69, 298, 298, - 298, 298, 95, 428, 298, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 245, 298, 211, 298, - 298, 100, 189, 298, 197, 120, 59, 245, 207, 211, - 298, 95, 103, 298, 258, 197, 120, 81, 298, 250, - 195, 231, 95, 246, 324, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 298, 245, 298, 211, - 298, 298, 103, 298, 298, 197, 120, 80, 298, 298, - 298, 298, 95, 298, 298, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 245, 298, 211, 298, - 298, 103, 298, 298, 197, 120, 67, 245, 298, 211, - 298, 95, 103, 298, 258, 197, 120, 57, 298, 250, - 195, 231, 95, 246, 324, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 298, 245, 298, 211, - 298, 298, 103, 298, 298, 197, 120, 58, 298, 298, - 298, 298, 95, 298, 298, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 245, 298, 211, 298, - 298, 103, 298, 298, 197, 120, 82, 245, 298, 211, - 298, 95, 103, 298, 258, 197, 97, 76, 298, 250, - 195, 231, 95, 246, 324, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 298, 245, 298, 211, - 298, 298, 103, 298, 298, 197, 120, 71, 298, 298, - 298, 298, 95, 298, 298, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 245, 298, 211, 298, - 298, 103, 298, 298, 187, 120, 61, 245, 298, 211, - 298, 95, 103, 298, 258, 197, 120, 63, 298, 250, - 195, 231, 95, 246, 324, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 298, 245, 298, 211, - 298, 298, 103, 298, 298, 197, 94, 79, 298, 298, - 298, 298, 95, 298, 298, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 245, 298, 211, 298, - 298, 103, 298, 298, 197, 120, 59, 245, 298, 211, - 298, 95, 103, 298, 258, 197, 120, 77, 298, 250, - 195, 231, 95, 246, 324, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 298, 245, 298, 211, - 298, 298, 103, 298, 298, 188, 108, 64, 298, 298, - 298, 298, 95, 298, 298, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 245, 298, 211, 298, - 298, 103, 298, 298, 197, 120, 65, 245, 298, 211, - 298, 95, 103, 298, 258, 197, 97, 66, 298, 250, - 195, 231, 95, 246, 324, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 298, 245, 298, 211, - 298, 298, 103, 298, 298, 197, 120, 68, 298, 298, - 298, 298, 95, 298, 298, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 245, 298, 211, 298, - 298, 103, 298, 298, 197, 120, 62, 245, 298, 211, - 298, 95, 103, 298, 258, 197, 120, 60, 298, 250, - 195, 231, 95, 246, 324, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 298, 245, 298, 211, - 298, 298, 103, 298, 298, 197, 120, 74, 298, 298, - 298, 298, 95, 298, 298, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 245, 298, 211, 298, - 298, 103, 298, 298, 197, 120, 72, 245, 298, 211, - 298, 95, 103, 298, 258, 197, 120, 48, 298, 250, - 195, 231, 95, 246, 324, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 298, 245, 298, 211, - 298, 298, 103, 298, 298, 197, 120, 46, 298, 298, - 298, 298, 95, 298, 298, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 245, 298, 211, 298, - 298, 103, 298, 298, 197, 120, 78, 245, 298, 211, - 298, 95, 103, 298, 258, 197, 120, 73, 298, 250, - 195, 231, 95, 246, 324, 258, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 298, 245, 298, 211, - 298, 298, 103, 298, 298, 197, 125, 298, 298, 298, - 298, 298, 95, 298, 298, 298, 298, 298, 298, 244, - 250, 195, 231, 298, 246, 324, 245, 298, 211, 298, - 298, 103, 298, 298, 197, 114, 298, 245, 298, 211, - 298, 95, 103, 298, 298, 197, 122, 298, 243, 250, - 195, 231, 95, 246, 324, 298, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 298, 245, 298, 211, - 298, 298, 103, 298, 298, 197, 117, 298, 298, 298, - 298, 298, 95, 298, 298, 298, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 245, 298, 211, 298, - 298, 103, 298, 298, 197, 121, 298, 245, 298, 211, - 298, 95, 103, 298, 298, 197, 124, 298, 298, 250, - 195, 231, 95, 246, 324, 298, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 298, 245, 298, 211, - 298, 298, 103, 298, 298, 197, 118, 298, 298, 298, - 298, 298, 95, 298, 298, 298, 298, 298, 298, 298, - 250, 195, 231, 298, 246, 324, 245, 298, 211, 298, - 298, 103, 298, 298, 197, 123, 298, 245, 298, 211, - 298, 95, 103, 298, 298, 197, 113, 298, 298, 250, - 195, 231, 95, 246, 324, 298, 298, 298, 298, 298, - 250, 195, 231, 220, 246, 324, 298, 27, 298, 16, - 298, 457, 298, 298, 457, 18, 298, 26, 457, 441, - 44, 45, 38, 217, 44, 45, 38, 298, 298, 298, - 298, 298, 298, 298, 298, 298, 298, 310, 312, 313, - 314, 310, 312, 313, 314, 298, 441, 298, 298, 441, - 298, 457, 220, 441, 457, 298, 298, 457, 298, 298, - 457, 457, 441, 457, 298, 298, 220, 457, 441, 298, - 298, 298, 298, 298, 457, 298, 298, 457, 298, 298, - 5, 457, 441, 298, 298, 298, 298, 298, 298, 441, - 298, 298, 441, 298, 457, 441, 441, 298, 441, 298, - 457, 298, 441, 306, 298, 298, 298, 298, 298, 441, - 298, 298, 441, 298, 457, 220, 441, 298, 298, 298, - 298, 298, 298, 457, 298, 298, 457, 298, 298, 15, - 457, 441, 35, 274, 44, 45, 38, 457, 298, 298, - 457, 298, 298, 298, 457, 441, 298, 298, 298, 298, - 298, 310, 312, 313, 314, 298, 298, 298, 441, 298, - 298, 441, 298, 457, 298, 441, 287, 298, 44, 45, - 38, 298, 441, 298, 298, 441, 298, 457, 298, 441, - 248, 298, 298, 298, 298, 310, 312, 313, 314, 298, - 44, 45, 38, 298, 298, 112, 298, 44, 45, 38, - 298, 173, 298, 298, 44, 45, 38, 310, 312, 313, - 314, 44, 45, 38, 310, 312, 313, 314, 298, 298, - 299, 310, 312, 313, 314, 44, 45, 38, 310, 312, - 313, 314, 174, 298, 298, 298, 138, 298, 298, 298, - 298, 298, 310, 312, 313, 314, 44, 45, 38, 298, - 298, 298, 44, 45, 38, 298, 44, 45, 38, 298, - 44, 45, 38, 310, 312, 313, 314, 307, 298, 310, - 312, 313, 314, 310, 312, 313, 314, 310, 312, 313, - 314, - ); - - public static $yy_lookahead = array( - 10, 11, 12, 13, 74, 15, 36, 17, 1, 19, - 20, 21, 29, 103, 84, 45, 26, 14, 48, 36, - 30, 31, 32, 53, 34, 22, 36, 24, 98, 39, - 27, 48, 42, 43, 44, 45, 33, 47, 35, 49, - 37, 51, 52, 53, 54, 14, 16, 16, 45, 59, - 60, 96, 10, 11, 12, 13, 1, 15, 27, 17, - 53, 19, 20, 21, 33, 27, 1, 36, 26, 14, - 45, 33, 30, 31, 32, 45, 34, 52, 36, 48, - 72, 39, 27, 75, 42, 43, 44, 45, 33, 47, - 82, 49, 27, 51, 52, 15, 54, 17, 33, 91, - 83, 59, 60, 95, 10, 11, 12, 13, 13, 15, - 15, 17, 17, 19, 20, 21, 97, 35, 99, 100, - 26, 86, 87, 88, 30, 31, 32, 66, 34, 49, - 36, 51, 96, 39, 54, 53, 42, 43, 44, 45, - 72, 47, 16, 49, 18, 51, 52, 79, 54, 54, - 82, 14, 18, 59, 60, 1, 10, 11, 12, 13, - 23, 15, 15, 17, 27, 19, 20, 21, 14, 17, - 33, 13, 26, 15, 48, 17, 30, 31, 32, 45, - 34, 27, 36, 46, 83, 39, 52, 33, 42, 43, - 44, 45, 34, 47, 74, 49, 10, 51, 52, 13, - 54, 54, 50, 17, 84, 59, 60, 14, 10, 11, - 12, 13, 54, 15, 45, 17, 23, 19, 20, 21, - 27, 52, 100, 103, 26, 35, 33, 37, 30, 31, - 32, 22, 34, 67, 36, 69, 50, 39, 83, 46, - 42, 43, 44, 45, 35, 47, 72, 49, 10, 51, - 52, 13, 54, 79, 80, 17, 82, 59, 60, 1, - 10, 11, 12, 13, 16, 15, 18, 17, 72, 19, - 20, 21, 14, 107, 108, 79, 26, 71, 82, 18, - 30, 31, 32, 1, 34, 27, 36, 15, 50, 39, - 45, 33, 42, 43, 44, 45, 48, 47, 53, 49, - 10, 51, 52, 13, 54, 99, 100, 17, 36, 59, - 60, 29, 10, 11, 12, 13, 15, 15, 17, 17, - 13, 19, 20, 21, 8, 9, 54, 72, 26, 67, - 75, 69, 30, 31, 32, 78, 34, 82, 36, 24, - 50, 39, 17, 36, 42, 43, 44, 45, 74, 47, - 95, 49, 51, 51, 52, 54, 54, 35, 84, 37, - 103, 59, 60, 36, 10, 11, 12, 13, 74, 15, - 108, 17, 23, 19, 20, 21, 10, 103, 84, 13, - 26, 23, 36, 17, 30, 31, 32, 7, 34, 9, - 36, 17, 98, 39, 48, 46, 42, 43, 44, 45, - 17, 47, 53, 49, 46, 51, 52, 93, 54, 78, - 16, 1, 36, 59, 60, 101, 10, 11, 12, 13, - 35, 15, 37, 17, 48, 19, 20, 21, 18, 36, - 65, 66, 26, 74, 103, 104, 30, 31, 32, 45, - 34, 48, 36, 84, 36, 39, 52, 17, 42, 43, - 44, 45, 15, 47, 17, 49, 10, 51, 52, 13, - 54, 18, 74, 17, 82, 59, 60, 34, 10, 11, - 12, 13, 84, 15, 93, 17, 15, 19, 20, 21, - 1, 2, 101, 101, 26, 99, 100, 17, 30, 31, - 32, 48, 34, 96, 36, 98, 96, 39, 98, 71, - 42, 43, 44, 45, 35, 47, 37, 49, 27, 51, - 52, 67, 54, 69, 33, 54, 74, 59, 60, 17, - 10, 11, 12, 13, 96, 15, 84, 17, 34, 19, - 20, 21, 45, 78, 63, 64, 26, 99, 100, 16, - 30, 31, 32, 16, 34, 23, 36, 17, 17, 39, - 23, 51, 42, 43, 44, 45, 72, 47, 103, 49, - 78, 51, 52, 17, 54, 74, 82, 41, 46, 59, - 60, 67, 68, 69, 70, 84, 72, 73, 53, 75, - 76, 77, 53, 61, 15, 103, 82, 14, 51, 85, - 14, 37, 17, 8, 90, 91, 92, 1, 94, 95, - 3, 4, 5, 6, 7, 96, 82, 10, 11, 12, - 13, 97, 84, 81, 96, 74, 19, 20, 21, 78, - 82, 82, 1, 26, 104, 84, 2, 30, 31, 32, - 67, 68, 69, 70, 98, 72, 73, 109, 75, 76, - 77, 67, 109, 69, 103, 82, 72, 96, 85, 75, - 76, 77, 96, 90, 91, 92, 82, 94, 95, 85, - 10, 14, 96, 13, 90, 91, 92, 17, 94, 95, - 109, 109, 109, 109, 109, 109, 109, 27, 109, 105, - 106, 109, 109, 33, 4, 38, 39, 40, 109, 109, - 10, 11, 12, 13, 109, 15, 109, 109, 109, 19, - 20, 21, 55, 56, 57, 58, 26, 74, 109, 109, - 30, 31, 32, 109, 109, 109, 4, 84, 109, 86, - 87, 88, 10, 11, 12, 13, 109, 15, 109, 109, - 109, 19, 20, 21, 109, 74, 109, 109, 26, 109, - 60, 61, 30, 31, 32, 84, 109, 86, 87, 88, - 109, 109, 67, 109, 69, 70, 109, 72, 73, 109, - 75, 76, 77, 109, 109, 109, 109, 82, 109, 109, - 85, 109, 60, 61, 109, 90, 91, 92, 10, 94, - 95, 13, 109, 2, 67, 17, 69, 109, 109, 72, - 109, 109, 75, 76, 77, 27, 109, 29, 109, 82, - 109, 33, 85, 109, 109, 109, 109, 90, 91, 92, - 109, 94, 95, 109, 109, 109, 109, 36, 109, 38, - 39, 40, 105, 106, 109, 67, 109, 69, 109, 48, - 72, 109, 109, 75, 76, 77, 55, 56, 57, 58, - 82, 109, 109, 85, 109, 109, 109, 74, 90, 91, - 92, 78, 94, 95, 67, 27, 69, 84, 109, 72, - 102, 33, 75, 76, 77, 109, 38, 39, 40, 82, - 109, 109, 85, 109, 109, 109, 103, 90, 91, 92, - 109, 94, 95, 55, 56, 57, 58, 109, 109, 102, - 67, 109, 69, 109, 109, 72, 109, 109, 75, 76, - 77, 109, 109, 109, 109, 82, 109, 109, 85, 109, - 109, 109, 109, 90, 91, 92, 109, 94, 95, 109, - 109, 109, 67, 109, 69, 109, 1, 72, 109, 106, - 75, 76, 77, 109, 79, 109, 109, 82, 109, 14, - 85, 74, 109, 18, 109, 90, 91, 92, 109, 94, - 95, 84, 27, 86, 87, 88, 109, 67, 33, 69, - 109, 36, 72, 109, 109, 75, 76, 77, 109, 109, - 109, 109, 82, 48, 109, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 67, 109, 69, 109, - 109, 72, 102, 109, 75, 76, 77, 67, 79, 69, - 109, 82, 72, 109, 85, 75, 76, 77, 109, 90, - 91, 92, 82, 94, 95, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 109, 67, 109, 69, - 109, 109, 72, 109, 109, 75, 76, 77, 109, 109, - 109, 109, 82, 109, 109, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 67, 109, 69, 109, - 109, 72, 109, 109, 75, 76, 77, 67, 109, 69, - 109, 82, 72, 109, 85, 75, 76, 77, 109, 90, - 91, 92, 82, 94, 95, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 109, 67, 109, 69, - 109, 109, 72, 109, 109, 75, 76, 77, 109, 109, - 109, 109, 82, 109, 109, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 67, 109, 69, 109, - 109, 72, 109, 109, 75, 76, 77, 67, 109, 69, - 109, 82, 72, 109, 85, 75, 76, 77, 109, 90, - 91, 92, 82, 94, 95, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 109, 67, 109, 69, - 109, 109, 72, 109, 109, 75, 76, 77, 109, 109, - 109, 109, 82, 109, 109, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 67, 109, 69, 109, - 109, 72, 109, 109, 75, 76, 77, 67, 109, 69, - 109, 82, 72, 109, 85, 75, 76, 77, 109, 90, - 91, 92, 82, 94, 95, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 109, 67, 109, 69, - 109, 109, 72, 109, 109, 75, 76, 77, 109, 109, - 109, 109, 82, 109, 109, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 67, 109, 69, 109, - 109, 72, 109, 109, 75, 76, 77, 67, 109, 69, - 109, 82, 72, 109, 85, 75, 76, 77, 109, 90, - 91, 92, 82, 94, 95, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 109, 67, 109, 69, - 109, 109, 72, 109, 109, 75, 76, 77, 109, 109, - 109, 109, 82, 109, 109, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 67, 109, 69, 109, - 109, 72, 109, 109, 75, 76, 77, 67, 109, 69, - 109, 82, 72, 109, 85, 75, 76, 77, 109, 90, - 91, 92, 82, 94, 95, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 109, 67, 109, 69, - 109, 109, 72, 109, 109, 75, 76, 77, 109, 109, - 109, 109, 82, 109, 109, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 67, 109, 69, 109, - 109, 72, 109, 109, 75, 76, 77, 67, 109, 69, - 109, 82, 72, 109, 85, 75, 76, 77, 109, 90, - 91, 92, 82, 94, 95, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 109, 67, 109, 69, - 109, 109, 72, 109, 109, 75, 76, 77, 109, 109, - 109, 109, 82, 109, 109, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 67, 109, 69, 109, - 109, 72, 109, 109, 75, 76, 77, 67, 109, 69, - 109, 82, 72, 109, 85, 75, 76, 77, 109, 90, - 91, 92, 82, 94, 95, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 109, 67, 109, 69, - 109, 109, 72, 109, 109, 75, 76, 77, 109, 109, - 109, 109, 82, 109, 109, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 67, 109, 69, 109, - 109, 72, 109, 109, 75, 76, 77, 67, 109, 69, - 109, 82, 72, 109, 85, 75, 76, 77, 109, 90, - 91, 92, 82, 94, 95, 85, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 109, 67, 109, 69, - 109, 109, 72, 109, 109, 75, 76, 109, 109, 109, - 109, 109, 82, 109, 109, 109, 109, 109, 109, 89, - 90, 91, 92, 109, 94, 95, 67, 109, 69, 109, - 109, 72, 109, 109, 75, 76, 109, 67, 109, 69, - 109, 82, 72, 109, 109, 75, 76, 109, 89, 90, - 91, 92, 82, 94, 95, 109, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 109, 67, 109, 69, - 109, 109, 72, 109, 109, 75, 76, 109, 109, 109, - 109, 109, 82, 109, 109, 109, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 67, 109, 69, 109, - 109, 72, 109, 109, 75, 76, 109, 67, 109, 69, - 109, 82, 72, 109, 109, 75, 76, 109, 109, 90, - 91, 92, 82, 94, 95, 109, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 109, 67, 109, 69, - 109, 109, 72, 109, 109, 75, 76, 109, 109, 109, - 109, 109, 82, 109, 109, 109, 109, 109, 109, 109, - 90, 91, 92, 109, 94, 95, 67, 109, 69, 109, - 109, 72, 109, 109, 75, 76, 109, 67, 109, 69, - 109, 82, 72, 109, 109, 75, 76, 109, 109, 90, - 91, 92, 82, 94, 95, 109, 109, 109, 109, 109, - 90, 91, 92, 2, 94, 95, 109, 25, 109, 27, - 109, 10, 109, 109, 13, 33, 109, 16, 17, 18, - 38, 39, 40, 37, 38, 39, 40, 109, 109, 109, - 109, 109, 109, 109, 109, 109, 109, 55, 56, 57, - 58, 55, 56, 57, 58, 109, 45, 109, 109, 48, - 109, 50, 2, 52, 10, 109, 109, 13, 109, 109, - 10, 17, 18, 13, 109, 109, 2, 17, 18, 109, - 109, 109, 109, 109, 10, 109, 109, 13, 109, 109, - 16, 17, 18, 109, 109, 109, 109, 109, 109, 45, - 109, 109, 48, 109, 50, 45, 52, 109, 48, 109, - 50, 109, 52, 53, 109, 109, 109, 109, 109, 45, - 109, 109, 48, 109, 50, 2, 52, 109, 109, 109, - 109, 109, 109, 10, 109, 109, 13, 109, 109, 2, - 17, 18, 2, 37, 38, 39, 40, 10, 109, 109, - 13, 109, 109, 109, 17, 18, 109, 109, 109, 109, - 109, 55, 56, 57, 58, 109, 109, 109, 45, 109, - 109, 48, 109, 50, 109, 52, 14, 109, 38, 39, - 40, 109, 45, 109, 109, 48, 109, 50, 109, 52, - 14, 109, 109, 109, 109, 55, 56, 57, 58, 109, - 38, 39, 40, 109, 109, 22, 109, 38, 39, 40, - 109, 14, 109, 109, 38, 39, 40, 55, 56, 57, - 58, 38, 39, 40, 55, 56, 57, 58, 109, 109, - 61, 55, 56, 57, 58, 38, 39, 40, 55, 56, - 57, 58, 14, 109, 109, 109, 28, 109, 109, 109, - 109, 109, 55, 56, 57, 58, 38, 39, 40, 109, - 109, 109, 38, 39, 40, 109, 38, 39, 40, 109, - 38, 39, 40, 55, 56, 57, 58, 53, 109, 55, - 56, 57, 58, 55, 56, 57, 58, 55, 56, 57, - 58, - ); - - public static $yy_shift_ofst = array( - -31, 406, 406, 458, 458, 94, 510, 94, 94, 94, - 510, 458, -10, 94, 94, 354, 146, 94, 94, 94, - 94, 146, 94, 94, 94, 94, 250, 94, 94, 94, - 94, 94, 94, 302, 94, 94, 94, 198, 42, 42, - 42, 42, 42, 42, 42, 42, 1772, 828, 828, 80, - 712, 925, 301, 65, 272, 680, 1942, 1920, 1886, 1776, - 647, 1949, 1977, 2008, 2004, 1963, 1998, 1956, 2012, 2012, - 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, - 2012, 2012, 2012, 768, 650, 272, 65, 272, 65, 134, - 126, 479, 597, 1854, 154, 290, 95, 55, 258, 366, - 248, 366, 282, 443, 437, 38, 38, 437, 7, 481, - 410, 38, 461, 621, 596, 596, 261, 596, 596, 261, - 596, 596, 596, 596, 596, -31, -31, 1840, 1791, 1917, - 1903, 1834, 158, 238, 394, 446, 38, 25, 147, 169, - 147, 25, 169, 25, 38, 38, 25, 25, 38, 25, - 307, 38, 38, 25, 527, 38, 38, 25, 38, 38, - 38, 38, 38, 596, 624, 261, 624, 327, 596, 596, - 261, 596, 261, -31, -31, -31, -31, -31, -31, 781, - 3, 31, 193, 137, -30, 186, -17, 522, 349, 469, - 322, 30, 82, 316, 346, 376, 190, 358, 393, 152, - 209, 380, 385, 245, 315, 523, 585, 554, 576, 575, - 537, 573, 569, 529, 525, 546, 500, 526, 531, 325, - 530, 487, 494, 502, 470, 433, 430, 408, 383, 327, - 374, - ); - - public static $yy_reduce_ofst = array( - 471, 504, 563, 717, 574, 685, 919, 890, 787, 758, - 855, 823, 1240, 1199, 1140, 1100, 1070, 1129, 1170, 1210, - 1269, 1280, 1310, 1339, 1350, 1380, 1409, 1420, 1450, 1479, - 1490, 1059, 1030, 1000, 930, 960, 989, 1520, 1549, 1700, - 1619, 1689, 1660, 1630, 1590, 1560, 633, 661, 867, 8, - 166, 773, 255, 541, 174, 262, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 294, -70, 196, 120, 68, 274, 19, - 206, 331, 444, 428, 257, 400, 382, 257, 257, 400, - 386, 397, 257, 386, 381, 388, 359, 314, 257, 442, - 482, 491, 484, 257, 257, 455, 386, 257, 257, 438, - 257, 257, 257, 257, 257, 257, 365, 509, 509, 509, - 509, 509, 524, 536, 509, 509, 528, 514, 539, 551, - 538, 514, 556, 514, 528, 528, 514, 514, 528, 514, - 518, 528, 528, 514, 532, 528, 528, 514, 528, 528, - 528, 528, 528, -90, 520, 122, 520, 566, -90, -90, - 122, -90, 122, -45, 36, 155, 101, 61, 17, - ); - - public static $yyExpectedTokens = array( - array(), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 53, 54, 59, - 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array( - 10, 11, 12, 13, 15, 17, 19, 20, 21, 26, 30, 31, 32, 34, 36, 39, 42, 43, 44, 45, 47, 49, 51, 52, 54, 59, 60, - ), - array(25, 27, 33, 38, 39, 40, 55, 56, 57, 58,), - array(27, 33, 38, 39, 40, 55, 56, 57, 58,), - array(27, 33, 38, 39, 40, 55, 56, 57, 58,), - array(15, 17, 49, 51, 54,), - array(4, 10, 11, 12, 13, 15, 19, 20, 21, 26, 30, 31, 32, 60, 61,), - array(1, 14, 18, 27, 33, 36, 48,), - array(15, 17, 51, 54,), - array(1, 27, 33,), - array(15, 36, 54,), - array(4, 10, 11, 12, 13, 15, 19, 20, 21, 26, 30, 31, 32, 60, 61,), - array(14, 38, 39, 40, 55, 56, 57, 58,), - array(2, 38, 39, 40, 55, 56, 57, 58,), - array(37, 38, 39, 40, 55, 56, 57, 58,), - array(37, 38, 39, 40, 55, 56, 57, 58,), - array(14, 38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58, 61,), - array(14, 38, 39, 40, 55, 56, 57, 58,), - array(14, 38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 53, 55, 56, 57, 58,), - array(22, 38, 39, 40, 55, 56, 57, 58,), - array(28, 38, 39, 40, 55, 56, 57, 58,), - array(14, 38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(38, 39, 40, 55, 56, 57, 58,), - array(10, 13, 17, 27, 29, 33,), - array(10, 13, 17, 27, 33,), - array(15, 36, 54,), - array(1, 27, 33,), - array(15, 36, 54,), - array(1, 27, 33,), - array(18, 45, 52,), - array(16, 18, 48,), - array(1, 2,), - array(3, 4, 5, 6, 7, 10, 11, 12, 13, 19, 20, 21, 26, 30, 31, 32,), - array(2, 10, 13, 16, 17, 18, 45, 48, 50, 52,), - array(1, 14, 27, 33,), - array(10, 13, 17, 50,), - array(13, 15, 17, 54,), - array(1, 14, 27, 33,), - array(1, 14, 27, 33,), - array(10, 13, 17,), - array(16, 18, 48,), - array(10, 13, 17,), - array(1, 29,), - array(18, 48,), - array(15, 17,), - array(27, 33,), - array(27, 33,), - array(15, 17,), - array(1, 53,), - array(27, 33,), - array(1, 18,), - array(27, 33,), - array(15, 54,), - array(1,), - array(1,), - array(1,), - array(18,), - array(1,), - array(1,), - array(18,), - array(1,), - array(1,), - array(1,), - array(1,), - array(1,), - array(), - array(), - array(2, 10, 13, 17, 18, 45, 48, 50, 52, 53,), - array(2, 10, 13, 16, 17, 18, 45, 48, 50, 52,), - array(2, 10, 13, 17, 18, 45, 48, 50, 52,), - array(2, 10, 13, 17, 18, 45, 48, 50, 52,), - array(10, 13, 17, 18, 45, 48, 50, 52,), - array(13, 15, 17, 34, 54,), - array(10, 13, 17, 50,), - array(16, 45, 52,), - array(10, 13, 17,), - array(27, 33,), - array(45, 52,), - array(15, 54,), - array(45, 52,), - array(15, 54,), - array(45, 52,), - array(45, 52,), - array(45, 52,), - array(27, 33,), - array(27, 33,), - array(45, 52,), - array(45, 52,), - array(27, 33,), - array(45, 52,), - array(13, 36,), - array(27, 33,), - array(27, 33,), - array(45, 52,), - array(16, 23,), - array(27, 33,), - array(27, 33,), - array(45, 52,), - array(27, 33,), - array(27, 33,), - array(27, 33,), - array(27, 33,), - array(27, 33,), - array(1,), - array(2,), - array(18,), - array(2,), - array(36,), - array(1,), - array(1,), - array(18,), - array(1,), - array(18,), - array(), - array(), - array(), - array(), - array(), - array(), - array(2, 36, 38, 39, 40, 48, 55, 56, 57, 58,), - array(14, 22, 24, 27, 33, 35, 37, 45,), - array(14, 16, 27, 33, 36, 48,), - array(14, 23, 27, 33, 46,), - array(14, 23, 27, 33, 46,), - array(36, 45, 48, 53,), - array(10, 13, 17, 50,), - array(29, 36, 48,), - array(23, 46, 61,), - array(23, 46, 53,), - array(35, 37,), - array(35, 37,), - array(16, 45,), - array(35, 53,), - array(8, 9,), - array(36, 48,), - array(36, 48,), - array(35, 37,), - array(23, 46,), - array(36, 48,), - array(17, 50,), - array(22, 35,), - array(7, 9,), - array(35, 37,), - array(45, 53,), - array(24,), - array(16,), - array(8,), - array(37,), - array(14,), - array(17,), - array(51,), - array(14,), - array(15,), - array(53,), - array(53,), - array(17,), - array(51,), - array(41,), - array(17,), - array(17,), - array(17,), - array(45,), - array(34,), - array(17,), - array(17,), - array(34,), - array(17,), - array(36,), - array(17,), - array(36,), - array(17,), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array(), - ); - - public static $yy_default = array( - 338, 514, 514, 499, 499, 514, 514, 476, 476, 476, - 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, - 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, - 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, - 514, 514, 514, 514, 514, 514, 379, 358, 379, 514, - 514, 415, 514, 379, 514, 514, 351, 514, 514, 514, - 514, 514, 514, 514, 514, 514, 384, 514, 399, 475, - 351, 403, 390, 474, 500, 502, 384, 501, 363, 381, - 404, 386, 391, 379, 379, 514, 379, 514, 379, 489, - 431, 370, 327, 430, 393, 441, 514, 393, 393, 441, - 431, 441, 393, 431, 514, 379, 360, 514, 393, 379, - 373, 379, 514, 406, 402, 375, 431, 396, 398, 486, - 393, 408, 397, 407, 406, 483, 336, 430, 430, 430, - 430, 430, 514, 443, 457, 441, 367, 438, 514, 436, - 514, 435, 434, 466, 368, 348, 439, 437, 361, 467, - 441, 356, 354, 468, 514, 366, 355, 469, 362, 359, - 352, 369, 365, 371, 478, 463, 477, 441, 374, 376, - 490, 424, 487, 441, 441, 482, 482, 336, 482, 415, - 411, 415, 405, 405, 415, 442, 415, 405, 405, 514, - 514, 411, 514, 514, 425, 514, 514, 405, 415, 514, - 514, 334, 514, 411, 387, 514, 514, 514, 514, 514, - 514, 514, 514, 420, 514, 514, 514, 417, 514, 514, - 514, 411, 413, 514, 514, 514, 514, 488, 514, 457, - 514, 421, 364, 420, 340, 422, 357, 341, 409, 400, - 480, 457, 462, 401, 485, 423, 426, 342, 447, 380, - 416, 339, 428, 329, 330, 444, 445, 446, 394, 331, - 395, 429, 419, 388, 332, 418, 410, 392, 412, 333, - 335, 414, 337, 472, 417, 479, 427, 497, 347, 461, - 460, 459, 378, 346, 464, 510, 495, 511, 498, 473, - 377, 496, 503, 506, 513, 512, 509, 507, 504, 508, - 345, 458, 471, 448, 505, 454, 452, 455, 456, 450, - 491, 449, 492, 493, 494, 470, 451, 328, 453, 343, - 344, 372, 481, 432, 433, 465, 440, - ); - - public static $yyFallback = array(); - - public static $yyRuleName = array( - 'start ::= template', - 'template ::= template PHP', - 'template ::= template TEXT', - 'template ::= template STRIPON', - 'template ::= template STRIPOFF', - 'template ::= template LITERALSTART literal_e2 LITERALEND', - 'literal_e2 ::= literal_e1 LITERALSTART literal_e1 LITERALEND', - 'literal_e2 ::= literal_e1', - 'literal_e1 ::= literal_e1 LITERAL', - 'literal_e1 ::=', - 'template ::= template smartytag', - 'template ::=', - 'smartytag ::= SIMPELOUTPUT', - 'smartytag ::= SIMPLETAG', - 'smartytag ::= SMARTYBLOCKCHILDPARENT', - 'smartytag ::= LDEL tagbody RDEL', - 'smartytag ::= tag RDEL', - 'tagbody ::= outattr', - 'tagbody ::= DOLLARID eqoutattr', - 'tagbody ::= varindexed eqoutattr', - 'eqoutattr ::= EQUAL outattr', - 'outattr ::= output attributes', - 'output ::= variable', - 'output ::= value', - 'output ::= expr', - 'tag ::= LDEL ID attributes', - 'tag ::= LDEL ID', - 'tag ::= LDEL ID modifierlist attributes', - 'tag ::= LDEL ID PTR ID attributes', - 'tag ::= LDEL ID PTR ID modifierlist attributes', - 'tag ::= LDELMAKENOCACHE DOLLARID', - 'tag ::= LDELIF expr', - 'tag ::= LDELIF expr attributes', - 'tag ::= LDELIF statement', - 'tag ::= LDELIF statement attributes', - 'tag ::= LDELFOR statements SEMICOLON expr SEMICOLON varindexed foraction attributes', - 'foraction ::= EQUAL expr', - 'foraction ::= INCDEC', - 'tag ::= LDELFOR statement TO expr attributes', - 'tag ::= LDELFOR statement TO expr STEP expr attributes', - 'tag ::= LDELFOREACH SPACE expr AS varvar attributes', - 'tag ::= LDELFOREACH SPACE expr AS varvar APTR varvar attributes', - 'tag ::= LDELFOREACH attributes', - 'tag ::= LDELSETFILTER ID modparameters', - 'tag ::= LDELSETFILTER ID modparameters modifierlist', - 'smartytag ::= CLOSETAG', - 'tag ::= LDELSLASH ID', - 'tag ::= LDELSLASH ID modifierlist', - 'tag ::= LDELSLASH ID PTR ID', - 'tag ::= LDELSLASH ID PTR ID modifierlist', - 'attributes ::= attributes attribute', - 'attributes ::= attribute', - 'attributes ::=', - 'attribute ::= SPACE ID EQUAL ID', - 'attribute ::= ATTR expr', - 'attribute ::= ATTR value', - 'attribute ::= SPACE ID', - 'attribute ::= SPACE expr', - 'attribute ::= SPACE value', - 'attribute ::= SPACE INTEGER EQUAL expr', - 'statements ::= statement', - 'statements ::= statements COMMA statement', - 'statement ::= DOLLARID EQUAL INTEGER', - 'statement ::= DOLLARID EQUAL expr', - 'statement ::= varindexed EQUAL expr', - 'statement ::= OPENP statement CLOSEP', - 'expr ::= value', - 'expr ::= ternary', - 'expr ::= DOLLARID COLON ID', - 'expr ::= expr MATH value', - 'expr ::= expr UNIMATH value', - 'expr ::= expr tlop value', - 'expr ::= expr lop expr', - 'expr ::= expr scond', - 'expr ::= expr ISIN array', - 'expr ::= expr ISIN value', - 'ternary ::= OPENP expr CLOSEP QMARK DOLLARID COLON expr', - 'ternary ::= OPENP expr CLOSEP QMARK expr COLON expr', - 'value ::= variable', - 'value ::= UNIMATH value', - 'value ::= NOT value', - 'value ::= TYPECAST value', - 'value ::= variable INCDEC', - 'value ::= HEX', - 'value ::= INTEGER', - 'value ::= INTEGER DOT INTEGER', - 'value ::= INTEGER DOT', - 'value ::= DOT INTEGER', - 'value ::= ID', - 'value ::= function', - 'value ::= OPENP expr CLOSEP', - 'value ::= variable INSTANCEOF ns1', - 'value ::= variable INSTANCEOF variable', - 'value ::= SINGLEQUOTESTRING', - 'value ::= doublequoted_with_quotes', - 'value ::= varindexed DOUBLECOLON static_class_access', - 'value ::= smartytag', - 'value ::= value modifierlist', - 'value ::= NAMESPACE', - 'value ::= arraydef', - 'value ::= ns1 DOUBLECOLON static_class_access', - 'ns1 ::= ID', - 'ns1 ::= NAMESPACE', - 'variable ::= DOLLARID', - 'variable ::= varindexed', - 'variable ::= varvar AT ID', - 'variable ::= object', - 'variable ::= HATCH ID HATCH', - 'variable ::= HATCH ID HATCH arrayindex', - 'variable ::= HATCH variable HATCH', - 'variable ::= HATCH variable HATCH arrayindex', - 'varindexed ::= DOLLARID arrayindex', - 'varindexed ::= varvar arrayindex', - 'arrayindex ::= arrayindex indexdef', - 'arrayindex ::=', - 'indexdef ::= DOT DOLLARID', - 'indexdef ::= DOT varvar', - 'indexdef ::= DOT varvar AT ID', - 'indexdef ::= DOT ID', - 'indexdef ::= DOT INTEGER', - 'indexdef ::= DOT LDEL expr RDEL', - 'indexdef ::= OPENB ID CLOSEB', - 'indexdef ::= OPENB ID DOT ID CLOSEB', - 'indexdef ::= OPENB SINGLEQUOTESTRING CLOSEB', - 'indexdef ::= OPENB INTEGER CLOSEB', - 'indexdef ::= OPENB DOLLARID CLOSEB', - 'indexdef ::= OPENB variable CLOSEB', - 'indexdef ::= OPENB value CLOSEB', - 'indexdef ::= OPENB expr CLOSEB', - 'indexdef ::= OPENB CLOSEB', - 'varvar ::= DOLLARID', - 'varvar ::= DOLLAR', - 'varvar ::= varvar varvarele', - 'varvarele ::= ID', - 'varvarele ::= SIMPELOUTPUT', - 'varvarele ::= LDEL expr RDEL', - 'object ::= varindexed objectchain', - 'objectchain ::= objectelement', - 'objectchain ::= objectchain objectelement', - 'objectelement ::= PTR ID arrayindex', - 'objectelement ::= PTR varvar arrayindex', - 'objectelement ::= PTR LDEL expr RDEL arrayindex', - 'objectelement ::= PTR ID LDEL expr RDEL arrayindex', - 'objectelement ::= PTR method', - 'function ::= ns1 OPENP params CLOSEP', - 'method ::= ID OPENP params CLOSEP', - 'method ::= DOLLARID OPENP params CLOSEP', - 'params ::= params COMMA expr', - 'params ::= expr', - 'params ::=', - 'modifierlist ::= modifierlist modifier modparameters', - 'modifierlist ::= modifier modparameters', - 'modifier ::= VERT AT ID', - 'modifier ::= VERT ID', - 'modparameters ::= modparameters modparameter', - 'modparameters ::=', - 'modparameter ::= COLON value', - 'modparameter ::= COLON UNIMATH value', - 'modparameter ::= COLON array', - 'static_class_access ::= method', - 'static_class_access ::= method objectchain', - 'static_class_access ::= ID', - 'static_class_access ::= DOLLARID arrayindex', - 'static_class_access ::= DOLLARID arrayindex objectchain', - 'lop ::= LOGOP', - 'lop ::= SLOGOP', - 'tlop ::= TLOGOP', - 'scond ::= SINGLECOND', - 'arraydef ::= OPENB arrayelements CLOSEB', - 'arraydef ::= ARRAYOPEN arrayelements CLOSEP', - 'arrayelements ::= arrayelement', - 'arrayelements ::= arrayelements COMMA arrayelement', - 'arrayelements ::=', - 'arrayelement ::= value APTR expr', - 'arrayelement ::= ID APTR expr', - 'arrayelement ::= expr', - 'doublequoted_with_quotes ::= QUOTE QUOTE', - 'doublequoted_with_quotes ::= QUOTE doublequoted QUOTE', - 'doublequoted ::= doublequoted doublequotedcontent', - 'doublequoted ::= doublequotedcontent', - 'doublequotedcontent ::= BACKTICK variable BACKTICK', - 'doublequotedcontent ::= BACKTICK expr BACKTICK', - 'doublequotedcontent ::= DOLLARID', - 'doublequotedcontent ::= LDEL variable RDEL', - 'doublequotedcontent ::= LDEL expr RDEL', - 'doublequotedcontent ::= smartytag', - 'doublequotedcontent ::= TEXT', - ); - - public static $yyRuleInfo = array( - array(0 => 63, 1 => 1), - array(0 => 64, 1 => 2), - array(0 => 64, 1 => 2), - array(0 => 64, 1 => 2), - array(0 => 64, 1 => 2), - array(0 => 64, 1 => 4), - array(0 => 65, 1 => 4), - array(0 => 65, 1 => 1), - array(0 => 66, 1 => 2), - array(0 => 66, 1 => 0), - array(0 => 64, 1 => 2), - array(0 => 64, 1 => 0), - array(0 => 67, 1 => 1), - array(0 => 67, 1 => 1), - array(0 => 67, 1 => 1), - array(0 => 67, 1 => 3), - array(0 => 67, 1 => 2), - array(0 => 68, 1 => 1), - array(0 => 68, 1 => 2), - array(0 => 68, 1 => 2), - array(0 => 71, 1 => 2), - array(0 => 70, 1 => 2), - array(0 => 73, 1 => 1), - array(0 => 73, 1 => 1), - array(0 => 73, 1 => 1), - array(0 => 69, 1 => 3), - array(0 => 69, 1 => 2), - array(0 => 69, 1 => 4), - array(0 => 69, 1 => 5), - array(0 => 69, 1 => 6), - array(0 => 69, 1 => 2), - array(0 => 69, 1 => 2), - array(0 => 69, 1 => 3), - array(0 => 69, 1 => 2), - array(0 => 69, 1 => 3), - array(0 => 69, 1 => 8), - array(0 => 81, 1 => 2), - array(0 => 81, 1 => 1), - array(0 => 69, 1 => 5), - array(0 => 69, 1 => 7), - array(0 => 69, 1 => 6), - array(0 => 69, 1 => 8), - array(0 => 69, 1 => 2), - array(0 => 69, 1 => 3), - array(0 => 69, 1 => 4), - array(0 => 67, 1 => 1), - array(0 => 69, 1 => 2), - array(0 => 69, 1 => 3), - array(0 => 69, 1 => 4), - array(0 => 69, 1 => 5), - array(0 => 74, 1 => 2), - array(0 => 74, 1 => 1), - array(0 => 74, 1 => 0), - array(0 => 84, 1 => 4), - array(0 => 84, 1 => 2), - array(0 => 84, 1 => 2), - array(0 => 84, 1 => 2), - array(0 => 84, 1 => 2), - array(0 => 84, 1 => 2), - array(0 => 84, 1 => 4), - array(0 => 80, 1 => 1), - array(0 => 80, 1 => 3), - array(0 => 79, 1 => 3), - array(0 => 79, 1 => 3), - array(0 => 79, 1 => 3), - array(0 => 79, 1 => 3), - array(0 => 77, 1 => 1), - array(0 => 77, 1 => 1), - array(0 => 77, 1 => 3), - array(0 => 77, 1 => 3), - array(0 => 77, 1 => 3), - array(0 => 77, 1 => 3), - array(0 => 77, 1 => 3), - array(0 => 77, 1 => 2), - array(0 => 77, 1 => 3), - array(0 => 77, 1 => 3), - array(0 => 85, 1 => 7), - array(0 => 85, 1 => 7), - array(0 => 76, 1 => 1), - array(0 => 76, 1 => 2), - array(0 => 76, 1 => 2), - array(0 => 76, 1 => 2), - array(0 => 76, 1 => 2), - array(0 => 76, 1 => 1), - array(0 => 76, 1 => 1), - array(0 => 76, 1 => 3), - array(0 => 76, 1 => 2), - array(0 => 76, 1 => 2), - array(0 => 76, 1 => 1), - array(0 => 76, 1 => 1), - array(0 => 76, 1 => 3), - array(0 => 76, 1 => 3), - array(0 => 76, 1 => 3), - array(0 => 76, 1 => 1), - array(0 => 76, 1 => 1), - array(0 => 76, 1 => 3), - array(0 => 76, 1 => 1), - array(0 => 76, 1 => 2), - array(0 => 76, 1 => 1), - array(0 => 76, 1 => 1), - array(0 => 76, 1 => 3), - array(0 => 91, 1 => 1), - array(0 => 91, 1 => 1), - array(0 => 75, 1 => 1), - array(0 => 75, 1 => 1), - array(0 => 75, 1 => 3), - array(0 => 75, 1 => 1), - array(0 => 75, 1 => 3), - array(0 => 75, 1 => 4), - array(0 => 75, 1 => 3), - array(0 => 75, 1 => 4), - array(0 => 72, 1 => 2), - array(0 => 72, 1 => 2), - array(0 => 96, 1 => 2), - array(0 => 96, 1 => 0), - array(0 => 97, 1 => 2), - array(0 => 97, 1 => 2), - array(0 => 97, 1 => 4), - array(0 => 97, 1 => 2), - array(0 => 97, 1 => 2), - array(0 => 97, 1 => 4), - array(0 => 97, 1 => 3), - array(0 => 97, 1 => 5), - array(0 => 97, 1 => 3), - array(0 => 97, 1 => 3), - array(0 => 97, 1 => 3), - array(0 => 97, 1 => 3), - array(0 => 97, 1 => 3), - array(0 => 97, 1 => 3), - array(0 => 97, 1 => 2), - array(0 => 82, 1 => 1), - array(0 => 82, 1 => 1), - array(0 => 82, 1 => 2), - array(0 => 98, 1 => 1), - array(0 => 98, 1 => 1), - array(0 => 98, 1 => 3), - array(0 => 95, 1 => 2), - array(0 => 99, 1 => 1), - array(0 => 99, 1 => 2), - array(0 => 100, 1 => 3), - array(0 => 100, 1 => 3), - array(0 => 100, 1 => 5), - array(0 => 100, 1 => 6), - array(0 => 100, 1 => 2), - array(0 => 90, 1 => 4), - array(0 => 101, 1 => 4), - array(0 => 101, 1 => 4), - array(0 => 102, 1 => 3), - array(0 => 102, 1 => 1), - array(0 => 102, 1 => 0), - array(0 => 78, 1 => 3), - array(0 => 78, 1 => 2), - array(0 => 103, 1 => 3), - array(0 => 103, 1 => 2), - array(0 => 83, 1 => 2), - array(0 => 83, 1 => 0), - array(0 => 104, 1 => 2), - array(0 => 104, 1 => 3), - array(0 => 104, 1 => 2), - array(0 => 93, 1 => 1), - array(0 => 93, 1 => 2), - array(0 => 93, 1 => 1), - array(0 => 93, 1 => 2), - array(0 => 93, 1 => 3), - array(0 => 87, 1 => 1), - array(0 => 87, 1 => 1), - array(0 => 86, 1 => 1), - array(0 => 88, 1 => 1), - array(0 => 94, 1 => 3), - array(0 => 94, 1 => 3), - array(0 => 105, 1 => 1), - array(0 => 105, 1 => 3), - array(0 => 105, 1 => 0), - array(0 => 106, 1 => 3), - array(0 => 106, 1 => 3), - array(0 => 106, 1 => 1), - array(0 => 92, 1 => 2), - array(0 => 92, 1 => 3), - array(0 => 107, 1 => 2), - array(0 => 107, 1 => 1), - array(0 => 108, 1 => 3), - array(0 => 108, 1 => 3), - array(0 => 108, 1 => 1), - array(0 => 108, 1 => 3), - array(0 => 108, 1 => 3), - array(0 => 108, 1 => 1), - array(0 => 108, 1 => 1), - ); - - public static $yyReduceMap = array( - 0 => 0, - 1 => 1, - 2 => 2, - 3 => 3, - 4 => 4, - 5 => 5, - 6 => 6, - 7 => 7, - 22 => 7, - 23 => 7, - 24 => 7, - 37 => 7, - 57 => 7, - 58 => 7, - 66 => 7, - 67 => 7, - 78 => 7, - 83 => 7, - 84 => 7, - 89 => 7, - 93 => 7, - 94 => 7, - 98 => 7, - 99 => 7, - 101 => 7, - 106 => 7, - 170 => 7, - 175 => 7, - 8 => 8, - 9 => 9, - 10 => 10, - 12 => 12, - 13 => 13, - 14 => 14, - 15 => 15, - 16 => 16, - 17 => 17, - 18 => 18, - 19 => 19, - 20 => 20, - 21 => 21, - 25 => 25, - 26 => 26, - 27 => 27, - 28 => 28, - 29 => 29, - 30 => 30, - 31 => 31, - 32 => 32, - 34 => 32, - 33 => 33, - 35 => 35, - 36 => 36, - 38 => 38, - 39 => 39, - 40 => 40, - 41 => 41, - 42 => 42, - 43 => 43, - 44 => 44, - 45 => 45, - 46 => 46, - 47 => 47, - 48 => 48, - 49 => 49, - 50 => 50, - 51 => 51, - 60 => 51, - 148 => 51, - 152 => 51, - 156 => 51, - 158 => 51, - 52 => 52, - 149 => 52, - 155 => 52, - 53 => 53, - 54 => 54, - 55 => 54, - 56 => 56, - 133 => 56, - 59 => 59, - 61 => 61, - 62 => 62, - 63 => 62, - 64 => 64, - 65 => 65, - 68 => 68, - 69 => 69, - 70 => 69, - 71 => 71, - 72 => 72, - 73 => 73, - 74 => 74, - 75 => 75, - 76 => 76, - 77 => 77, - 79 => 79, - 81 => 79, - 82 => 79, - 113 => 79, - 80 => 80, - 85 => 85, - 86 => 86, - 87 => 87, - 88 => 88, - 90 => 90, - 91 => 91, - 92 => 91, - 95 => 95, - 96 => 96, - 97 => 97, - 100 => 100, - 102 => 102, - 103 => 103, - 104 => 104, - 105 => 105, - 107 => 107, - 108 => 108, - 109 => 109, - 110 => 110, - 111 => 111, - 112 => 112, - 114 => 114, - 172 => 114, - 115 => 115, - 116 => 116, - 117 => 117, - 118 => 118, - 119 => 119, - 120 => 120, - 128 => 120, - 121 => 121, - 122 => 122, - 123 => 123, - 124 => 123, - 126 => 123, - 127 => 123, - 125 => 125, - 129 => 129, - 130 => 130, - 131 => 131, - 176 => 131, - 132 => 132, - 134 => 134, - 135 => 135, - 136 => 136, - 137 => 137, - 138 => 138, - 139 => 139, - 140 => 140, - 141 => 141, - 142 => 142, - 143 => 143, - 144 => 144, - 145 => 145, - 146 => 146, - 147 => 147, - 150 => 150, - 151 => 151, - 153 => 153, - 154 => 154, - 157 => 157, - 159 => 159, - 160 => 160, - 161 => 161, - 162 => 162, - 163 => 163, - 164 => 164, - 165 => 165, - 166 => 166, - 167 => 167, - 168 => 168, - 169 => 168, - 171 => 171, - 173 => 173, - 174 => 174, - 177 => 177, - 178 => 178, - 179 => 179, - 180 => 180, - 183 => 180, - 181 => 181, - 184 => 181, - 182 => 182, - 185 => 185, - 186 => 186, - ); + const ERR1 = 'Security error: Call to private object member not allowed'; + const ERR2 = 'Security error: Call to dynamic object member not allowed'; /** * result status @@ -1654,13 +81,19 @@ class Smarty_Internal_Templateparser */ public $lex; + /** + * internal error flag + * + * @var bool + */ + private $internalError = false; + /** * {strip} status * * @var bool */ public $strip = false; - /** * compiler object * @@ -1710,54 +143,6 @@ class Smarty_Internal_Templateparser */ public $template_postfix = array(); - public $yyTraceFILE; - - public $yyTracePrompt; - - public $yyidx; - - public $yyerrcnt; - - public $yystack = array(); - - public $yyTokenName = array( - '$', 'VERT', 'COLON', 'PHP', - 'TEXT', 'STRIPON', 'STRIPOFF', 'LITERALSTART', - 'LITERALEND', 'LITERAL', 'SIMPELOUTPUT', 'SIMPLETAG', - 'SMARTYBLOCKCHILDPARENT', 'LDEL', 'RDEL', 'DOLLARID', - 'EQUAL', 'ID', 'PTR', 'LDELMAKENOCACHE', - 'LDELIF', 'LDELFOR', 'SEMICOLON', 'INCDEC', - 'TO', 'STEP', 'LDELFOREACH', 'SPACE', - 'AS', 'APTR', 'LDELSETFILTER', 'CLOSETAG', - 'LDELSLASH', 'ATTR', 'INTEGER', 'COMMA', - 'OPENP', 'CLOSEP', 'MATH', 'UNIMATH', - 'ISIN', 'QMARK', 'NOT', 'TYPECAST', - 'HEX', 'DOT', 'INSTANCEOF', 'SINGLEQUOTESTRING', - 'DOUBLECOLON', 'NAMESPACE', 'AT', 'HATCH', - 'OPENB', 'CLOSEB', 'DOLLAR', 'LOGOP', - 'SLOGOP', 'TLOGOP', 'SINGLECOND', 'ARRAYOPEN', - 'QUOTE', 'BACKTICK', 'error', 'start', - 'template', 'literal_e2', 'literal_e1', 'smartytag', - 'tagbody', 'tag', 'outattr', 'eqoutattr', - 'varindexed', 'output', 'attributes', 'variable', - 'value', 'expr', 'modifierlist', 'statement', - 'statements', 'foraction', 'varvar', 'modparameters', - 'attribute', 'ternary', 'tlop', 'lop', - 'scond', 'array', 'function', 'ns1', - 'doublequoted_with_quotes', 'static_class_access', 'arraydef', 'object', - 'arrayindex', 'indexdef', 'varvarele', 'objectchain', - 'objectelement', 'method', 'params', 'modifier', - 'modparameter', 'arrayelements', 'arrayelement', 'doublequoted', - 'doublequotedcontent', - ); - - /** - * internal error flag - * - * @var bool - */ - private $internalError = false; /* Index of top element in stack */ - private $_retvalue; /* Shifts left before out of the error */ /** * constructor * @@ -1772,16 +157,9 @@ class Smarty_Internal_Templateparser $this->smarty = $this->template->smarty; $this->security = isset($this->smarty->security_policy) ? $this->smarty->security_policy : false; $this->current_buffer = $this->root_buffer = new Smarty_Internal_ParseTree_Template(); - } /* The parser's stack */ - public static function yy_destructor($yymajor, $yypminor) - { - switch ($yymajor) { - default: - break; /* If no destructor action specified: do nothing */ - } } - /** + /** * insert PHP code in current buffer * * @param string $code @@ -1823,6 +201,898 @@ class Smarty_Internal_Templateparser return new Smarty_Internal_ParseTree_Tag($this, $this->compiler->processNocacheCode($tmp, true)); } + + const TP_VERT = 1; + const TP_COLON = 2; + const TP_TEXT = 3; + const TP_STRIPON = 4; + const TP_STRIPOFF = 5; + const TP_LITERALSTART = 6; + const TP_LITERALEND = 7; + const TP_LITERAL = 8; + const TP_SIMPELOUTPUT = 9; + const TP_SIMPLETAG = 10; + const TP_SMARTYBLOCKCHILDPARENT = 11; + const TP_LDEL = 12; + const TP_RDEL = 13; + const TP_DOLLARID = 14; + const TP_EQUAL = 15; + const TP_ID = 16; + const TP_PTR = 17; + const TP_LDELMAKENOCACHE = 18; + const TP_LDELIF = 19; + const TP_LDELFOR = 20; + const TP_SEMICOLON = 21; + const TP_INCDEC = 22; + const TP_TO = 23; + const TP_STEP = 24; + const TP_LDELFOREACH = 25; + const TP_SPACE = 26; + const TP_AS = 27; + const TP_APTR = 28; + const TP_LDELSETFILTER = 29; + const TP_CLOSETAG = 30; + const TP_LDELSLASH = 31; + const TP_ATTR = 32; + const TP_INTEGER = 33; + const TP_COMMA = 34; + const TP_OPENP = 35; + const TP_CLOSEP = 36; + const TP_MATH = 37; + const TP_UNIMATH = 38; + const TP_ISIN = 39; + const TP_QMARK = 40; + const TP_NOT = 41; + const TP_TYPECAST = 42; + const TP_HEX = 43; + const TP_DOT = 44; + const TP_INSTANCEOF = 45; + const TP_SINGLEQUOTESTRING = 46; + const TP_DOUBLECOLON = 47; + const TP_NAMESPACE = 48; + const TP_AT = 49; + const TP_HATCH = 50; + const TP_OPENB = 51; + const TP_CLOSEB = 52; + const TP_DOLLAR = 53; + const TP_LOGOP = 54; + const TP_SLOGOP = 55; + const TP_TLOGOP = 56; + const TP_SINGLECOND = 57; + const TP_ARRAYOPEN = 58; + const TP_QUOTE = 59; + const TP_BACKTICK = 60; + const YY_NO_ACTION = 514; + const YY_ACCEPT_ACTION = 513; + const YY_ERROR_ACTION = 512; + + const YY_SZ_ACTTAB = 1997; +public static $yy_action = array( + 249, 250, 239, 1, 27, 127, 220, 184, 160, 213, + 11, 54, 278, 10, 173, 34, 108, 387, 282, 279, + 223, 321, 221, 8, 194, 387, 18, 387, 85, 41, + 387, 285, 42, 44, 264, 222, 387, 209, 387, 198, + 387, 52, 5, 307, 288, 288, 164, 283, 224, 4, + 50, 249, 250, 239, 1, 232, 131, 381, 189, 205, + 213, 11, 54, 39, 35, 243, 31, 108, 94, 17, + 381, 223, 321, 221, 439, 226, 381, 33, 49, 426, + 41, 439, 89, 42, 44, 264, 222, 9, 235, 163, + 198, 426, 52, 5, 131, 288, 212, 284, 102, 106, + 4, 50, 249, 250, 239, 1, 232, 129, 426, 189, + 347, 213, 11, 54, 175, 324, 347, 208, 108, 22, + 426, 301, 223, 321, 221, 302, 226, 135, 18, 49, + 52, 41, 26, 288, 42, 44, 264, 222, 16, 235, + 294, 198, 204, 52, 5, 170, 288, 32, 90, 267, + 268, 4, 50, 249, 250, 239, 1, 20, 129, 185, + 179, 255, 213, 11, 54, 455, 288, 192, 455, 108, + 175, 167, 455, 223, 321, 221, 439, 226, 256, 18, + 55, 292, 41, 439, 132, 42, 44, 264, 222, 427, + 235, 12, 198, 165, 52, 5, 232, 288, 288, 347, + 153, 427, 4, 50, 249, 250, 239, 1, 232, 129, + 286, 181, 347, 213, 11, 54, 24, 13, 347, 49, + 108, 232, 320, 426, 223, 321, 221, 195, 201, 173, + 18, 49, 139, 41, 296, 426, 42, 44, 264, 222, + 7, 235, 286, 198, 49, 52, 5, 147, 288, 117, + 150, 317, 263, 4, 50, 249, 250, 239, 1, 95, + 130, 173, 189, 155, 213, 11, 54, 22, 244, 271, + 192, 108, 323, 286, 101, 223, 321, 221, 294, 226, + 204, 18, 348, 257, 41, 166, 283, 42, 44, 264, + 222, 28, 235, 300, 198, 348, 52, 5, 247, 288, + 117, 348, 94, 206, 4, 50, 249, 250, 239, 1, + 95, 129, 22, 189, 277, 213, 11, 54, 91, 274, + 224, 426, 108, 323, 216, 156, 223, 321, 221, 132, + 180, 262, 18, 426, 100, 41, 12, 288, 42, 44, + 264, 222, 15, 235, 216, 198, 254, 52, 5, 233, + 288, 210, 190, 192, 100, 4, 50, 249, 250, 239, + 1, 3, 131, 94, 189, 192, 213, 11, 54, 269, + 10, 204, 290, 108, 325, 216, 224, 223, 321, 221, + 23, 226, 211, 33, 315, 100, 45, 513, 92, 42, + 44, 264, 222, 102, 235, 178, 198, 268, 52, 5, + 275, 288, 161, 192, 37, 25, 4, 50, 249, 250, + 239, 1, 286, 129, 172, 187, 305, 213, 11, 54, + 164, 283, 310, 141, 108, 281, 281, 236, 223, 321, + 221, 169, 226, 230, 18, 122, 171, 41, 225, 175, + 42, 44, 264, 222, 144, 235, 303, 198, 134, 52, + 5, 265, 288, 151, 286, 192, 175, 4, 50, 249, + 250, 239, 1, 286, 128, 94, 189, 143, 213, 11, + 54, 219, 152, 207, 193, 108, 149, 281, 31, 223, + 321, 221, 100, 226, 21, 6, 286, 288, 41, 158, + 16, 42, 44, 264, 222, 102, 235, 238, 198, 286, + 52, 5, 157, 288, 281, 122, 168, 283, 4, 50, + 249, 250, 239, 1, 30, 93, 308, 51, 215, 213, + 11, 54, 53, 251, 140, 248, 108, 245, 304, 116, + 223, 321, 221, 111, 226, 176, 18, 270, 266, 41, + 224, 322, 42, 44, 264, 222, 7, 235, 259, 198, + 147, 52, 5, 257, 288, 43, 40, 38, 83, 4, + 50, 241, 214, 204, 319, 280, 88, 107, 138, 182, + 97, 64, 311, 312, 313, 316, 95, 281, 298, 258, + 142, 234, 94, 105, 272, 197, 231, 482, 237, 323, + 37, 133, 324, 241, 214, 204, 319, 314, 88, 107, + 296, 183, 97, 82, 84, 43, 40, 38, 95, 296, + 296, 258, 296, 296, 296, 159, 272, 197, 231, 296, + 237, 323, 311, 312, 313, 316, 241, 296, 204, 296, + 296, 103, 296, 296, 199, 104, 77, 296, 296, 110, + 296, 95, 296, 296, 258, 278, 296, 296, 34, 272, + 197, 231, 279, 237, 323, 43, 40, 38, 296, 296, + 296, 241, 26, 204, 196, 276, 103, 296, 16, 199, + 104, 77, 311, 312, 313, 316, 95, 192, 296, 258, + 146, 296, 296, 296, 272, 197, 231, 296, 237, 323, + 286, 393, 39, 35, 243, 296, 296, 296, 296, 191, + 276, 296, 26, 318, 252, 253, 126, 296, 16, 249, + 250, 239, 1, 296, 296, 131, 296, 261, 213, 11, + 54, 296, 296, 296, 426, 108, 393, 393, 393, 223, + 321, 221, 241, 296, 204, 299, 426, 103, 107, 296, + 183, 97, 82, 393, 393, 393, 393, 95, 296, 260, + 258, 52, 296, 296, 288, 272, 197, 231, 296, 237, + 323, 293, 296, 296, 296, 296, 296, 249, 250, 239, + 2, 296, 295, 296, 296, 296, 213, 11, 54, 296, + 296, 177, 296, 108, 136, 296, 296, 223, 321, 221, + 296, 296, 296, 293, 43, 40, 38, 296, 296, 249, + 250, 239, 2, 296, 295, 43, 40, 38, 213, 11, + 54, 311, 312, 313, 316, 108, 296, 291, 14, 223, + 321, 221, 311, 312, 313, 316, 296, 296, 241, 296, + 204, 296, 192, 103, 296, 296, 199, 104, 77, 296, + 296, 296, 296, 95, 383, 296, 258, 296, 296, 297, + 14, 272, 197, 231, 296, 237, 323, 383, 296, 296, + 241, 296, 204, 383, 296, 99, 296, 287, 199, 120, + 48, 241, 112, 204, 296, 95, 103, 296, 258, 199, + 120, 74, 296, 272, 197, 231, 95, 237, 323, 258, + 455, 296, 296, 455, 272, 197, 231, 455, 237, 323, + 241, 296, 204, 296, 296, 103, 200, 296, 199, 120, + 74, 296, 296, 296, 296, 95, 296, 296, 258, 278, + 296, 296, 34, 272, 197, 231, 279, 237, 323, 241, + 455, 204, 296, 296, 99, 202, 296, 199, 120, 56, + 241, 211, 204, 296, 95, 103, 296, 258, 199, 120, + 74, 296, 272, 197, 231, 95, 237, 323, 258, 227, + 296, 296, 296, 272, 197, 231, 296, 237, 323, 241, + 296, 204, 148, 296, 103, 203, 86, 199, 120, 73, + 296, 296, 286, 296, 95, 296, 296, 258, 278, 296, + 296, 34, 272, 197, 231, 279, 237, 323, 241, 296, + 204, 175, 296, 103, 296, 296, 199, 120, 75, 241, + 296, 204, 296, 95, 103, 296, 258, 199, 120, 63, + 296, 272, 197, 231, 95, 237, 323, 258, 229, 192, + 296, 296, 272, 197, 231, 296, 237, 323, 241, 296, + 204, 380, 296, 103, 296, 296, 199, 120, 58, 296, + 296, 296, 296, 95, 380, 296, 258, 296, 296, 296, + 380, 272, 197, 231, 296, 237, 323, 241, 296, 204, + 296, 296, 103, 296, 296, 199, 120, 71, 241, 296, + 204, 296, 95, 103, 296, 258, 199, 120, 79, 296, + 272, 197, 231, 95, 237, 323, 258, 296, 296, 296, + 154, 272, 197, 231, 87, 237, 323, 241, 296, 204, + 286, 296, 103, 296, 296, 199, 120, 70, 296, 296, + 296, 296, 95, 296, 296, 258, 296, 296, 296, 175, + 272, 197, 231, 296, 237, 323, 241, 296, 204, 296, + 296, 103, 296, 296, 199, 120, 56, 241, 296, 204, + 296, 95, 103, 296, 258, 199, 120, 46, 296, 272, + 197, 231, 95, 237, 323, 258, 296, 296, 296, 296, + 272, 197, 231, 296, 237, 323, 241, 296, 204, 296, + 296, 103, 296, 296, 199, 120, 78, 296, 296, 296, + 296, 95, 296, 296, 258, 296, 296, 296, 296, 272, + 197, 231, 296, 237, 323, 241, 296, 204, 296, 296, + 103, 296, 296, 199, 120, 66, 241, 296, 204, 296, + 95, 103, 296, 258, 199, 120, 59, 296, 272, 197, + 231, 95, 237, 323, 258, 296, 296, 296, 296, 272, + 197, 231, 296, 237, 323, 241, 296, 204, 296, 296, + 103, 296, 296, 186, 109, 57, 296, 296, 296, 296, + 95, 296, 296, 258, 296, 296, 296, 296, 272, 197, + 231, 296, 237, 323, 241, 296, 204, 296, 296, 103, + 296, 296, 188, 120, 67, 241, 296, 204, 296, 95, + 103, 296, 258, 199, 96, 62, 296, 272, 197, 231, + 95, 237, 323, 258, 296, 296, 296, 296, 272, 197, + 231, 296, 237, 323, 241, 296, 204, 296, 296, 103, + 296, 296, 199, 120, 80, 296, 296, 296, 296, 95, + 296, 296, 258, 296, 296, 296, 296, 272, 197, 231, + 296, 237, 323, 241, 296, 204, 296, 296, 103, 296, + 296, 199, 120, 76, 241, 296, 204, 296, 95, 103, + 296, 258, 199, 120, 81, 296, 272, 197, 231, 95, + 237, 323, 258, 296, 296, 296, 296, 272, 197, 231, + 296, 237, 323, 241, 296, 204, 296, 296, 103, 296, + 296, 199, 120, 65, 296, 296, 296, 296, 95, 296, + 296, 258, 296, 296, 296, 296, 272, 197, 231, 296, + 237, 323, 241, 296, 204, 296, 296, 103, 296, 296, + 199, 96, 68, 241, 296, 204, 296, 95, 103, 296, + 258, 199, 120, 61, 296, 272, 197, 231, 95, 237, + 323, 258, 296, 296, 296, 296, 272, 197, 231, 296, + 237, 323, 241, 296, 204, 296, 296, 103, 296, 296, + 199, 98, 69, 296, 296, 296, 296, 95, 296, 296, + 258, 296, 296, 296, 296, 272, 197, 231, 296, 237, + 323, 241, 296, 204, 296, 296, 103, 296, 296, 199, + 120, 72, 241, 296, 204, 296, 95, 103, 296, 258, + 199, 120, 47, 296, 272, 197, 231, 95, 237, 323, + 258, 296, 296, 296, 296, 272, 197, 231, 296, 237, + 323, 241, 192, 204, 296, 296, 103, 296, 296, 199, + 120, 60, 296, 296, 351, 296, 95, 296, 217, 258, + 296, 296, 296, 296, 272, 197, 231, 26, 237, 323, + 241, 296, 204, 16, 296, 103, 426, 296, 199, 125, + 296, 241, 296, 204, 296, 95, 103, 296, 426, 199, + 118, 296, 242, 272, 197, 231, 95, 237, 323, 296, + 296, 296, 296, 246, 272, 197, 231, 296, 237, 323, + 241, 296, 204, 278, 296, 103, 34, 296, 199, 121, + 279, 296, 296, 296, 296, 95, 296, 296, 296, 296, + 26, 296, 162, 272, 197, 231, 16, 237, 323, 241, + 296, 204, 296, 296, 103, 296, 296, 199, 123, 296, + 241, 296, 204, 296, 95, 103, 296, 296, 199, 114, + 296, 296, 272, 197, 231, 95, 237, 323, 296, 296, + 296, 296, 296, 272, 197, 231, 296, 237, 323, 241, + 296, 204, 296, 145, 103, 296, 296, 199, 124, 296, + 296, 296, 296, 286, 95, 39, 35, 243, 296, 296, + 296, 296, 272, 197, 231, 296, 237, 323, 241, 296, + 204, 296, 296, 103, 296, 296, 199, 115, 296, 241, + 296, 204, 296, 95, 103, 296, 296, 199, 113, 296, + 296, 272, 197, 231, 95, 237, 323, 296, 296, 296, + 296, 296, 272, 197, 231, 228, 237, 323, 241, 296, + 204, 296, 455, 103, 296, 455, 199, 119, 3, 455, + 439, 296, 296, 95, 296, 296, 296, 296, 296, 296, + 296, 272, 197, 231, 228, 237, 323, 296, 296, 296, + 296, 455, 296, 296, 455, 296, 296, 439, 455, 439, + 439, 228, 455, 296, 439, 296, 296, 137, 455, 296, + 296, 455, 296, 296, 32, 455, 439, 286, 296, 39, + 35, 243, 29, 296, 26, 296, 439, 296, 296, 439, + 16, 455, 296, 439, 306, 43, 40, 38, 296, 296, + 296, 296, 296, 439, 296, 296, 439, 296, 455, 296, + 439, 26, 311, 312, 313, 316, 296, 16, 228, 296, + 296, 296, 43, 40, 38, 455, 296, 296, 455, 296, + 296, 296, 455, 439, 296, 296, 19, 296, 296, 311, + 312, 313, 316, 455, 296, 296, 455, 296, 296, 296, + 455, 439, 296, 296, 296, 43, 40, 38, 296, 296, + 439, 296, 296, 439, 174, 455, 296, 439, 296, 240, + 309, 296, 311, 312, 313, 316, 296, 289, 439, 296, + 36, 439, 296, 455, 296, 439, 296, 296, 43, 40, + 38, 296, 296, 43, 40, 38, 296, 296, 296, 296, + 296, 43, 40, 38, 296, 311, 312, 313, 316, 296, + 311, 312, 313, 316, 296, 43, 40, 38, 311, 312, + 313, 316, 273, 43, 40, 38, 296, 296, 296, 296, + 296, 296, 311, 312, 313, 316, 296, 296, 296, 296, + 311, 312, 313, 316, 455, 296, 296, 455, 43, 40, + 38, 455, 439, 218, 43, 40, 38, 296, 296, 296, + 296, 296, 296, 296, 296, 311, 312, 313, 316, 296, + 296, 311, 312, 313, 316, 296, 296, 296, 296, 439, + 296, 296, 439, 296, 455, 296, 439, + ); + public static $yy_lookahead = array( + 9, 10, 11, 12, 12, 14, 14, 16, 16, 18, + 19, 20, 9, 34, 102, 12, 25, 13, 70, 16, + 29, 30, 31, 35, 33, 21, 35, 23, 95, 38, + 26, 52, 41, 42, 43, 44, 32, 46, 34, 48, + 36, 50, 51, 52, 53, 53, 98, 99, 44, 58, + 59, 9, 10, 11, 12, 22, 14, 13, 16, 15, + 18, 19, 20, 85, 86, 87, 15, 25, 17, 21, + 26, 29, 30, 31, 44, 33, 32, 35, 45, 35, + 38, 51, 34, 41, 42, 43, 44, 35, 46, 77, + 48, 47, 50, 51, 14, 53, 16, 13, 47, 47, + 58, 59, 9, 10, 11, 12, 22, 14, 35, 16, + 26, 18, 19, 20, 102, 103, 32, 44, 25, 34, + 47, 36, 29, 30, 31, 52, 33, 14, 35, 45, + 50, 38, 26, 53, 41, 42, 43, 44, 32, 46, + 66, 48, 68, 50, 51, 77, 53, 15, 35, 7, + 8, 58, 59, 9, 10, 11, 12, 12, 14, 14, + 16, 16, 18, 19, 20, 9, 53, 1, 12, 25, + 102, 82, 16, 29, 30, 31, 44, 33, 33, 35, + 106, 107, 38, 51, 44, 41, 42, 43, 44, 35, + 46, 51, 48, 82, 50, 51, 22, 53, 53, 13, + 73, 47, 58, 59, 9, 10, 11, 12, 22, 14, + 83, 16, 26, 18, 19, 20, 28, 12, 32, 45, + 25, 22, 70, 35, 29, 30, 31, 65, 33, 102, + 35, 45, 73, 38, 60, 47, 41, 42, 43, 44, + 35, 46, 83, 48, 45, 50, 51, 95, 53, 71, + 95, 52, 74, 58, 59, 9, 10, 11, 12, 81, + 14, 102, 16, 73, 18, 19, 20, 34, 90, 36, + 1, 25, 94, 83, 81, 29, 30, 31, 66, 33, + 68, 35, 13, 96, 38, 98, 99, 41, 42, 43, + 44, 15, 46, 100, 48, 26, 50, 51, 14, 53, + 71, 32, 17, 74, 58, 59, 9, 10, 11, 12, + 81, 14, 34, 16, 36, 18, 19, 20, 82, 107, + 44, 35, 25, 94, 71, 95, 29, 30, 31, 44, + 33, 78, 35, 47, 81, 38, 51, 53, 41, 42, + 43, 44, 15, 46, 71, 48, 16, 50, 51, 22, + 53, 78, 79, 1, 81, 58, 59, 9, 10, 11, + 12, 15, 14, 17, 16, 1, 18, 19, 20, 66, + 34, 68, 36, 25, 16, 71, 44, 29, 30, 31, + 28, 33, 78, 35, 52, 81, 38, 62, 63, 41, + 42, 43, 44, 47, 46, 6, 48, 8, 50, 51, + 16, 53, 73, 1, 2, 40, 58, 59, 9, 10, + 11, 12, 83, 14, 77, 16, 52, 18, 19, 20, + 98, 99, 52, 95, 25, 97, 97, 92, 29, 30, + 31, 77, 33, 49, 35, 100, 14, 38, 16, 102, + 41, 42, 43, 44, 73, 46, 14, 48, 14, 50, + 51, 36, 53, 73, 83, 1, 102, 58, 59, 9, + 10, 11, 12, 83, 14, 17, 16, 50, 18, 19, + 20, 17, 71, 64, 65, 25, 73, 97, 15, 29, + 30, 31, 81, 33, 26, 35, 83, 53, 38, 73, + 32, 41, 42, 43, 44, 47, 46, 92, 48, 83, + 50, 51, 95, 53, 97, 100, 98, 99, 58, 59, + 9, 10, 11, 12, 23, 14, 52, 16, 16, 18, + 19, 20, 16, 7, 50, 16, 25, 13, 13, 16, + 29, 30, 31, 16, 33, 16, 35, 33, 33, 38, + 44, 16, 41, 42, 43, 44, 35, 46, 16, 48, + 95, 50, 51, 96, 53, 37, 38, 39, 81, 58, + 59, 66, 67, 68, 69, 83, 71, 72, 95, 74, + 75, 76, 54, 55, 56, 57, 81, 97, 60, 84, + 95, 13, 17, 80, 89, 90, 91, 1, 93, 94, + 2, 81, 103, 66, 67, 68, 69, 99, 71, 72, + 108, 74, 75, 76, 81, 37, 38, 39, 81, 108, + 108, 84, 108, 108, 108, 95, 89, 90, 91, 108, + 93, 94, 54, 55, 56, 57, 66, 108, 68, 108, + 108, 71, 108, 108, 74, 75, 76, 108, 108, 21, + 108, 81, 108, 108, 84, 9, 108, 108, 12, 89, + 90, 91, 16, 93, 94, 37, 38, 39, 108, 108, + 108, 66, 26, 68, 104, 105, 71, 108, 32, 74, + 75, 76, 54, 55, 56, 57, 81, 1, 108, 84, + 73, 108, 108, 108, 89, 90, 91, 108, 93, 94, + 83, 2, 85, 86, 87, 108, 108, 108, 108, 104, + 105, 108, 26, 3, 4, 5, 6, 108, 32, 9, + 10, 11, 12, 108, 108, 14, 108, 16, 18, 19, + 20, 108, 108, 108, 35, 25, 37, 38, 39, 29, + 30, 31, 66, 108, 68, 69, 47, 71, 72, 108, + 74, 75, 76, 54, 55, 56, 57, 81, 108, 48, + 84, 50, 108, 108, 53, 89, 90, 91, 108, 93, + 94, 3, 108, 108, 108, 108, 108, 9, 10, 11, + 12, 108, 14, 108, 108, 108, 18, 19, 20, 108, + 108, 13, 108, 25, 27, 108, 108, 29, 30, 31, + 108, 108, 108, 3, 37, 38, 39, 108, 108, 9, + 10, 11, 12, 108, 14, 37, 38, 39, 18, 19, + 20, 54, 55, 56, 57, 25, 108, 59, 60, 29, + 30, 31, 54, 55, 56, 57, 108, 108, 66, 108, + 68, 108, 1, 71, 108, 108, 74, 75, 76, 108, + 108, 108, 108, 81, 13, 108, 84, 108, 108, 59, + 60, 89, 90, 91, 108, 93, 94, 26, 108, 108, + 66, 108, 68, 32, 108, 71, 108, 105, 74, 75, + 76, 66, 78, 68, 108, 81, 71, 108, 84, 74, + 75, 76, 108, 89, 90, 91, 81, 93, 94, 84, + 9, 108, 108, 12, 89, 90, 91, 16, 93, 94, + 66, 108, 68, 108, 108, 71, 101, 108, 74, 75, + 76, 108, 108, 108, 108, 81, 108, 108, 84, 9, + 108, 108, 12, 89, 90, 91, 16, 93, 94, 66, + 49, 68, 108, 108, 71, 101, 108, 74, 75, 76, + 66, 78, 68, 108, 81, 71, 108, 84, 74, 75, + 76, 108, 89, 90, 91, 81, 93, 94, 84, 49, + 108, 108, 108, 89, 90, 91, 108, 93, 94, 66, + 108, 68, 73, 108, 71, 101, 77, 74, 75, 76, + 108, 108, 83, 108, 81, 108, 108, 84, 9, 108, + 108, 12, 89, 90, 91, 16, 93, 94, 66, 108, + 68, 102, 108, 71, 108, 108, 74, 75, 76, 66, + 108, 68, 108, 81, 71, 108, 84, 74, 75, 76, + 108, 89, 90, 91, 81, 93, 94, 84, 49, 1, + 108, 108, 89, 90, 91, 108, 93, 94, 66, 108, + 68, 13, 108, 71, 108, 108, 74, 75, 76, 108, + 108, 108, 108, 81, 26, 108, 84, 108, 108, 108, + 32, 89, 90, 91, 108, 93, 94, 66, 108, 68, + 108, 108, 71, 108, 108, 74, 75, 76, 66, 108, + 68, 108, 81, 71, 108, 84, 74, 75, 76, 108, + 89, 90, 91, 81, 93, 94, 84, 108, 108, 108, + 73, 89, 90, 91, 77, 93, 94, 66, 108, 68, + 83, 108, 71, 108, 108, 74, 75, 76, 108, 108, + 108, 108, 81, 108, 108, 84, 108, 108, 108, 102, + 89, 90, 91, 108, 93, 94, 66, 108, 68, 108, + 108, 71, 108, 108, 74, 75, 76, 66, 108, 68, + 108, 81, 71, 108, 84, 74, 75, 76, 108, 89, + 90, 91, 81, 93, 94, 84, 108, 108, 108, 108, + 89, 90, 91, 108, 93, 94, 66, 108, 68, 108, + 108, 71, 108, 108, 74, 75, 76, 108, 108, 108, + 108, 81, 108, 108, 84, 108, 108, 108, 108, 89, + 90, 91, 108, 93, 94, 66, 108, 68, 108, 108, + 71, 108, 108, 74, 75, 76, 66, 108, 68, 108, + 81, 71, 108, 84, 74, 75, 76, 108, 89, 90, + 91, 81, 93, 94, 84, 108, 108, 108, 108, 89, + 90, 91, 108, 93, 94, 66, 108, 68, 108, 108, + 71, 108, 108, 74, 75, 76, 108, 108, 108, 108, + 81, 108, 108, 84, 108, 108, 108, 108, 89, 90, + 91, 108, 93, 94, 66, 108, 68, 108, 108, 71, + 108, 108, 74, 75, 76, 66, 108, 68, 108, 81, + 71, 108, 84, 74, 75, 76, 108, 89, 90, 91, + 81, 93, 94, 84, 108, 108, 108, 108, 89, 90, + 91, 108, 93, 94, 66, 108, 68, 108, 108, 71, + 108, 108, 74, 75, 76, 108, 108, 108, 108, 81, + 108, 108, 84, 108, 108, 108, 108, 89, 90, 91, + 108, 93, 94, 66, 108, 68, 108, 108, 71, 108, + 108, 74, 75, 76, 66, 108, 68, 108, 81, 71, + 108, 84, 74, 75, 76, 108, 89, 90, 91, 81, + 93, 94, 84, 108, 108, 108, 108, 89, 90, 91, + 108, 93, 94, 66, 108, 68, 108, 108, 71, 108, + 108, 74, 75, 76, 108, 108, 108, 108, 81, 108, + 108, 84, 108, 108, 108, 108, 89, 90, 91, 108, + 93, 94, 66, 108, 68, 108, 108, 71, 108, 108, + 74, 75, 76, 66, 108, 68, 108, 81, 71, 108, + 84, 74, 75, 76, 108, 89, 90, 91, 81, 93, + 94, 84, 108, 108, 108, 108, 89, 90, 91, 108, + 93, 94, 66, 108, 68, 108, 108, 71, 108, 108, + 74, 75, 76, 108, 108, 108, 108, 81, 108, 108, + 84, 108, 108, 108, 108, 89, 90, 91, 108, 93, + 94, 66, 108, 68, 108, 108, 71, 108, 108, 74, + 75, 76, 66, 108, 68, 108, 81, 71, 108, 84, + 74, 75, 76, 108, 89, 90, 91, 81, 93, 94, + 84, 108, 108, 108, 108, 89, 90, 91, 108, 93, + 94, 66, 1, 68, 108, 108, 71, 108, 108, 74, + 75, 76, 108, 108, 13, 108, 81, 108, 17, 84, + 108, 108, 108, 108, 89, 90, 91, 26, 93, 94, + 66, 108, 68, 32, 108, 71, 35, 108, 74, 75, + 108, 66, 108, 68, 108, 81, 71, 108, 47, 74, + 75, 108, 88, 89, 90, 91, 81, 93, 94, 108, + 108, 108, 108, 88, 89, 90, 91, 108, 93, 94, + 66, 108, 68, 9, 108, 71, 12, 108, 74, 75, + 16, 108, 108, 108, 108, 81, 108, 108, 108, 108, + 26, 108, 28, 89, 90, 91, 32, 93, 94, 66, + 108, 68, 108, 108, 71, 108, 108, 74, 75, 108, + 66, 108, 68, 108, 81, 71, 108, 108, 74, 75, + 108, 108, 89, 90, 91, 81, 93, 94, 108, 108, + 108, 108, 108, 89, 90, 91, 108, 93, 94, 66, + 108, 68, 108, 73, 71, 108, 108, 74, 75, 108, + 108, 108, 108, 83, 81, 85, 86, 87, 108, 108, + 108, 108, 89, 90, 91, 108, 93, 94, 66, 108, + 68, 108, 108, 71, 108, 108, 74, 75, 108, 66, + 108, 68, 108, 81, 71, 108, 108, 74, 75, 108, + 108, 89, 90, 91, 81, 93, 94, 108, 108, 108, + 108, 108, 89, 90, 91, 2, 93, 94, 66, 108, + 68, 108, 9, 71, 108, 12, 74, 75, 15, 16, + 17, 108, 108, 81, 108, 108, 108, 108, 108, 108, + 108, 89, 90, 91, 2, 93, 94, 108, 108, 108, + 108, 9, 108, 108, 12, 108, 108, 44, 16, 17, + 47, 2, 49, 108, 51, 108, 108, 73, 9, 108, + 108, 12, 108, 108, 15, 16, 17, 83, 108, 85, + 86, 87, 24, 108, 26, 108, 44, 108, 108, 47, + 32, 49, 108, 51, 52, 37, 38, 39, 108, 108, + 108, 108, 108, 44, 108, 108, 47, 108, 49, 108, + 51, 26, 54, 55, 56, 57, 108, 32, 2, 108, + 108, 108, 37, 38, 39, 9, 108, 108, 12, 108, + 108, 108, 16, 17, 108, 108, 2, 108, 108, 54, + 55, 56, 57, 9, 108, 108, 12, 108, 108, 108, + 16, 17, 108, 108, 108, 37, 38, 39, 108, 108, + 44, 108, 108, 47, 13, 49, 108, 51, 108, 13, + 52, 108, 54, 55, 56, 57, 108, 13, 44, 108, + 2, 47, 108, 49, 108, 51, 108, 108, 37, 38, + 39, 108, 108, 37, 38, 39, 108, 108, 108, 108, + 108, 37, 38, 39, 108, 54, 55, 56, 57, 108, + 54, 55, 56, 57, 108, 37, 38, 39, 54, 55, + 56, 57, 36, 37, 38, 39, 108, 108, 108, 108, + 108, 108, 54, 55, 56, 57, 108, 108, 108, 108, + 54, 55, 56, 57, 9, 108, 108, 12, 37, 38, + 39, 16, 17, 36, 37, 38, 39, 108, 108, 108, + 108, 108, 108, 108, 108, 54, 55, 56, 57, 108, + 108, 54, 55, 56, 57, 108, 108, 108, 108, 44, + 108, 108, 47, 108, 49, 108, 51, +); + const YY_SHIFT_USE_DFLT = -22; + const YY_SHIFT_MAX = 230; + public static $yy_shift_ofst = array( + -22, 501, 501, 93, 399, 399, 450, 93, 93, 93, + 399, 450, -9, 93, 93, 93, 93, 93, 93, 144, + 93, 195, 93, 93, 93, 246, 195, 93, 93, 93, + 93, 93, 297, 93, 93, 93, 93, 348, 42, 42, + 42, 42, 42, 42, 42, 42, 1768, 1795, 1795, 701, + 758, 1521, 80, 676, 113, 790, 1927, 1828, 1896, 568, + 768, 1861, 757, 1866, 1874, 1888, 618, 518, 1921, 1921, + 1921, 1921, 1921, 1921, 1921, 1921, 1921, 1921, 1921, 1921, + 1921, 1921, 1921, 1584, 636, 285, 676, 676, 346, 113, + 113, 402, 700, 1723, -8, 910, 831, 269, 1028, 51, + 3, 3, 422, 448, 352, 106, 422, 106, 458, 364, + 434, 454, 106, 166, 166, 166, 166, 565, 166, 166, + 166, 586, 565, 166, 166, -22, -22, 1752, 1769, 1826, + 1844, 1945, 145, 979, 156, 132, 284, 106, 140, 106, + 30, 140, 140, 30, 106, 106, 106, 140, 106, 106, + 140, 106, 327, 106, 106, 106, 140, 140, 106, 140, + 205, 106, 284, 166, 565, 588, 565, 588, 565, 166, + 166, -12, 166, -22, -22, -22, -22, -22, -22, 689, + 4, 44, 84, 186, 73, 881, 199, 188, 174, 286, + 48, 336, 384, 389, 332, 142, -21, 52, 154, 33, + 85, 276, 278, 233, 515, 509, 474, 516, 502, 464, + 491, 415, 417, 432, 514, 370, 463, 506, 365, 513, + -12, 517, 504, 519, 505, 511, 496, 525, 532, 330, + 358, +); + const YY_REDUCE_USE_DFLT = -89; + const YY_REDUCE_MAX = 178; + public static $yy_reduce_ofst = array( + 325, 527, 495, 666, 595, 560, 863, 874, 834, 805, + 762, 794, 1179, 1455, 1208, 1012, 1386, 1139, 1070, 1110, + 1150, 1219, 1248, 1277, 1288, 1317, 1346, 1357, 1415, 1426, + 1081, 1041, 1001, 972, 943, 932, 903, 1484, 1495, 1622, + 1633, 1662, 1593, 1564, 1553, 1524, 1704, 607, 1590, 178, + 74, 1027, 229, 899, 273, 212, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, 380, 329, 187, 159, 127, -52, 253, + 304, 12, 303, 152, 193, 328, 68, 68, 68, 322, + 328, 407, 405, 322, 68, 190, 335, 416, 403, 68, + 401, 354, 371, 68, 68, 68, 337, 322, 68, 68, + 68, 68, 408, 68, 68, 68, 409, 455, 455, 455, + 455, 455, 510, 480, 455, 455, 477, 482, 457, 482, + 473, 457, 457, 485, 482, 482, 482, 457, 482, 482, + 457, 482, 503, 482, 482, 482, 457, 457, 482, 457, + 520, 482, 523, -88, 498, 489, 498, 489, 498, -88, + -88, -67, -88, 111, 155, 89, 236, 230, 162, +); + public static $yyExpectedTokens = array( + array(), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 52, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(9, 10, 11, 12, 14, 16, 18, 19, 20, 25, 29, 30, 31, 33, 35, 38, 41, 42, 43, 44, 46, 48, 50, 51, 53, 58, 59, ), + array(24, 26, 32, 37, 38, 39, 54, 55, 56, 57, ), + array(26, 32, 37, 38, 39, 54, 55, 56, 57, ), + array(26, 32, 37, 38, 39, 54, 55, 56, 57, ), + array(14, 16, 48, 50, 53, ), + array(3, 9, 10, 11, 12, 14, 18, 19, 20, 25, 29, 30, 31, 59, 60, ), + array(1, 13, 17, 26, 32, 35, 47, ), + array(14, 16, 50, 53, ), + array(1, 26, 32, ), + array(14, 35, 53, ), + array(3, 9, 10, 11, 12, 14, 18, 19, 20, 25, 29, 30, 31, 59, 60, ), + array(36, 37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 52, 54, 55, 56, 57, ), + array(36, 37, 38, 39, 54, 55, 56, 57, ), + array(13, 37, 38, 39, 54, 55, 56, 57, ), + array(13, 37, 38, 39, 54, 55, 56, 57, ), + array(13, 37, 38, 39, 54, 55, 56, 57, ), + array(27, 37, 38, 39, 54, 55, 56, 57, ), + array(13, 37, 38, 39, 54, 55, 56, 57, ), + array(13, 37, 38, 39, 54, 55, 56, 57, ), + array(2, 37, 38, 39, 54, 55, 56, 57, ), + array(21, 37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, 60, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(37, 38, 39, 54, 55, 56, 57, ), + array(9, 12, 16, 26, 28, 32, ), + array(9, 12, 16, 26, 32, ), + array(17, 44, 51, ), + array(1, 26, 32, ), + array(1, 26, 32, ), + array(15, 17, 47, ), + array(14, 35, 53, ), + array(14, 35, 53, ), + array(1, 2, ), + array(3, 4, 5, 6, 9, 10, 11, 12, 18, 19, 20, 25, 29, 30, 31, ), + array(2, 9, 12, 15, 16, 17, 44, 47, 49, 51, ), + array(12, 14, 16, 53, ), + array(9, 12, 16, 49, ), + array(1, 13, 26, 32, ), + array(1, 13, 26, 32, ), + array(1, 13, 26, 32, ), + array(15, 17, 47, ), + array(9, 12, 16, ), + array(9, 12, 16, ), + array(14, 16, ), + array(17, 47, ), + array(1, 28, ), + array(26, 32, ), + array(14, 16, ), + array(26, 32, ), + array(26, 32, ), + array(1, 52, ), + array(14, 53, ), + array(1, 17, ), + array(26, 32, ), + array(1, ), + array(1, ), + array(1, ), + array(1, ), + array(17, ), + array(1, ), + array(1, ), + array(1, ), + array(1, ), + array(17, ), + array(1, ), + array(1, ), + array(), + array(), + array(2, 9, 12, 16, 17, 44, 47, 49, 51, 52, ), + array(2, 9, 12, 15, 16, 17, 44, 47, 49, 51, ), + array(2, 9, 12, 16, 17, 44, 47, 49, 51, ), + array(2, 9, 12, 16, 17, 44, 47, 49, 51, ), + array(9, 12, 16, 17, 44, 47, 49, 51, ), + array(12, 14, 16, 33, 53, ), + array(9, 12, 16, 49, ), + array(9, 12, 16, ), + array(15, 44, 51, ), + array(14, 53, ), + array(26, 32, ), + array(44, 51, ), + array(26, 32, ), + array(44, 51, ), + array(44, 51, ), + array(44, 51, ), + array(44, 51, ), + array(26, 32, ), + array(26, 32, ), + array(26, 32, ), + array(44, 51, ), + array(26, 32, ), + array(26, 32, ), + array(44, 51, ), + array(26, 32, ), + array(15, 22, ), + array(26, 32, ), + array(26, 32, ), + array(26, 32, ), + array(44, 51, ), + array(44, 51, ), + array(26, 32, ), + array(44, 51, ), + array(12, 35, ), + array(26, 32, ), + array(14, 53, ), + array(1, ), + array(17, ), + array(2, ), + array(17, ), + array(2, ), + array(17, ), + array(1, ), + array(1, ), + array(35, ), + array(1, ), + array(), + array(), + array(), + array(), + array(), + array(), + array(2, 35, 37, 38, 39, 47, 54, 55, 56, 57, ), + array(13, 21, 23, 26, 32, 34, 36, 44, ), + array(13, 15, 26, 32, 35, 47, ), + array(13, 22, 26, 32, 45, ), + array(13, 22, 26, 32, 45, ), + array(35, 44, 47, 52, ), + array(9, 12, 16, 49, ), + array(22, 45, 52, ), + array(28, 35, 47, ), + array(22, 45, 60, ), + array(35, 47, ), + array(21, 34, ), + array(34, 36, ), + array(16, 49, ), + array(6, 8, ), + array(44, 52, ), + array(7, 8, ), + array(34, 52, ), + array(35, 47, ), + array(35, 47, ), + array(22, 45, ), + array(34, 36, ), + array(15, 44, ), + array(34, 36, ), + array(34, 36, ), + array(13, ), + array(16, ), + array(50, ), + array(7, ), + array(16, ), + array(52, ), + array(23, ), + array(36, ), + array(50, ), + array(14, ), + array(13, ), + array(52, ), + array(15, ), + array(16, ), + array(40, ), + array(16, ), + array(35, ), + array(16, ), + array(33, ), + array(16, ), + array(33, ), + array(35, ), + array(44, ), + array(16, ), + array(16, ), + array(16, ), + array(16, ), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), + array(), +); + public static $yy_default = array( + 336, 512, 512, 512, 497, 497, 512, 474, 474, 474, + 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, + 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, + 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, + 512, 512, 512, 512, 512, 512, 377, 377, 356, 512, + 512, 413, 512, 377, 512, 512, 512, 512, 512, 512, + 512, 512, 382, 512, 349, 512, 512, 512, 382, 379, + 389, 388, 384, 402, 473, 397, 498, 500, 401, 361, + 472, 499, 349, 377, 377, 487, 377, 377, 429, 512, + 512, 368, 326, 428, 512, 439, 391, 391, 391, 429, + 439, 439, 512, 429, 391, 377, 512, 377, 377, 391, + 512, 371, 358, 395, 394, 396, 373, 429, 400, 404, + 391, 404, 484, 406, 405, 481, 334, 428, 428, 428, + 428, 428, 512, 441, 439, 455, 512, 363, 435, 354, + 434, 437, 433, 432, 359, 357, 364, 436, 353, 367, + 466, 365, 512, 352, 350, 360, 467, 465, 346, 464, + 439, 366, 512, 369, 461, 475, 488, 476, 485, 372, + 422, 439, 374, 480, 439, 480, 480, 439, 334, 413, + 409, 413, 403, 403, 413, 440, 403, 413, 403, 413, + 512, 512, 512, 332, 409, 512, 512, 512, 423, 403, + 512, 409, 512, 512, 512, 512, 512, 512, 512, 418, + 385, 512, 512, 512, 512, 512, 512, 512, 415, 512, + 455, 512, 512, 512, 411, 486, 409, 512, 512, 512, + 512, 419, 407, 362, 445, 418, 425, 424, 420, 339, + 460, 421, 483, 398, 416, 340, 399, 455, 378, 337, + 338, 330, 328, 329, 442, 443, 444, 438, 392, 393, + 427, 426, 386, 417, 408, 390, 410, 331, 333, 335, + 412, 470, 414, 415, 503, 478, 495, 471, 459, 458, + 375, 457, 344, 462, 508, 493, 376, 496, 456, 509, + 494, 501, 504, 511, 510, 507, 505, 502, 506, 345, + 468, 469, 446, 355, 341, 452, 450, 454, 448, 453, + 447, 489, 490, 491, 463, 449, 492, 451, 327, 342, + 343, 370, 430, 431, 479, 477, +); + const YYNOCODE = 109; + const YYSTACKDEPTH = 500; + const YYNSTATE = 326; + const YYNRULE = 186; + const YYERRORSYMBOL = 61; + const YYERRSYMDT = 'yy0'; + const YYFALLBACK = 0; + public static $yyFallback = array( + ); public function Trace($TraceFILE, $zTracePrompt) { if (!$TraceFILE) { @@ -1840,18 +1110,250 @@ class Smarty_Internal_Templateparser $this->yyTracePrompt = '
'; } + public $yyTraceFILE; + public $yyTracePrompt; + public $yyidx; /* Index of top element in stack */ + public $yyerrcnt; /* Shifts left before out of the error */ + public $yystack = array(); /* The parser's stack */ + + public $yyTokenName = array( + '$', 'VERT', 'COLON', 'TEXT', + 'STRIPON', 'STRIPOFF', 'LITERALSTART', 'LITERALEND', + 'LITERAL', 'SIMPELOUTPUT', 'SIMPLETAG', 'SMARTYBLOCKCHILDPARENT', + 'LDEL', 'RDEL', 'DOLLARID', 'EQUAL', + 'ID', 'PTR', 'LDELMAKENOCACHE', 'LDELIF', + 'LDELFOR', 'SEMICOLON', 'INCDEC', 'TO', + 'STEP', 'LDELFOREACH', 'SPACE', 'AS', + 'APTR', 'LDELSETFILTER', 'CLOSETAG', 'LDELSLASH', + 'ATTR', 'INTEGER', 'COMMA', 'OPENP', + 'CLOSEP', 'MATH', 'UNIMATH', 'ISIN', + 'QMARK', 'NOT', 'TYPECAST', 'HEX', + 'DOT', 'INSTANCEOF', 'SINGLEQUOTESTRING', 'DOUBLECOLON', + 'NAMESPACE', 'AT', 'HATCH', 'OPENB', + 'CLOSEB', 'DOLLAR', 'LOGOP', 'SLOGOP', + 'TLOGOP', 'SINGLECOND', 'ARRAYOPEN', 'QUOTE', + 'BACKTICK', 'error', 'start', 'template', + 'literal_e2', 'literal_e1', 'smartytag', 'tagbody', + 'tag', 'outattr', 'eqoutattr', 'varindexed', + 'output', 'attributes', 'variable', 'value', + 'expr', 'modifierlist', 'statement', 'statements', + 'foraction', 'varvar', 'modparameters', 'attribute', + 'ternary', 'tlop', 'lop', 'scond', + 'array', 'function', 'ns1', 'doublequoted_with_quotes', + 'static_class_access', 'arraydef', 'object', 'arrayindex', + 'indexdef', 'varvarele', 'objectchain', 'objectelement', + 'method', 'params', 'modifier', 'modparameter', + 'arrayelements', 'arrayelement', 'doublequoted', 'doublequotedcontent', + ); + + public static $yyRuleName = array( + 'start ::= template', + 'template ::= template TEXT', + 'template ::= template STRIPON', + 'template ::= template STRIPOFF', + 'template ::= template LITERALSTART literal_e2 LITERALEND', + 'literal_e2 ::= literal_e1 LITERALSTART literal_e1 LITERALEND', + 'literal_e2 ::= literal_e1', + 'literal_e1 ::= literal_e1 LITERAL', + 'literal_e1 ::=', + 'template ::= template smartytag', + 'template ::=', + 'smartytag ::= SIMPELOUTPUT', + 'smartytag ::= SIMPLETAG', + 'smartytag ::= SMARTYBLOCKCHILDPARENT', + 'smartytag ::= LDEL tagbody RDEL', + 'smartytag ::= tag RDEL', + 'tagbody ::= outattr', + 'tagbody ::= DOLLARID eqoutattr', + 'tagbody ::= varindexed eqoutattr', + 'eqoutattr ::= EQUAL outattr', + 'outattr ::= output attributes', + 'output ::= variable', + 'output ::= value', + 'output ::= expr', + 'tag ::= LDEL ID attributes', + 'tag ::= LDEL ID', + 'tag ::= LDEL ID modifierlist attributes', + 'tag ::= LDEL ID PTR ID attributes', + 'tag ::= LDEL ID PTR ID modifierlist attributes', + 'tag ::= LDELMAKENOCACHE DOLLARID', + 'tag ::= LDELIF expr', + 'tag ::= LDELIF expr attributes', + 'tag ::= LDELIF statement', + 'tag ::= LDELIF statement attributes', + 'tag ::= LDELFOR statements SEMICOLON expr SEMICOLON varindexed foraction attributes', + 'foraction ::= EQUAL expr', + 'foraction ::= INCDEC', + 'tag ::= LDELFOR statement TO expr attributes', + 'tag ::= LDELFOR statement TO expr STEP expr attributes', + 'tag ::= LDELFOREACH SPACE expr AS varvar attributes', + 'tag ::= LDELFOREACH SPACE expr AS varvar APTR varvar attributes', + 'tag ::= LDELFOREACH attributes', + 'tag ::= LDELSETFILTER ID modparameters', + 'tag ::= LDELSETFILTER ID modparameters modifierlist', + 'smartytag ::= CLOSETAG', + 'tag ::= LDELSLASH ID', + 'tag ::= LDELSLASH ID modifierlist', + 'tag ::= LDELSLASH ID PTR ID', + 'tag ::= LDELSLASH ID PTR ID modifierlist', + 'attributes ::= attributes attribute', + 'attributes ::= attribute', + 'attributes ::=', + 'attribute ::= SPACE ID EQUAL ID', + 'attribute ::= ATTR expr', + 'attribute ::= ATTR value', + 'attribute ::= SPACE ID', + 'attribute ::= SPACE expr', + 'attribute ::= SPACE value', + 'attribute ::= SPACE INTEGER EQUAL expr', + 'statements ::= statement', + 'statements ::= statements COMMA statement', + 'statement ::= DOLLARID EQUAL INTEGER', + 'statement ::= DOLLARID EQUAL expr', + 'statement ::= varindexed EQUAL expr', + 'statement ::= OPENP statement CLOSEP', + 'expr ::= value', + 'expr ::= ternary', + 'expr ::= DOLLARID COLON ID', + 'expr ::= expr MATH value', + 'expr ::= expr UNIMATH value', + 'expr ::= expr tlop value', + 'expr ::= expr lop expr', + 'expr ::= expr scond', + 'expr ::= expr ISIN array', + 'expr ::= expr ISIN value', + 'ternary ::= OPENP expr CLOSEP QMARK DOLLARID COLON expr', + 'ternary ::= OPENP expr CLOSEP QMARK expr COLON expr', + 'value ::= variable', + 'value ::= UNIMATH value', + 'value ::= NOT value', + 'value ::= TYPECAST value', + 'value ::= variable INCDEC', + 'value ::= HEX', + 'value ::= INTEGER', + 'value ::= INTEGER DOT INTEGER', + 'value ::= INTEGER DOT', + 'value ::= DOT INTEGER', + 'value ::= ID', + 'value ::= function', + 'value ::= OPENP expr CLOSEP', + 'value ::= variable INSTANCEOF ns1', + 'value ::= variable INSTANCEOF variable', + 'value ::= SINGLEQUOTESTRING', + 'value ::= doublequoted_with_quotes', + 'value ::= varindexed DOUBLECOLON static_class_access', + 'value ::= smartytag', + 'value ::= value modifierlist', + 'value ::= NAMESPACE', + 'value ::= arraydef', + 'value ::= ns1 DOUBLECOLON static_class_access', + 'ns1 ::= ID', + 'ns1 ::= NAMESPACE', + 'variable ::= DOLLARID', + 'variable ::= varindexed', + 'variable ::= varvar AT ID', + 'variable ::= object', + 'variable ::= HATCH ID HATCH', + 'variable ::= HATCH ID HATCH arrayindex', + 'variable ::= HATCH variable HATCH', + 'variable ::= HATCH variable HATCH arrayindex', + 'varindexed ::= DOLLARID arrayindex', + 'varindexed ::= varvar arrayindex', + 'arrayindex ::= arrayindex indexdef', + 'arrayindex ::=', + 'indexdef ::= DOT DOLLARID', + 'indexdef ::= DOT varvar', + 'indexdef ::= DOT varvar AT ID', + 'indexdef ::= DOT ID', + 'indexdef ::= DOT INTEGER', + 'indexdef ::= DOT LDEL expr RDEL', + 'indexdef ::= OPENB ID CLOSEB', + 'indexdef ::= OPENB ID DOT ID CLOSEB', + 'indexdef ::= OPENB SINGLEQUOTESTRING CLOSEB', + 'indexdef ::= OPENB INTEGER CLOSEB', + 'indexdef ::= OPENB DOLLARID CLOSEB', + 'indexdef ::= OPENB variable CLOSEB', + 'indexdef ::= OPENB value CLOSEB', + 'indexdef ::= OPENB expr CLOSEB', + 'indexdef ::= OPENB CLOSEB', + 'varvar ::= DOLLARID', + 'varvar ::= DOLLAR', + 'varvar ::= varvar varvarele', + 'varvarele ::= ID', + 'varvarele ::= SIMPELOUTPUT', + 'varvarele ::= LDEL expr RDEL', + 'object ::= varindexed objectchain', + 'objectchain ::= objectelement', + 'objectchain ::= objectchain objectelement', + 'objectelement ::= PTR ID arrayindex', + 'objectelement ::= PTR varvar arrayindex', + 'objectelement ::= PTR LDEL expr RDEL arrayindex', + 'objectelement ::= PTR ID LDEL expr RDEL arrayindex', + 'objectelement ::= PTR method', + 'function ::= ns1 OPENP params CLOSEP', + 'method ::= ID OPENP params CLOSEP', + 'method ::= DOLLARID OPENP params CLOSEP', + 'params ::= params COMMA expr', + 'params ::= expr', + 'params ::=', + 'modifierlist ::= modifierlist modifier modparameters', + 'modifierlist ::= modifier modparameters', + 'modifier ::= VERT AT ID', + 'modifier ::= VERT ID', + 'modparameters ::= modparameters modparameter', + 'modparameters ::=', + 'modparameter ::= COLON value', + 'modparameter ::= COLON UNIMATH value', + 'modparameter ::= COLON array', + 'static_class_access ::= method', + 'static_class_access ::= method objectchain', + 'static_class_access ::= ID', + 'static_class_access ::= DOLLARID arrayindex', + 'static_class_access ::= DOLLARID arrayindex objectchain', + 'lop ::= LOGOP', + 'lop ::= SLOGOP', + 'tlop ::= TLOGOP', + 'scond ::= SINGLECOND', + 'arraydef ::= OPENB arrayelements CLOSEB', + 'arraydef ::= ARRAYOPEN arrayelements CLOSEP', + 'arrayelements ::= arrayelement', + 'arrayelements ::= arrayelements COMMA arrayelement', + 'arrayelements ::=', + 'arrayelement ::= value APTR expr', + 'arrayelement ::= ID APTR expr', + 'arrayelement ::= expr', + 'doublequoted_with_quotes ::= QUOTE QUOTE', + 'doublequoted_with_quotes ::= QUOTE doublequoted QUOTE', + 'doublequoted ::= doublequoted doublequotedcontent', + 'doublequoted ::= doublequotedcontent', + 'doublequotedcontent ::= BACKTICK variable BACKTICK', + 'doublequotedcontent ::= BACKTICK expr BACKTICK', + 'doublequotedcontent ::= DOLLARID', + 'doublequotedcontent ::= LDEL variable RDEL', + 'doublequotedcontent ::= LDEL expr RDEL', + 'doublequotedcontent ::= smartytag', + 'doublequotedcontent ::= TEXT', + ); + public function tokenName($tokenType) { if ($tokenType === 0) { return 'End of Input'; } if ($tokenType > 0 && $tokenType < count($this->yyTokenName)) { - return $this->yyTokenName[ $tokenType ]; + return $this->yyTokenName[$tokenType]; } else { return 'Unknown'; } } + public static function yy_destructor($yymajor, $yypminor) + { + switch ($yymajor) { + default: break; /* If no destructor action specified: do nothing */ + } + } + public function yy_pop_parser_stack() { if (empty($this->yystack)) { @@ -1860,18 +1362,19 @@ class Smarty_Internal_Templateparser $yytos = array_pop($this->yystack); if ($this->yyTraceFILE && $this->yyidx >= 0) { fwrite($this->yyTraceFILE, - $this->yyTracePrompt . 'Popping ' . $this->yyTokenName[ $yytos->major ] . - "\n"); + $this->yyTracePrompt . 'Popping ' . $this->yyTokenName[$yytos->major] . + "\n"); } $yymajor = $yytos->major; self::yy_destructor($yymajor, $yytos->minor); $this->yyidx--; + return $yymajor; } public function __destruct() { - while ($this->yystack !== array()) { + while ($this->yystack !== Array()) { $this->yy_pop_parser_stack(); } if (is_resource($this->yyTraceFILE)) { @@ -1883,14 +1386,14 @@ class Smarty_Internal_Templateparser { static $res3 = array(); static $res4 = array(); - $state = $this->yystack[ $this->yyidx ]->stateno; - $expected = self::$yyExpectedTokens[ $state ]; - if (isset($res3[ $state ][ $token ])) { - if ($res3[ $state ][ $token ]) { + $state = $this->yystack[$this->yyidx]->stateno; + $expected = self::$yyExpectedTokens[$state]; + if (isset($res3[$state][$token])) { + if ($res3[$state][$token]) { return $expected; } } else { - if ($res3[ $state ][ $token ] = in_array($token, self::$yyExpectedTokens[ $state ], true)) { + if ($res3[$state][$token] = in_array($token, self::$yyExpectedTokens[$state], true)) { return $expected; } } @@ -1910,21 +1413,20 @@ class Smarty_Internal_Templateparser return array_unique($expected); } $yyruleno = $yyact - self::YYNSTATE; - $this->yyidx -= self::$yyRuleInfo[ $yyruleno ][ 1 ]; + $this->yyidx -= self::$yyRuleInfo[$yyruleno][1]; $nextstate = $this->yy_find_reduce_action( - $this->yystack[ $this->yyidx ]->stateno, - self::$yyRuleInfo[ $yyruleno ][ 0 ]); - if (isset(self::$yyExpectedTokens[ $nextstate ])) { - $expected = array_merge($expected, self::$yyExpectedTokens[ $nextstate ]); - if (isset($res4[ $nextstate ][ $token ])) { - if ($res4[ $nextstate ][ $token ]) { + $this->yystack[$this->yyidx]->stateno, + self::$yyRuleInfo[$yyruleno][0]); + if (isset(self::$yyExpectedTokens[$nextstate])) { + $expected = array_merge($expected, self::$yyExpectedTokens[$nextstate]); + if (isset($res4[$nextstate][$token])) { + if ($res4[$nextstate][$token]) { $this->yyidx = $yyidx; $this->yystack = $stack; return array_unique($expected); } } else { - if ($res4[ $nextstate ][ $token ] = - in_array($token, self::$yyExpectedTokens[ $nextstate ], true)) { + if ($res4[$nextstate][$token] = in_array($token, self::$yyExpectedTokens[$nextstate], true)) { $this->yyidx = $yyidx; $this->yystack = $stack; return array_unique($expected); @@ -1936,8 +1438,8 @@ class Smarty_Internal_Templateparser $this->yyidx++; $x = new TP_yyStackEntry; $x->stateno = $nextstate; - $x->major = self::$yyRuleInfo[ $yyruleno ][ 0 ]; - $this->yystack[ $this->yyidx ] = $x; + $x->major = self::$yyRuleInfo[$yyruleno][0]; + $this->yystack[$this->yyidx] = $x; continue 2; } elseif ($nextstate === self::YYNSTATE + self::YYNRULE + 1) { $this->yyidx = $yyidx; @@ -1958,8 +1460,9 @@ class Smarty_Internal_Templateparser } break; } while (true); - $this->yyidx = $yyidx; - $this->yystack = $stack; + $this->yyidx = $yyidx; + $this->yystack = $stack; + return array_unique($expected); } @@ -1970,16 +1473,16 @@ class Smarty_Internal_Templateparser if ($token === 0) { return true; // 0 is not part of this } - $state = $this->yystack[ $this->yyidx ]->stateno; - if (isset($res[ $state ][ $token ])) { - if ($res[ $state ][ $token ]) { + $state = $this->yystack[$this->yyidx]->stateno; + if (isset($res[$state][$token])) { + if ($res[$state][$token]) { return true; } } else { - if ($res[ $state ][ $token ] = in_array($token, self::$yyExpectedTokens[ $state ], true)) { + if ($res[$state][$token] = in_array($token, self::$yyExpectedTokens[$state], true)) { return true; } - } + } $stack = $this->yystack; $yyidx = $this->yyidx; do { @@ -1996,20 +1499,18 @@ class Smarty_Internal_Templateparser return true; } $yyruleno = $yyact - self::YYNSTATE; - $this->yyidx -= self::$yyRuleInfo[ $yyruleno ][ 1 ]; + $this->yyidx -= self::$yyRuleInfo[$yyruleno][1]; $nextstate = $this->yy_find_reduce_action( - $this->yystack[ $this->yyidx ]->stateno, - self::$yyRuleInfo[ $yyruleno ][ 0 ]); - if (isset($res2[ $nextstate ][ $token ])) { - if ($res2[ $nextstate ][ $token ]) { + $this->yystack[$this->yyidx]->stateno, + self::$yyRuleInfo[$yyruleno][0]); + if (isset($res2[$nextstate][$token])) { + if ($res2[$nextstate][$token]) { $this->yyidx = $yyidx; $this->yystack = $stack; return true; } } else { - if ($res2[ $nextstate ][ $token ] = - (isset(self::$yyExpectedTokens[ $nextstate ]) && - in_array($token, self::$yyExpectedTokens[ $nextstate ], true))) { + if ($res2[$nextstate][$token] = (isset(self::$yyExpectedTokens[$nextstate]) && in_array($token, self::$yyExpectedTokens[$nextstate], true))) { $this->yyidx = $yyidx; $this->yystack = $stack; return true; @@ -2020,8 +1521,8 @@ class Smarty_Internal_Templateparser $this->yyidx++; $x = new TP_yyStackEntry; $x->stateno = $nextstate; - $x->major = self::$yyRuleInfo[ $yyruleno ][ 0 ]; - $this->yystack[ $this->yyidx ] = $x; + $x->major = self::$yyRuleInfo[$yyruleno][0]; + $this->yystack[$this->yyidx] = $x; continue 2; } elseif ($nextstate === self::YYNSTATE + self::YYNRULE + 1) { $this->yyidx = $yyidx; @@ -2048,65 +1549,69 @@ class Smarty_Internal_Templateparser } while (true); $this->yyidx = $yyidx; $this->yystack = $stack; + return true; } - public function yy_find_shift_action($iLookAhead) + public function yy_find_shift_action($iLookAhead) { - $stateno = $this->yystack[ $this->yyidx ]->stateno; + $stateno = $this->yystack[$this->yyidx]->stateno; + /* if ($this->yyidx < 0) return self::YY_NO_ACTION; */ - if (!isset(self::$yy_shift_ofst[ $stateno ])) { + if (!isset(self::$yy_shift_ofst[$stateno])) { // no shift actions - return self::$yy_default[ $stateno ]; + return self::$yy_default[$stateno]; } - $i = self::$yy_shift_ofst[ $stateno ]; + $i = self::$yy_shift_ofst[$stateno]; if ($i === self::YY_SHIFT_USE_DFLT) { - return self::$yy_default[ $stateno ]; + return self::$yy_default[$stateno]; } if ($iLookAhead === self::YYNOCODE) { return self::YY_NO_ACTION; } $i += $iLookAhead; if ($i < 0 || $i >= self::YY_SZ_ACTTAB || - self::$yy_lookahead[ $i ] != $iLookAhead) { + self::$yy_lookahead[$i] != $iLookAhead) { if (count(self::$yyFallback) && $iLookAhead < count(self::$yyFallback) - && ($iFallback = self::$yyFallback[ $iLookAhead ]) != 0) { + && ($iFallback = self::$yyFallback[$iLookAhead]) != 0) { if ($this->yyTraceFILE) { fwrite($this->yyTraceFILE, $this->yyTracePrompt . 'FALLBACK ' . - $this->yyTokenName[ $iLookAhead ] . ' => ' . - $this->yyTokenName[ $iFallback ] . "\n"); + $this->yyTokenName[$iLookAhead] . ' => ' . + $this->yyTokenName[$iFallback] . "\n"); } + return $this->yy_find_shift_action($iFallback); } - return self::$yy_default[ $stateno ]; + + return self::$yy_default[$stateno]; } else { - return self::$yy_action[ $i ]; + return self::$yy_action[$i]; } } public function yy_find_reduce_action($stateno, $iLookAhead) { /* $stateno = $this->yystack[$this->yyidx]->stateno; */ - if (!isset(self::$yy_reduce_ofst[ $stateno ])) { - return self::$yy_default[ $stateno ]; + + if (!isset(self::$yy_reduce_ofst[$stateno])) { + return self::$yy_default[$stateno]; } - $i = self::$yy_reduce_ofst[ $stateno ]; + $i = self::$yy_reduce_ofst[$stateno]; if ($i === self::YY_REDUCE_USE_DFLT) { - return self::$yy_default[ $stateno ]; + return self::$yy_default[$stateno]; } if ($iLookAhead === self::YYNOCODE) { return self::YY_NO_ACTION; } $i += $iLookAhead; if ($i < 0 || $i >= self::YY_SZ_ACTTAB || - self::$yy_lookahead[ $i ] != $iLookAhead) { - return self::$yy_default[ $stateno ]; + self::$yy_lookahead[$i] != $iLookAhead) { + return self::$yy_default[$stateno]; } else { - return self::$yy_action[ $i ]; + return self::$yy_action[$i]; } } - // line 234 "../smarty/lexer/smarty_internal_templateparser.y" public function yy_shift($yyNewState, $yyMajor, $yypMinor) { $this->yyidx++; @@ -2118,9 +1623,11 @@ class Smarty_Internal_Templateparser while ($this->yyidx >= 0) { $this->yy_pop_parser_stack(); } - // line 221 "../smarty/lexer/smarty_internal_templateparser.y" - $this->internalError = true; - $this->compiler->trigger_template_error('Stack overflow in template parser'); +// line 220 "../smarty/lexer/smarty_internal_templateparser.y" + + $this->internalError = true; + $this->compiler->trigger_template_error('Stack overflow in template parser'); + return; } $yytos = new TP_yyStackEntry; @@ -2134,1357 +1641,1153 @@ class Smarty_Internal_Templateparser fprintf($this->yyTraceFILE, "%sStack:", $this->yyTracePrompt); for ($i = 1; $i <= $this->yyidx; $i++) { fprintf($this->yyTraceFILE, " %s", - $this->yyTokenName[ $this->yystack[ $i ]->major ]); + $this->yyTokenName[$this->yystack[$i]->major]); } - fwrite($this->yyTraceFILE, "\n"); + fwrite($this->yyTraceFILE,"\n"); } } - // line 242 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r0() - { - $this->root_buffer->prepend_array($this, $this->template_prefix); - $this->root_buffer->append_array($this, $this->template_postfix); - $this->_retvalue = $this->root_buffer->to_smarty_php($this); + public static $yyRuleInfo = array( + array( 0 => 62, 1 => 1 ), + array( 0 => 63, 1 => 2 ), + array( 0 => 63, 1 => 2 ), + array( 0 => 63, 1 => 2 ), + array( 0 => 63, 1 => 4 ), + array( 0 => 64, 1 => 4 ), + array( 0 => 64, 1 => 1 ), + array( 0 => 65, 1 => 2 ), + array( 0 => 65, 1 => 0 ), + array( 0 => 63, 1 => 2 ), + array( 0 => 63, 1 => 0 ), + array( 0 => 66, 1 => 1 ), + array( 0 => 66, 1 => 1 ), + array( 0 => 66, 1 => 1 ), + array( 0 => 66, 1 => 3 ), + array( 0 => 66, 1 => 2 ), + array( 0 => 67, 1 => 1 ), + array( 0 => 67, 1 => 2 ), + array( 0 => 67, 1 => 2 ), + array( 0 => 70, 1 => 2 ), + array( 0 => 69, 1 => 2 ), + array( 0 => 72, 1 => 1 ), + array( 0 => 72, 1 => 1 ), + array( 0 => 72, 1 => 1 ), + array( 0 => 68, 1 => 3 ), + array( 0 => 68, 1 => 2 ), + array( 0 => 68, 1 => 4 ), + array( 0 => 68, 1 => 5 ), + array( 0 => 68, 1 => 6 ), + array( 0 => 68, 1 => 2 ), + array( 0 => 68, 1 => 2 ), + array( 0 => 68, 1 => 3 ), + array( 0 => 68, 1 => 2 ), + array( 0 => 68, 1 => 3 ), + array( 0 => 68, 1 => 8 ), + array( 0 => 80, 1 => 2 ), + array( 0 => 80, 1 => 1 ), + array( 0 => 68, 1 => 5 ), + array( 0 => 68, 1 => 7 ), + array( 0 => 68, 1 => 6 ), + array( 0 => 68, 1 => 8 ), + array( 0 => 68, 1 => 2 ), + array( 0 => 68, 1 => 3 ), + array( 0 => 68, 1 => 4 ), + array( 0 => 66, 1 => 1 ), + array( 0 => 68, 1 => 2 ), + array( 0 => 68, 1 => 3 ), + array( 0 => 68, 1 => 4 ), + array( 0 => 68, 1 => 5 ), + array( 0 => 73, 1 => 2 ), + array( 0 => 73, 1 => 1 ), + array( 0 => 73, 1 => 0 ), + array( 0 => 83, 1 => 4 ), + array( 0 => 83, 1 => 2 ), + array( 0 => 83, 1 => 2 ), + array( 0 => 83, 1 => 2 ), + array( 0 => 83, 1 => 2 ), + array( 0 => 83, 1 => 2 ), + array( 0 => 83, 1 => 4 ), + array( 0 => 79, 1 => 1 ), + array( 0 => 79, 1 => 3 ), + array( 0 => 78, 1 => 3 ), + array( 0 => 78, 1 => 3 ), + array( 0 => 78, 1 => 3 ), + array( 0 => 78, 1 => 3 ), + array( 0 => 76, 1 => 1 ), + array( 0 => 76, 1 => 1 ), + array( 0 => 76, 1 => 3 ), + array( 0 => 76, 1 => 3 ), + array( 0 => 76, 1 => 3 ), + array( 0 => 76, 1 => 3 ), + array( 0 => 76, 1 => 3 ), + array( 0 => 76, 1 => 2 ), + array( 0 => 76, 1 => 3 ), + array( 0 => 76, 1 => 3 ), + array( 0 => 84, 1 => 7 ), + array( 0 => 84, 1 => 7 ), + array( 0 => 75, 1 => 1 ), + array( 0 => 75, 1 => 2 ), + array( 0 => 75, 1 => 2 ), + array( 0 => 75, 1 => 2 ), + array( 0 => 75, 1 => 2 ), + array( 0 => 75, 1 => 1 ), + array( 0 => 75, 1 => 1 ), + array( 0 => 75, 1 => 3 ), + array( 0 => 75, 1 => 2 ), + array( 0 => 75, 1 => 2 ), + array( 0 => 75, 1 => 1 ), + array( 0 => 75, 1 => 1 ), + array( 0 => 75, 1 => 3 ), + array( 0 => 75, 1 => 3 ), + array( 0 => 75, 1 => 3 ), + array( 0 => 75, 1 => 1 ), + array( 0 => 75, 1 => 1 ), + array( 0 => 75, 1 => 3 ), + array( 0 => 75, 1 => 1 ), + array( 0 => 75, 1 => 2 ), + array( 0 => 75, 1 => 1 ), + array( 0 => 75, 1 => 1 ), + array( 0 => 75, 1 => 3 ), + array( 0 => 90, 1 => 1 ), + array( 0 => 90, 1 => 1 ), + array( 0 => 74, 1 => 1 ), + array( 0 => 74, 1 => 1 ), + array( 0 => 74, 1 => 3 ), + array( 0 => 74, 1 => 1 ), + array( 0 => 74, 1 => 3 ), + array( 0 => 74, 1 => 4 ), + array( 0 => 74, 1 => 3 ), + array( 0 => 74, 1 => 4 ), + array( 0 => 71, 1 => 2 ), + array( 0 => 71, 1 => 2 ), + array( 0 => 95, 1 => 2 ), + array( 0 => 95, 1 => 0 ), + array( 0 => 96, 1 => 2 ), + array( 0 => 96, 1 => 2 ), + array( 0 => 96, 1 => 4 ), + array( 0 => 96, 1 => 2 ), + array( 0 => 96, 1 => 2 ), + array( 0 => 96, 1 => 4 ), + array( 0 => 96, 1 => 3 ), + array( 0 => 96, 1 => 5 ), + array( 0 => 96, 1 => 3 ), + array( 0 => 96, 1 => 3 ), + array( 0 => 96, 1 => 3 ), + array( 0 => 96, 1 => 3 ), + array( 0 => 96, 1 => 3 ), + array( 0 => 96, 1 => 3 ), + array( 0 => 96, 1 => 2 ), + array( 0 => 81, 1 => 1 ), + array( 0 => 81, 1 => 1 ), + array( 0 => 81, 1 => 2 ), + array( 0 => 97, 1 => 1 ), + array( 0 => 97, 1 => 1 ), + array( 0 => 97, 1 => 3 ), + array( 0 => 94, 1 => 2 ), + array( 0 => 98, 1 => 1 ), + array( 0 => 98, 1 => 2 ), + array( 0 => 99, 1 => 3 ), + array( 0 => 99, 1 => 3 ), + array( 0 => 99, 1 => 5 ), + array( 0 => 99, 1 => 6 ), + array( 0 => 99, 1 => 2 ), + array( 0 => 89, 1 => 4 ), + array( 0 => 100, 1 => 4 ), + array( 0 => 100, 1 => 4 ), + array( 0 => 101, 1 => 3 ), + array( 0 => 101, 1 => 1 ), + array( 0 => 101, 1 => 0 ), + array( 0 => 77, 1 => 3 ), + array( 0 => 77, 1 => 2 ), + array( 0 => 102, 1 => 3 ), + array( 0 => 102, 1 => 2 ), + array( 0 => 82, 1 => 2 ), + array( 0 => 82, 1 => 0 ), + array( 0 => 103, 1 => 2 ), + array( 0 => 103, 1 => 3 ), + array( 0 => 103, 1 => 2 ), + array( 0 => 92, 1 => 1 ), + array( 0 => 92, 1 => 2 ), + array( 0 => 92, 1 => 1 ), + array( 0 => 92, 1 => 2 ), + array( 0 => 92, 1 => 3 ), + array( 0 => 86, 1 => 1 ), + array( 0 => 86, 1 => 1 ), + array( 0 => 85, 1 => 1 ), + array( 0 => 87, 1 => 1 ), + array( 0 => 93, 1 => 3 ), + array( 0 => 93, 1 => 3 ), + array( 0 => 104, 1 => 1 ), + array( 0 => 104, 1 => 3 ), + array( 0 => 104, 1 => 0 ), + array( 0 => 105, 1 => 3 ), + array( 0 => 105, 1 => 3 ), + array( 0 => 105, 1 => 1 ), + array( 0 => 91, 1 => 2 ), + array( 0 => 91, 1 => 3 ), + array( 0 => 106, 1 => 2 ), + array( 0 => 106, 1 => 1 ), + array( 0 => 107, 1 => 3 ), + array( 0 => 107, 1 => 3 ), + array( 0 => 107, 1 => 1 ), + array( 0 => 107, 1 => 3 ), + array( 0 => 107, 1 => 3 ), + array( 0 => 107, 1 => 1 ), + array( 0 => 107, 1 => 1 ), + ); + + public static $yyReduceMap = array( + 0 => 0, + 1 => 1, + 2 => 2, + 3 => 3, + 4 => 4, + 5 => 5, + 6 => 6, + 21 => 6, + 22 => 6, + 23 => 6, + 36 => 6, + 56 => 6, + 57 => 6, + 65 => 6, + 66 => 6, + 77 => 6, + 82 => 6, + 83 => 6, + 88 => 6, + 92 => 6, + 93 => 6, + 97 => 6, + 98 => 6, + 100 => 6, + 105 => 6, + 169 => 6, + 174 => 6, + 7 => 7, + 8 => 8, + 9 => 9, + 11 => 11, + 12 => 12, + 13 => 13, + 14 => 14, + 15 => 15, + 16 => 16, + 17 => 17, + 18 => 18, + 19 => 19, + 20 => 20, + 24 => 24, + 25 => 25, + 26 => 26, + 27 => 27, + 28 => 28, + 29 => 29, + 30 => 30, + 31 => 31, + 33 => 31, + 32 => 32, + 34 => 34, + 35 => 35, + 37 => 37, + 38 => 38, + 39 => 39, + 40 => 40, + 41 => 41, + 42 => 42, + 43 => 43, + 44 => 44, + 45 => 45, + 46 => 46, + 47 => 47, + 48 => 48, + 49 => 49, + 50 => 50, + 59 => 50, + 147 => 50, + 151 => 50, + 155 => 50, + 157 => 50, + 51 => 51, + 148 => 51, + 154 => 51, + 52 => 52, + 53 => 53, + 54 => 53, + 55 => 55, + 132 => 55, + 58 => 58, + 60 => 60, + 61 => 61, + 62 => 61, + 63 => 63, + 64 => 64, + 67 => 67, + 68 => 68, + 69 => 68, + 70 => 70, + 71 => 71, + 72 => 72, + 73 => 73, + 74 => 74, + 75 => 75, + 76 => 76, + 78 => 78, + 80 => 78, + 81 => 78, + 112 => 78, + 79 => 79, + 84 => 84, + 85 => 85, + 86 => 86, + 87 => 87, + 89 => 89, + 90 => 90, + 91 => 90, + 94 => 94, + 95 => 95, + 96 => 96, + 99 => 99, + 101 => 101, + 102 => 102, + 103 => 103, + 104 => 104, + 106 => 106, + 107 => 107, + 108 => 108, + 109 => 109, + 110 => 110, + 111 => 111, + 113 => 113, + 171 => 113, + 114 => 114, + 115 => 115, + 116 => 116, + 117 => 117, + 118 => 118, + 119 => 119, + 127 => 119, + 120 => 120, + 121 => 121, + 122 => 122, + 123 => 122, + 125 => 122, + 126 => 122, + 124 => 124, + 128 => 128, + 129 => 129, + 130 => 130, + 175 => 130, + 131 => 131, + 133 => 133, + 134 => 134, + 135 => 135, + 136 => 136, + 137 => 137, + 138 => 138, + 139 => 139, + 140 => 140, + 141 => 141, + 142 => 142, + 143 => 143, + 144 => 144, + 145 => 145, + 146 => 146, + 149 => 149, + 150 => 150, + 152 => 152, + 153 => 153, + 156 => 156, + 158 => 158, + 159 => 159, + 160 => 160, + 161 => 161, + 162 => 162, + 163 => 163, + 164 => 164, + 165 => 165, + 166 => 166, + 167 => 167, + 168 => 167, + 170 => 170, + 172 => 172, + 173 => 173, + 176 => 176, + 177 => 177, + 178 => 178, + 179 => 179, + 182 => 179, + 180 => 180, + 183 => 180, + 181 => 181, + 184 => 184, + 185 => 185, + ); +// line 233 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r0(){ + $this->root_buffer->prepend_array($this, $this->template_prefix); + $this->root_buffer->append_array($this, $this->template_postfix); + $this->_retvalue = $this->root_buffer->to_smarty_php($this); } +// line 240 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r1(){ + $text = $this->yystack[ $this->yyidx + 0 ]->minor; - // line 251 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r1() - { - $code = - $this->compiler->compileTag('private_php', - array(array('code' => $this->yystack[ $this->yyidx + 0 ]->minor), array('type' => $this->lex->phpType)), - array()); - if ($this->compiler->has_code && !empty($code)) { - $tmp = ''; - foreach ($this->compiler->prefix_code as $code) { - $tmp .= $code; - } - $this->compiler->prefix_code = array(); - $this->current_buffer->append_subtree($this, - new Smarty_Internal_ParseTree_Tag($this, $this->compiler->processNocacheCode($tmp . $code, true))); - } + if ((string)$text == '') { + $this->current_buffer->append_subtree($this, null); + } + + $this->current_buffer->append_subtree($this, new Smarty_Internal_ParseTree_Text($text, $this->strip)); } - - // line 255 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r2() - { - $text = $this->yystack[ $this->yyidx + 0 ]->minor; - - if ((string)$text == '') { - $this->current_buffer->append_subtree($this, null); - } - - $this->current_buffer->append_subtree($this, new Smarty_Internal_ParseTree_Text($text, $this->strip)); +// line 250 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r2(){ + $this->strip = true; } +// line 254 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r3(){ + $this->strip = false; + } +// line 259 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r4(){ + $this->current_buffer->append_subtree($this, new Smarty_Internal_ParseTree_Text($this->yystack[$this->yyidx + -1]->minor)); + } +// line 264 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r5(){ + $this->_retvalue = $this->yystack[$this->yyidx + -3]->minor.$this->yystack[$this->yyidx + -1]->minor; + } +// line 267 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r6(){ + $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; + } +// line 271 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r7(){ + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; - // line 259 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r3() - { + } +// line 276 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r8(){ + $this->_retvalue = ''; + } +// line 280 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r9(){ + if ($this->compiler->has_code) { + $this->current_buffer->append_subtree($this, $this->mergePrefixCode($this->yystack[$this->yyidx + 0]->minor)); + } + $this->compiler->has_variable_string = false; + $this->block_nesting_level = count($this->compiler->_tag_stack); + } +// line 292 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r11(){ + $var = trim(substr($this->yystack[$this->yyidx + 0]->minor, $this->compiler->getLdelLength(), -$this->compiler->getRdelLength()), ' $'); + if (preg_match('/^(.*)(\s+nocache)$/', $var, $match)) { + $this->_retvalue = $this->compiler->compileTag('private_print_expression',array('nocache'),array('value'=>$this->compiler->compileVariable('\''.$match[1].'\''))); + } else { + $this->_retvalue = $this->compiler->compileTag('private_print_expression',array(),array('value'=>$this->compiler->compileVariable('\''.$var.'\''))); + } + } +// line 302 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r12(){ + $tag = trim(substr($this->yystack[$this->yyidx + 0]->minor, $this->compiler->getLdelLength(), -$this->compiler->getRdelLength())); + if ($tag == 'strip') { $this->strip = true; + $this->_retvalue = null; + } else { + if (defined($tag)) { + if ($this->security) { + $this->security->isTrustedConstant($tag, $this->compiler); + } + $this->_retvalue = $this->compiler->compileTag('private_print_expression',array(),array('value'=>$tag)); + } else { + if (preg_match('/^(.*)(\s+nocache)$/', $tag, $match)) { + $this->_retvalue = $this->compiler->compileTag($match[1],array('\'nocache\'')); + } else { + $this->_retvalue = $this->compiler->compileTag($tag,array()); + } + } } - - // line 264 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r4() - { + } +// line 323 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r13(){ + $j = strrpos($this->yystack[$this->yyidx + 0]->minor,'.'); + if ($this->yystack[$this->yyidx + 0]->minor[$j+1] == 'c') { + // {$smarty.block.child} + $this->_retvalue = $this->compiler->compileTag('child',array(),array($this->yystack[$this->yyidx + 0]->minor)); + } else { + // {$smarty.block.parent} + $this->_retvalue = $this->compiler->compileTag('parent',array(),array($this->yystack[$this->yyidx + 0]->minor)); + } + } +// line 334 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r14(){ + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor; + } +// line 338 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r15(){ + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor; + } +// line 342 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r16(){ + $this->_retvalue = $this->compiler->compileTag('private_print_expression',$this->yystack[$this->yyidx + 0]->minor[1],array('value'=>$this->yystack[$this->yyidx + 0]->minor[0])); + } +// line 351 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r17(){ + $this->_retvalue = $this->compiler->compileTag('assign',array_merge(array(array('value'=>$this->yystack[$this->yyidx + 0]->minor[0]),array('var'=>'\''.substr($this->yystack[$this->yyidx + -1]->minor,1).'\'')),$this->yystack[$this->yyidx + 0]->minor[1])); + } +// line 355 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r18(){ + $this->_retvalue = $this->compiler->compileTag('assign',array_merge(array(array('value'=>$this->yystack[$this->yyidx + 0]->minor[0]),array('var'=>$this->yystack[$this->yyidx + -1]->minor['var'])),$this->yystack[$this->yyidx + 0]->minor[1]),array('smarty_internal_index'=>$this->yystack[$this->yyidx + -1]->minor['smarty_internal_index'])); + } +// line 359 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r19(){ + $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; + } +// line 363 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r20(){ + $this->_retvalue = array($this->yystack[$this->yyidx + -1]->minor,$this->yystack[$this->yyidx + 0]->minor); + } +// line 378 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r24(){ + if (defined($this->yystack[$this->yyidx + -1]->minor)) { + if ($this->security) { + $this->security->isTrustedConstant($this->yystack[$this->yyidx + -1]->minor, $this->compiler); + } + $this->_retvalue = $this->compiler->compileTag('private_print_expression',$this->yystack[$this->yyidx + 0]->minor,array('value'=>$this->yystack[$this->yyidx + -1]->minor)); + } else { + $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + -1]->minor,$this->yystack[$this->yyidx + 0]->minor); + } + } +// line 388 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r25(){ + if (defined($this->yystack[$this->yyidx + 0]->minor)) { + if ($this->security) { + $this->security->isTrustedConstant($this->yystack[$this->yyidx + 0]->minor, $this->compiler); + } + $this->_retvalue = $this->compiler->compileTag('private_print_expression',array(),array('value'=>$this->yystack[$this->yyidx + 0]->minor)); + } else { + $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + 0]->minor,array()); + } + } +// line 401 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r26(){ + if (defined($this->yystack[$this->yyidx + -2]->minor)) { + if ($this->security) { + $this->security->isTrustedConstant($this->yystack[$this->yyidx + -2]->minor, $this->compiler); + } + $this->_retvalue = $this->compiler->compileTag('private_print_expression',$this->yystack[$this->yyidx + 0]->minor,array('value'=>$this->yystack[$this->yyidx + -2]->minor, 'modifierlist'=>$this->yystack[$this->yyidx + -1]->minor)); + } else { + $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + -2]->minor,$this->yystack[$this->yyidx + 0]->minor, array('modifierlist'=>$this->yystack[$this->yyidx + -1]->minor)); + } + } +// line 413 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r27(){ + $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + -3]->minor,$this->yystack[$this->yyidx + 0]->minor,array('object_method'=>$this->yystack[$this->yyidx + -1]->minor)); + } +// line 418 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r28(){ + $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + -4]->minor,$this->yystack[$this->yyidx + 0]->minor,array('modifierlist'=>$this->yystack[$this->yyidx + -1]->minor, 'object_method'=>$this->yystack[$this->yyidx + -2]->minor)); + } +// line 423 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r29(){ + $this->_retvalue = $this->compiler->compileTag('make_nocache',array(array('var'=>'\''.substr($this->yystack[$this->yyidx + 0]->minor,1).'\''))); + } +// line 428 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r30(){ + $tag = trim(substr($this->yystack[$this->yyidx + -1]->minor,$this->compiler->getLdelLength())); + $this->_retvalue = $this->compiler->compileTag(($tag === 'else if')? 'elseif' : $tag,array(),array('if condition'=>$this->yystack[$this->yyidx + 0]->minor)); + } +// line 433 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r31(){ + $tag = trim(substr($this->yystack[$this->yyidx + -2]->minor,$this->compiler->getLdelLength())); + $this->_retvalue = $this->compiler->compileTag(($tag === 'else if')? 'elseif' : $tag,$this->yystack[$this->yyidx + 0]->minor,array('if condition'=>$this->yystack[$this->yyidx + -1]->minor)); + } +// line 438 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r32(){ + $tag = trim(substr($this->yystack[$this->yyidx + -1]->minor,$this->compiler->getLdelLength())); + $this->_retvalue = $this->compiler->compileTag(($tag === 'else if')? 'elseif' : $tag,array(),array('if condition'=>$this->yystack[$this->yyidx + 0]->minor)); + } +// line 449 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r34(){ + $this->_retvalue = $this->compiler->compileTag('for',array_merge($this->yystack[$this->yyidx + 0]->minor,array(array('start'=>$this->yystack[$this->yyidx + -6]->minor),array('ifexp'=>$this->yystack[$this->yyidx + -4]->minor),array('var'=>$this->yystack[$this->yyidx + -2]->minor),array('step'=>$this->yystack[$this->yyidx + -1]->minor))),1); + } +// line 453 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r35(){ + $this->_retvalue = '='.$this->yystack[$this->yyidx + 0]->minor; + } +// line 461 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r37(){ + $this->_retvalue = $this->compiler->compileTag('for',array_merge($this->yystack[$this->yyidx + 0]->minor,array(array('start'=>$this->yystack[$this->yyidx + -3]->minor),array('to'=>$this->yystack[$this->yyidx + -1]->minor))),0); + } +// line 465 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r38(){ + $this->_retvalue = $this->compiler->compileTag('for',array_merge($this->yystack[$this->yyidx + 0]->minor,array(array('start'=>$this->yystack[$this->yyidx + -5]->minor),array('to'=>$this->yystack[$this->yyidx + -3]->minor),array('step'=>$this->yystack[$this->yyidx + -1]->minor))),0); + } +// line 470 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r39(){ + $this->_retvalue = $this->compiler->compileTag('foreach',array_merge($this->yystack[$this->yyidx + 0]->minor,array(array('from'=>$this->yystack[$this->yyidx + -3]->minor),array('item'=>$this->yystack[$this->yyidx + -1]->minor)))); + } +// line 474 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r40(){ + $this->_retvalue = $this->compiler->compileTag('foreach',array_merge($this->yystack[$this->yyidx + 0]->minor,array(array('from'=>$this->yystack[$this->yyidx + -5]->minor),array('item'=>$this->yystack[$this->yyidx + -1]->minor),array('key'=>$this->yystack[$this->yyidx + -3]->minor)))); + } +// line 477 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r41(){ + $this->_retvalue = $this->compiler->compileTag('foreach',$this->yystack[$this->yyidx + 0]->minor); + } +// line 482 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r42(){ + $this->_retvalue = $this->compiler->compileTag('setfilter',array(),array('modifier_list'=>array(array_merge(array($this->yystack[$this->yyidx + -1]->minor),$this->yystack[$this->yyidx + 0]->minor)))); + } +// line 486 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r43(){ + $this->_retvalue = $this->compiler->compileTag('setfilter',array(),array('modifier_list'=>array_merge(array(array_merge(array($this->yystack[$this->yyidx + -2]->minor),$this->yystack[$this->yyidx + -1]->minor)),$this->yystack[$this->yyidx + 0]->minor))); + } +// line 492 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r44(){ + $tag = trim(substr($this->yystack[$this->yyidx + 0]->minor, $this->compiler->getLdelLength(), -$this->compiler->getRdelLength()), ' /'); + if ($tag === 'strip') { $this->strip = false; - } - - // line 269 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r5() - { - $this->current_buffer->append_subtree($this, - new Smarty_Internal_ParseTree_Text($this->yystack[ $this->yyidx + -1 ]->minor)); - } - - // line 272 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r6() - { - $this->_retvalue = $this->yystack[ $this->yyidx + -3 ]->minor . $this->yystack[ $this->yyidx + -1 ]->minor; - } - - // line 276 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r7() - { - $this->_retvalue = $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 281 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r8() - { - $this->_retvalue = $this->yystack[ $this->yyidx + -1 ]->minor . $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 285 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r9() - { - $this->_retvalue = ''; - } - - // line 297 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r10() - { - if ($this->compiler->has_code) { - $this->current_buffer->append_subtree($this, - $this->mergePrefixCode($this->yystack[ $this->yyidx + 0 ]->minor)); - } - $this->compiler->has_variable_string = false; - $this->block_nesting_level = count($this->compiler->_tag_stack); - } - - // line 307 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r12() - { - $var = - trim(substr($this->yystack[ $this->yyidx + 0 ]->minor, $this->compiler->getLdelLength(), - -$this->compiler->getRdelLength()), ' $'); - if (preg_match('/^(.*)(\s+nocache)$/', $var, $match)) { - $this->_retvalue = - $this->compiler->compileTag('private_print_expression', array('nocache'), - array('value' => $this->compiler->compileVariable('\'' . $match[ 1 ] . '\''))); - } else { - $this->_retvalue = - $this->compiler->compileTag('private_print_expression', array(), - array('value' => $this->compiler->compileVariable('\'' . $var . '\''))); - } - } - - // line 328 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r13() - { - $tag = - trim(substr($this->yystack[ $this->yyidx + 0 ]->minor, $this->compiler->getLdelLength(), - -$this->compiler->getRdelLength())); - if ($tag == 'strip') { - $this->strip = true; - $this->_retvalue = null; - } else { - if (defined($tag)) { - if ($this->security) { - $this->security->isTrustedConstant($tag, $this->compiler); - } - $this->_retvalue = - $this->compiler->compileTag('private_print_expression', array(), array('value' => $tag)); - } else { - if (preg_match('/^(.*)(\s+nocache)$/', $tag, $match)) { - $this->_retvalue = $this->compiler->compileTag($match[ 1 ], array('\'nocache\'')); - } else { - $this->_retvalue = $this->compiler->compileTag($tag, array()); - } - } - } - } - - // line 339 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r14() - { - $j = strrpos($this->yystack[ $this->yyidx + 0 ]->minor, '.'); - if ($this->yystack[ $this->yyidx + 0 ]->minor[ $j + 1 ] == 'c') { - // {$smarty.block.child} - $this->_retvalue = - $this->compiler->compileTag('child', array(), array($this->yystack[ $this->yyidx + 0 ]->minor)); - } else { - // {$smarty.block.parent} - $this->_retvalue = - $this->compiler->compileTag('parent', array(), array($this->yystack[ $this->yyidx + 0 ]->minor)); - } - } - - // line 343 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r15() - { - $this->_retvalue = $this->yystack[ $this->yyidx + -1 ]->minor; - } - - // line 347 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r16() - { - $this->_retvalue = $this->yystack[ $this->yyidx + -1 ]->minor; - } - - // line 356 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r17() - { - $this->_retvalue = - $this->compiler->compileTag('private_print_expression', $this->yystack[ $this->yyidx + 0 ]->minor[ 1 ], - array('value' => $this->yystack[ $this->yyidx + 0 ]->minor[ 0 ])); - } - - // line 360 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r18() - { - $this->_retvalue = - $this->compiler->compileTag('assign', array_merge(array( - array('value' => $this->yystack[ $this->yyidx + 0 ]->minor[ 0 ]), - array('var' => '\'' . substr($this->yystack[ $this->yyidx + -1 ]->minor, 1) . '\'') - ), $this->yystack[ $this->yyidx + 0 ]->minor[ 1 ])); - } - - // line 364 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r19() - { - $this->_retvalue = - $this->compiler->compileTag('assign', array_merge(array( - array('value' => $this->yystack[ $this->yyidx + 0 ]->minor[ 0 ]), - array('var' => $this->yystack[ $this->yyidx + -1 ]->minor[ 'var' ]) - ), $this->yystack[ $this->yyidx + 0 ]->minor[ 1 ]), array( - 'smarty_internal_index' => $this->yystack[ $this->yyidx + - -1 ]->minor[ 'smarty_internal_index' ] - )); - } - - // line 368 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r20() - { - $this->_retvalue = $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 383 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r21() - { - $this->_retvalue = array($this->yystack[ $this->yyidx + -1 ]->minor, $this->yystack[ $this->yyidx + 0 ]->minor); - } - - // line 393 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r25() - { - if (defined($this->yystack[ $this->yyidx + -1 ]->minor)) { - if ($this->security) { - $this->security->isTrustedConstant($this->yystack[ $this->yyidx + -1 ]->minor, $this->compiler); - } - $this->_retvalue = - $this->compiler->compileTag('private_print_expression', $this->yystack[ $this->yyidx + 0 ]->minor, - array('value' => $this->yystack[ $this->yyidx + -1 ]->minor)); - } else { - $this->_retvalue = - $this->compiler->compileTag($this->yystack[ $this->yyidx + -1 ]->minor, - $this->yystack[ $this->yyidx + 0 ]->minor); - } - } - - // line 406 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r26() - { - if (defined($this->yystack[ $this->yyidx + 0 ]->minor)) { - if ($this->security) { - $this->security->isTrustedConstant($this->yystack[ $this->yyidx + 0 ]->minor, $this->compiler); - } - $this->_retvalue = - $this->compiler->compileTag('private_print_expression', array(), - array('value' => $this->yystack[ $this->yyidx + 0 ]->minor)); - } else { - $this->_retvalue = $this->compiler->compileTag($this->yystack[ $this->yyidx + 0 ]->minor, array()); - } - } - - // line 418 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r27() - { - if (defined($this->yystack[ $this->yyidx + -2 ]->minor)) { - if ($this->security) { - $this->security->isTrustedConstant($this->yystack[ $this->yyidx + -2 ]->minor, $this->compiler); - } - $this->_retvalue = - $this->compiler->compileTag('private_print_expression', $this->yystack[ $this->yyidx + 0 ]->minor, - array( - 'value' => $this->yystack[ $this->yyidx + -2 ]->minor, - 'modifierlist' => $this->yystack[ $this->yyidx + -1 ]->minor - )); - } else { - $this->_retvalue = - $this->compiler->compileTag($this->yystack[ $this->yyidx + -2 ]->minor, - $this->yystack[ $this->yyidx + 0 ]->minor, - array('modifierlist' => $this->yystack[ $this->yyidx + -1 ]->minor)); - } - } - - // line 423 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r28() - { - $this->_retvalue = - $this->compiler->compileTag($this->yystack[ $this->yyidx + -3 ]->minor, - $this->yystack[ $this->yyidx + 0 ]->minor, - array('object_method' => $this->yystack[ $this->yyidx + -1 ]->minor)); - } - - // line 428 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r29() - { - $this->_retvalue = - $this->compiler->compileTag($this->yystack[ $this->yyidx + -4 ]->minor, - $this->yystack[ $this->yyidx + 0 ]->minor, array( - 'modifierlist' => $this->yystack[ $this->yyidx + -1 ]->minor, - 'object_method' => $this->yystack[ $this->yyidx + -2 ]->minor - )); - } - - // line 433 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r30() - { - $this->_retvalue = - $this->compiler->compileTag('make_nocache', - array(array('var' => '\'' . substr($this->yystack[ $this->yyidx + 0 ]->minor, 1) . '\''))); - } - - // line 438 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r31() - { - $tag = trim(substr($this->yystack[ $this->yyidx + -1 ]->minor, $this->compiler->getLdelLength())); - $this->_retvalue = - $this->compiler->compileTag(($tag === 'else if') ? 'elseif' : $tag, array(), - array('if condition' => $this->yystack[ $this->yyidx + 0 ]->minor)); - } - - // line 443 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r32() - { - $tag = trim(substr($this->yystack[ $this->yyidx + -2 ]->minor, $this->compiler->getLdelLength())); - $this->_retvalue = - $this->compiler->compileTag(($tag === 'else if') ? 'elseif' : $tag, - $this->yystack[ $this->yyidx + 0 ]->minor, - array('if condition' => $this->yystack[ $this->yyidx + -1 ]->minor)); - } - - // line 454 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r33() - { - $tag = trim(substr($this->yystack[ $this->yyidx + -1 ]->minor, $this->compiler->getLdelLength())); - $this->_retvalue = - $this->compiler->compileTag(($tag === 'else if') ? 'elseif' : $tag, array(), - array('if condition' => $this->yystack[ $this->yyidx + 0 ]->minor)); - } - - // line 458 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r35() - { - $this->_retvalue = - $this->compiler->compileTag('for', array_merge($this->yystack[ $this->yyidx + 0 ]->minor, array( - array('start' => $this->yystack[ $this->yyidx + -6 ]->minor), - array('ifexp' => $this->yystack[ $this->yyidx + -4 ]->minor), - array('var' => $this->yystack[ $this->yyidx + -2 ]->minor), - array('step' => $this->yystack[ $this->yyidx + -1 ]->minor) - )), 1); - } - - // line 466 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r36() - { - $this->_retvalue = '=' . $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 470 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r38() - { - $this->_retvalue = - $this->compiler->compileTag('for', array_merge($this->yystack[ $this->yyidx + 0 ]->minor, array( - array('start' => $this->yystack[ $this->yyidx + -3 ]->minor), - array('to' => $this->yystack[ $this->yyidx + -1 ]->minor) - )), 0); - } - - // line 475 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r39() - { - $this->_retvalue = - $this->compiler->compileTag('for', array_merge($this->yystack[ $this->yyidx + 0 ]->minor, array( - array('start' => $this->yystack[ $this->yyidx + -5 ]->minor), - array('to' => $this->yystack[ $this->yyidx + -3 ]->minor), - array('step' => $this->yystack[ $this->yyidx + -1 ]->minor) - )), 0); - } - - // line 479 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r40() - { - $this->_retvalue = - $this->compiler->compileTag('foreach', array_merge($this->yystack[ $this->yyidx + 0 ]->minor, array( - array('from' => $this->yystack[ $this->yyidx + -3 ]->minor), - array('item' => $this->yystack[ $this->yyidx + -1 ]->minor) - ))); - } - - // line 482 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r41() - { - $this->_retvalue = - $this->compiler->compileTag('foreach', array_merge($this->yystack[ $this->yyidx + 0 ]->minor, array( - array('from' => $this->yystack[ $this->yyidx + -5 ]->minor), - array('item' => $this->yystack[ $this->yyidx + -1 ]->minor), - array('key' => $this->yystack[ $this->yyidx + -3 ]->minor) - ))); - } - - // line 487 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r42() - { - $this->_retvalue = $this->compiler->compileTag('foreach', $this->yystack[ $this->yyidx + 0 ]->minor); - } - - // line 491 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r43() - { - $this->_retvalue = - $this->compiler->compileTag('setfilter', array(), array( - 'modifier_list' => array( - array_merge(array($this->yystack[ $this->yyidx + -1 ]->minor), - $this->yystack[ $this->yyidx + 0 ]->minor) - ) - )); - } - - // line 497 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r44() - { - $this->_retvalue = - $this->compiler->compileTag('setfilter', array(), array( - 'modifier_list' => array_merge(array( - array_merge(array( - $this->yystack[ $this->yyidx + - -2 ]->minor - ), $this->yystack[ $this->yyidx + -1 ]->minor) - ), $this->yystack[ $this->yyidx + 0 ]->minor) - )); - } - - // line 506 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r45() - { - $tag = - trim(substr($this->yystack[ $this->yyidx + 0 ]->minor, $this->compiler->getLdelLength(), - -$this->compiler->getRdelLength()), ' /'); - if ($tag === 'strip') { - $this->strip = false; - $this->_retvalue = null; - } else { - $this->_retvalue = $this->compiler->compileTag($tag . 'close', array()); - } - } - - // line 510 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r46() - { - $this->_retvalue = $this->compiler->compileTag($this->yystack[ $this->yyidx + 0 ]->minor . 'close', array()); - } - - // line 515 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r47() - { - $this->_retvalue = - $this->compiler->compileTag($this->yystack[ $this->yyidx + -1 ]->minor . 'close', array(), - array('modifier_list' => $this->yystack[ $this->yyidx + 0 ]->minor)); - } - - // line 519 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r48() - { - $this->_retvalue = - $this->compiler->compileTag($this->yystack[ $this->yyidx + -2 ]->minor . 'close', array(), - array('object_method' => $this->yystack[ $this->yyidx + 0 ]->minor)); - } - - // line 527 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r49() - { - $this->_retvalue = - $this->compiler->compileTag($this->yystack[ $this->yyidx + -3 ]->minor . 'close', array(), array( - 'object_method' => $this->yystack[ $this->yyidx + -1 ]->minor, - 'modifier_list' => $this->yystack[ $this->yyidx + 0 ]->minor - )); - } - - // line 533 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r50() - { - $this->_retvalue = $this->yystack[ $this->yyidx + -1 ]->minor; - $this->_retvalue[] = $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 538 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r51() - { - $this->_retvalue = array($this->yystack[ $this->yyidx + 0 ]->minor); - } - - // line 543 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r52() - { - $this->_retvalue = array(); - } - - // line 554 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r53() - { - if (defined($this->yystack[ $this->yyidx + 0 ]->minor)) { - if ($this->security) { - $this->security->isTrustedConstant($this->yystack[ $this->yyidx + 0 ]->minor, $this->compiler); - } - $this->_retvalue = - array($this->yystack[ $this->yyidx + -2 ]->minor => $this->yystack[ $this->yyidx + 0 ]->minor); - } else { - $this->_retvalue = - array( - $this->yystack[ $this->yyidx + -2 ]->minor => '\'' . - $this->yystack[ $this->yyidx + 0 ]->minor . - '\'' - ); - } - } - - // line 562 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r54() - { - $this->_retvalue = - array( - trim($this->yystack[ $this->yyidx + -1 ]->minor, " =\n\r\t") => $this->yystack[ $this->yyidx + - 0 ]->minor - ); - } - - // line 574 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r56() - { - $this->_retvalue = '\'' . $this->yystack[ $this->yyidx + 0 ]->minor . '\''; - } - - // line 587 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r59() - { - $this->_retvalue = - array($this->yystack[ $this->yyidx + -2 ]->minor => $this->yystack[ $this->yyidx + 0 ]->minor); - } - - // line 592 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r61() - { - $this->yystack[ $this->yyidx + -2 ]->minor[] = $this->yystack[ $this->yyidx + 0 ]->minor; - $this->_retvalue = $this->yystack[ $this->yyidx + -2 ]->minor; - } - - // line 599 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r62() - { - $this->_retvalue = - array( - 'var' => '\'' . substr($this->yystack[ $this->yyidx + -2 ]->minor, 1) . '\'', - 'value' => $this->yystack[ $this->yyidx + 0 ]->minor - ); - } - - // line 603 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r64() - { - $this->_retvalue = - array( - 'var' => $this->yystack[ $this->yyidx + -2 ]->minor, - 'value' => $this->yystack[ $this->yyidx + 0 ]->minor - ); - } - - // line 623 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r65() - { - $this->_retvalue = $this->yystack[ $this->yyidx + -1 ]->minor; - } - - // line 628 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r68() - { - $this->_retvalue = - '$_smarty_tpl->getStreamVariable(\'' . - substr($this->yystack[ $this->yyidx + -2 ]->minor, 1) . - '://' . - $this->yystack[ $this->yyidx + 0 ]->minor . - '\')'; - } - - // line 638 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r69() - { - $this->_retvalue = - $this->yystack[ $this->yyidx + -2 ]->minor . - trim($this->yystack[ $this->yyidx + -1 ]->minor) . - $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 642 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r71() - { - $this->_retvalue = - $this->yystack[ $this->yyidx + -1 ]->minor[ 'pre' ] . - $this->yystack[ $this->yyidx + -2 ]->minor . - $this->yystack[ $this->yyidx + -1 ]->minor[ 'op' ] . - $this->yystack[ $this->yyidx + 0 ]->minor . - ')'; - } - - // line 646 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r72() - { - $this->_retvalue = - $this->yystack[ $this->yyidx + -2 ]->minor . - $this->yystack[ $this->yyidx + -1 ]->minor . - $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 650 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r73() - { - $this->_retvalue = $this->yystack[ $this->yyidx + 0 ]->minor . $this->yystack[ $this->yyidx + -1 ]->minor . ')'; - } - - // line 654 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r74() - { - $this->_retvalue = - 'in_array(' . - $this->yystack[ $this->yyidx + -2 ]->minor . - ',' . - $this->yystack[ $this->yyidx + 0 ]->minor . - ')'; - } - - // line 662 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r75() - { - $this->_retvalue = - 'in_array(' . - $this->yystack[ $this->yyidx + -2 ]->minor . - ',(array)' . - $this->yystack[ $this->yyidx + 0 ]->minor . - ')'; - } - - // line 666 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r76() - { - $this->_retvalue = - $this->yystack[ $this->yyidx + -5 ]->minor . - ' ? ' . - $this->compiler->compileVariable('\'' . substr($this->yystack[ $this->yyidx + -2 ]->minor, 1) . '\'') . - ' : ' . - $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 676 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r77() - { - $this->_retvalue = - $this->yystack[ $this->yyidx + -5 ]->minor . - ' ? ' . - $this->yystack[ $this->yyidx + -2 ]->minor . - ' : ' . - $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 681 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r79() - { - $this->_retvalue = $this->yystack[ $this->yyidx + -1 ]->minor . $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 702 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r80() - { - $this->_retvalue = '!' . $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 706 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r85() - { - $this->_retvalue = $this->yystack[ $this->yyidx + -2 ]->minor . '.' . $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 710 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r86() - { - $this->_retvalue = $this->yystack[ $this->yyidx + -1 ]->minor . '.'; - } - - // line 715 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r87() - { - $this->_retvalue = '.' . $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 732 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r88() - { - if (defined($this->yystack[ $this->yyidx + 0 ]->minor)) { - if ($this->security) { - $this->security->isTrustedConstant($this->yystack[ $this->yyidx + 0 ]->minor, $this->compiler); - } - $this->_retvalue = $this->yystack[ $this->yyidx + 0 ]->minor; - } else { - $this->_retvalue = '\'' . $this->yystack[ $this->yyidx + 0 ]->minor . '\''; - } - } - - // line 736 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r90() - { - $this->_retvalue = '(' . $this->yystack[ $this->yyidx + -1 ]->minor . ')'; - } - - // line 754 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r91() - { - $this->_retvalue = - $this->yystack[ $this->yyidx + -2 ]->minor . - $this->yystack[ $this->yyidx + -1 ]->minor . - $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 765 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r95() - { - $prefixVar = $this->compiler->getNewPrefixVariable(); - if ($this->yystack[ $this->yyidx + -2 ]->minor[ 'var' ] === '\'smarty\'') { - $this->compiler->appendPrefixCode("compiler->compileTag('private_special_variable', array(), - $this->yystack[ $this->yyidx + - -2 ]->minor[ 'smarty_internal_index' ]) . - ';?>'); - } else { - $this->compiler->appendPrefixCode("compiler->compileVariable($this->yystack[ $this->yyidx + - -2 ]->minor[ 'var' ]) . - $this->yystack[ $this->yyidx + -2 ]->minor[ 'smarty_internal_index' ] . - ';?>'); - } - $this->_retvalue = - $prefixVar . - '::' . - $this->yystack[ $this->yyidx + 0 ]->minor[ 0 ] . - $this->yystack[ $this->yyidx + 0 ]->minor[ 1 ]; - } - - // line 772 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r96() - { - $prefixVar = $this->compiler->getNewPrefixVariable(); - $tmp = $this->compiler->appendCode('', $this->yystack[ $this->yyidx + 0 ]->minor); - $this->compiler->appendPrefixCode($this->compiler->appendCode($tmp, "")); - $this->_retvalue = $prefixVar; - } - - // line 785 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r97() - { - $this->_retvalue = - $this->compiler->compileTag('private_modifier', array(), array( - 'value' => $this->yystack[ $this->yyidx + -1 ]->minor, - 'modifierlist' => $this->yystack[ $this->yyidx + 0 ]->minor - )); - } - - // line 804 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r100() - { - if (!in_array(strtolower($this->yystack[ $this->yyidx + -2 ]->minor), array('self', 'parent')) && - (!$this->security || - $this->security->isTrustedStaticClassAccess($this->yystack[ $this->yyidx + -2 ]->minor, - $this->yystack[ $this->yyidx + 0 ]->minor, $this->compiler))) { - if (isset($this->smarty->registered_classes[ $this->yystack[ $this->yyidx + -2 ]->minor ])) { - $this->_retvalue = - $this->smarty->registered_classes[ $this->yystack[ $this->yyidx + -2 ]->minor ] . - '::' . - $this->yystack[ $this->yyidx + 0 ]->minor[ 0 ] . - $this->yystack[ $this->yyidx + 0 ]->minor[ 1 ]; - } else { - $this->_retvalue = - $this->yystack[ $this->yyidx + -2 ]->minor . - '::' . - $this->yystack[ $this->yyidx + 0 ]->minor[ 0 ] . - $this->yystack[ $this->yyidx + 0 ]->minor[ 1 ]; - } - } else { - $this->compiler->trigger_template_error('static class \'' . - $this->yystack[ $this->yyidx + -2 ]->minor . - '\' is undefined or not allowed by security setting'); - } - } - - // line 815 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r102() - { - $this->_retvalue = $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 818 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r103() - { - $this->_retvalue = - $this->compiler->compileVariable('\'' . substr($this->yystack[ $this->yyidx + 0 ]->minor, 1) . '\''); - } - - // line 831 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r104() - { - if ($this->yystack[ $this->yyidx + 0 ]->minor[ 'var' ] === '\'smarty\'') { - $smarty_var = - $this->compiler->compileTag('private_special_variable', array(), - $this->yystack[ $this->yyidx + 0 ]->minor[ 'smarty_internal_index' ]); - $this->_retvalue = $smarty_var; - } else { - // used for array reset,next,prev,end,current - $this->last_variable = $this->yystack[ $this->yyidx + 0 ]->minor[ 'var' ]; - $this->last_index = $this->yystack[ $this->yyidx + 0 ]->minor[ 'smarty_internal_index' ]; - $this->_retvalue = - $this->compiler->compileVariable($this->yystack[ $this->yyidx + 0 ]->minor[ 'var' ]) . - $this->yystack[ $this->yyidx + 0 ]->minor[ 'smarty_internal_index' ]; - } - } - - // line 841 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r105() - { - $this->_retvalue = - '$_smarty_tpl->tpl_vars[' . - $this->yystack[ $this->yyidx + -2 ]->minor . - ']->' . - $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 845 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r107() - { - $this->_retvalue = - $this->compiler->compileConfigVariable('\'' . $this->yystack[ $this->yyidx + -1 ]->minor . '\''); - } - - // line 849 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r108() - { - $this->_retvalue = - '(is_array($tmp = ' . - $this->compiler->compileConfigVariable('\'' . $this->yystack[ $this->yyidx + -2 ]->minor . '\'') . - ') ? $tmp' . - $this->yystack[ $this->yyidx + 0 ]->minor . - ' :null)'; - } - - // line 853 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r109() - { - $this->_retvalue = $this->compiler->compileConfigVariable($this->yystack[ $this->yyidx + -1 ]->minor); - } - - // line 857 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r110() - { - $this->_retvalue = - '(is_array($tmp = ' . - $this->compiler->compileConfigVariable($this->yystack[ $this->yyidx + -2 ]->minor) . - ') ? $tmp' . - $this->yystack[ $this->yyidx + 0 ]->minor . - ' : null)'; - } - - // line 860 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r111() - { - $this->_retvalue = - array( - 'var' => '\'' . substr($this->yystack[ $this->yyidx + -1 ]->minor, 1) . '\'', - 'smarty_internal_index' => $this->yystack[ $this->yyidx + 0 ]->minor - ); - } - - // line 873 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r112() - { - $this->_retvalue = - array( - 'var' => $this->yystack[ $this->yyidx + -1 ]->minor, - 'smarty_internal_index' => $this->yystack[ $this->yyidx + 0 ]->minor - ); - } - - // line 879 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r114() - { - return; - } - - // line 882 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r115() - { - $this->_retvalue = - '[' . - $this->compiler->compileVariable('\'' . substr($this->yystack[ $this->yyidx + 0 ]->minor, 1) . '\'') . - ']'; - } - - // line 886 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r116() - { - $this->_retvalue = '[' . $this->compiler->compileVariable($this->yystack[ $this->yyidx + 0 ]->minor) . ']'; - } - - // line 890 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r117() - { - $this->_retvalue = - '[' . - $this->compiler->compileVariable($this->yystack[ $this->yyidx + -2 ]->minor) . - '->' . - $this->yystack[ $this->yyidx + 0 ]->minor . - ']'; - } - - // line 894 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r118() - { - $this->_retvalue = '[\'' . $this->yystack[ $this->yyidx + 0 ]->minor . '\']'; - } - - // line 899 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r119() - { - $this->_retvalue = '[' . $this->yystack[ $this->yyidx + 0 ]->minor . ']'; - } - - // line 904 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r120() - { - $this->_retvalue = '[' . $this->yystack[ $this->yyidx + -1 ]->minor . ']'; - } - - // line 908 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r121() - { - $this->_retvalue = - '[' . - $this->compiler->compileTag('private_special_variable', array(), - '[\'section\'][\'' . $this->yystack[ $this->yyidx + -1 ]->minor . '\'][\'index\']') . - ']'; - } - - // line 911 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r122() - { - $this->_retvalue = - '[' . - $this->compiler->compileTag('private_special_variable', array(), '[\'section\'][\'' . - $this->yystack[ $this->yyidx + - -3 ]->minor . - '\'][\'' . - $this->yystack[ $this->yyidx + - -1 ]->minor . - '\']') . - ']'; - } - - // line 917 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r123() - { - $this->_retvalue = '[' . $this->yystack[ $this->yyidx + -1 ]->minor . ']'; - } - - // line 933 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r125() - { - $this->_retvalue = - '[' . - $this->compiler->compileVariable('\'' . substr($this->yystack[ $this->yyidx + -1 ]->minor, 1) . '\'') . - ']'; - } - - // line 943 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r129() - { - $this->_retvalue = '[]'; - } - - // line 947 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r130() - { - $this->_retvalue = '\'' . substr($this->yystack[ $this->yyidx + 0 ]->minor, 1) . '\''; - } - - // line 952 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r131() - { - $this->_retvalue = '\'\''; - } - - // line 960 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r132() - { - $this->_retvalue = $this->yystack[ $this->yyidx + -1 ]->minor . '.' . $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 966 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r134() - { - $var = - trim(substr($this->yystack[ $this->yyidx + 0 ]->minor, $this->compiler->getLdelLength(), - -$this->compiler->getRdelLength()), ' $'); - $this->_retvalue = $this->compiler->compileVariable('\'' . $var . '\''); - } - - // line 973 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r135() - { - $this->_retvalue = '(' . $this->yystack[ $this->yyidx + -1 ]->minor . ')'; - } - - // line 982 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r136() - { - if ($this->yystack[ $this->yyidx + -1 ]->minor[ 'var' ] === '\'smarty\'') { - $this->_retvalue = - $this->compiler->compileTag('private_special_variable', array(), - $this->yystack[ $this->yyidx + -1 ]->minor[ 'smarty_internal_index' ]) . - $this->yystack[ $this->yyidx + 0 ]->minor; - } else { - $this->_retvalue = - $this->compiler->compileVariable($this->yystack[ $this->yyidx + -1 ]->minor[ 'var' ]) . - $this->yystack[ $this->yyidx + -1 ]->minor[ 'smarty_internal_index' ] . - $this->yystack[ $this->yyidx + 0 ]->minor; - } - } - - // line 987 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r137() - { - $this->_retvalue = $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 992 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r138() - { - $this->_retvalue = $this->yystack[ $this->yyidx + -1 ]->minor . $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 999 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r139() - { - if ($this->security && substr($this->yystack[ $this->yyidx + -1 ]->minor, 0, 1) === '_') { - $this->compiler->trigger_template_error(self::ERR1); - } - $this->_retvalue = - '->' . $this->yystack[ $this->yyidx + -1 ]->minor . $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 1006 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r140() - { + $this->_retvalue = null; + } else { + $this->_retvalue = $this->compiler->compileTag($tag.'close',array()); + } + } +// line 501 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r45(){ + $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + 0]->minor.'close',array()); + } +// line 505 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r46(){ + $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + -1]->minor.'close',array(),array('modifier_list'=>$this->yystack[$this->yyidx + 0]->minor)); + } +// line 510 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r47(){ + $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + -2]->minor.'close',array(),array('object_method'=>$this->yystack[$this->yyidx + 0]->minor)); + } +// line 514 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r48(){ + $this->_retvalue = $this->compiler->compileTag($this->yystack[$this->yyidx + -3]->minor.'close',array(),array('object_method'=>$this->yystack[$this->yyidx + -1]->minor, 'modifier_list'=>$this->yystack[$this->yyidx + 0]->minor)); + } +// line 522 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r49(){ + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor; + $this->_retvalue[] = $this->yystack[$this->yyidx + 0]->minor; + } +// line 528 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r50(){ + $this->_retvalue = array($this->yystack[$this->yyidx + 0]->minor); + } +// line 533 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r51(){ + $this->_retvalue = array(); + } +// line 538 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r52(){ + if (defined($this->yystack[$this->yyidx + 0]->minor)) { if ($this->security) { - $this->compiler->trigger_template_error(self::ERR2); + $this->security->isTrustedConstant($this->yystack[$this->yyidx + 0]->minor, $this->compiler); } - $this->_retvalue = - '->{' . - $this->compiler->compileVariable($this->yystack[ $this->yyidx + -1 ]->minor) . - $this->yystack[ $this->yyidx + 0 ]->minor . - '}'; + $this->_retvalue = array($this->yystack[$this->yyidx + -2]->minor=>$this->yystack[$this->yyidx + 0]->minor); + } else { + $this->_retvalue = array($this->yystack[$this->yyidx + -2]->minor=>'\''.$this->yystack[$this->yyidx + 0]->minor.'\''); } - - // line 1013 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r141() - { + } +// line 549 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r53(){ + $this->_retvalue = array(trim($this->yystack[$this->yyidx + -1]->minor," =\n\r\t")=>$this->yystack[$this->yyidx + 0]->minor); + } +// line 557 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r55(){ + $this->_retvalue = '\''.$this->yystack[$this->yyidx + 0]->minor.'\''; + } +// line 569 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r58(){ + $this->_retvalue = array($this->yystack[$this->yyidx + -2]->minor=>$this->yystack[$this->yyidx + 0]->minor); + } +// line 582 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r60(){ + $this->yystack[$this->yyidx + -2]->minor[]=$this->yystack[$this->yyidx + 0]->minor; + $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor; + } +// line 587 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r61(){ + $this->_retvalue = array('var' => '\''.substr($this->yystack[$this->yyidx + -2]->minor,1).'\'', 'value'=>$this->yystack[$this->yyidx + 0]->minor); + } +// line 594 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r63(){ + $this->_retvalue = array('var' => $this->yystack[$this->yyidx + -2]->minor, 'value'=>$this->yystack[$this->yyidx + 0]->minor); + } +// line 598 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r64(){ + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor; + } +// line 618 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r67(){ + $this->_retvalue = '$_smarty_tpl->getStreamVariable(\''.substr($this->yystack[$this->yyidx + -2]->minor,1).'://' . $this->yystack[$this->yyidx + 0]->minor . '\')'; + } +// line 623 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r68(){ + $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor . trim($this->yystack[$this->yyidx + -1]->minor) . $this->yystack[$this->yyidx + 0]->minor; + } +// line 633 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r70(){ + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor['pre']. $this->yystack[$this->yyidx + -2]->minor.$this->yystack[$this->yyidx + -1]->minor['op'].$this->yystack[$this->yyidx + 0]->minor .')'; + } +// line 637 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r71(){ + $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor.$this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; + } +// line 641 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r72(){ + $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor . $this->yystack[$this->yyidx + -1]->minor . ')'; + } +// line 645 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r73(){ + $this->_retvalue = 'in_array('.$this->yystack[$this->yyidx + -2]->minor.','.$this->yystack[$this->yyidx + 0]->minor.')'; + } +// line 649 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r74(){ + $this->_retvalue = 'in_array('.$this->yystack[$this->yyidx + -2]->minor.',(array)'.$this->yystack[$this->yyidx + 0]->minor.')'; + } +// line 657 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r75(){ + $this->_retvalue = $this->yystack[$this->yyidx + -5]->minor.' ? '. $this->compiler->compileVariable('\''.substr($this->yystack[$this->yyidx + -2]->minor,1).'\'') . ' : '.$this->yystack[$this->yyidx + 0]->minor; + } +// line 661 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r76(){ + $this->_retvalue = $this->yystack[$this->yyidx + -5]->minor.' ? '.$this->yystack[$this->yyidx + -2]->minor.' : '.$this->yystack[$this->yyidx + 0]->minor; + } +// line 671 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r78(){ + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; + } +// line 676 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r79(){ + $this->_retvalue = '!'.$this->yystack[$this->yyidx + 0]->minor; + } +// line 697 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r84(){ + $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor.'.'.$this->yystack[$this->yyidx + 0]->minor; + } +// line 701 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r85(){ + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor.'.'; + } +// line 705 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r86(){ + $this->_retvalue = '.'.$this->yystack[$this->yyidx + 0]->minor; + } +// line 710 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r87(){ + if (defined($this->yystack[$this->yyidx + 0]->minor)) { if ($this->security) { - $this->compiler->trigger_template_error(self::ERR2); + $this->security->isTrustedConstant($this->yystack[$this->yyidx + 0]->minor, $this->compiler); } - $this->_retvalue = - '->{' . $this->yystack[ $this->yyidx + -2 ]->minor . $this->yystack[ $this->yyidx + 0 ]->minor . '}'; + $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; + } else { + $this->_retvalue = '\''.$this->yystack[$this->yyidx + 0]->minor.'\''; } - - // line 1021 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r142() - { - if ($this->security) { - $this->compiler->trigger_template_error(self::ERR2); + } +// line 727 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r89(){ + $this->_retvalue = '('. $this->yystack[$this->yyidx + -1]->minor .')'; + } +// line 731 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r90(){ + $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor.$this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; + } +// line 749 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r94(){ + if ($this->security && $this->security->static_classes !== array()) { + $this->compiler->trigger_template_error('dynamic static class not allowed by security setting'); + } + $prefixVar = $this->compiler->getNewPrefixVariable(); + if ($this->yystack[$this->yyidx + -2]->minor['var'] === '\'smarty\'') { + $this->compiler->appendPrefixCode("compiler->compileTag('private_special_variable',array(),$this->yystack[$this->yyidx + -2]->minor['smarty_internal_index']).';?>'); + } else { + $this->compiler->appendPrefixCode("compiler->compileVariable($this->yystack[$this->yyidx + -2]->minor['var']).$this->yystack[$this->yyidx + -2]->minor['smarty_internal_index'].';?>'); + } + $this->_retvalue = $prefixVar .'::'.$this->yystack[$this->yyidx + 0]->minor[0].$this->yystack[$this->yyidx + 0]->minor[1]; + } +// line 760 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r95(){ + $prefixVar = $this->compiler->getNewPrefixVariable(); + $tmp = $this->compiler->appendCode('', $this->yystack[$this->yyidx + 0]->minor); + $this->compiler->appendPrefixCode($this->compiler->appendCode($tmp, "")); + $this->_retvalue = $prefixVar; + } +// line 767 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r96(){ + $this->_retvalue = $this->compiler->compileTag('private_modifier',array(),array('value'=>$this->yystack[$this->yyidx + -1]->minor,'modifierlist'=>$this->yystack[$this->yyidx + 0]->minor)); + } +// line 780 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r99(){ + if (!in_array(strtolower($this->yystack[$this->yyidx + -2]->minor), array('self', 'parent')) && (!$this->security || $this->security->isTrustedStaticClassAccess($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->compiler))) { + if (isset($this->smarty->registered_classes[$this->yystack[$this->yyidx + -2]->minor])) { + $this->_retvalue = $this->smarty->registered_classes[$this->yystack[$this->yyidx + -2]->minor].'::'.$this->yystack[$this->yyidx + 0]->minor[0].$this->yystack[$this->yyidx + 0]->minor[1]; + } else { + // trigger_error('Using unregistered static method "' . $this->yystack[$this->yyidx + -2]->minor.'::'.$this->yystack[$this->yyidx + 0]->minor[0] . '" in a template is deprecated and will be ' . + // 'removed in a future release. Use Smarty::registerClass to explicitly register ' . + // 'a class for access.', E_USER_DEPRECATED); + $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor.'::'.$this->yystack[$this->yyidx + 0]->minor[0].$this->yystack[$this->yyidx + 0]->minor[1]; } - $this->_retvalue = - '->{\'' . - $this->yystack[ $this->yyidx + -4 ]->minor . - '\'.' . - $this->yystack[ $this->yyidx + -2 ]->minor . - $this->yystack[ $this->yyidx + 0 ]->minor . - '}'; + } else { + $this->compiler->trigger_template_error ('static class \''.$this->yystack[$this->yyidx + -2]->minor.'\' is undefined or not allowed by security setting'); } - - // line 1029 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r143() - { - $this->_retvalue = '->' . $this->yystack[ $this->yyidx + 0 ]->minor; } - - // line 1037 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r144() - { - $this->_retvalue = - $this->compiler->compilePHPFunctionCall($this->yystack[ $this->yyidx + -3 ]->minor, - $this->yystack[ $this->yyidx + -1 ]->minor); - } - - // line 1044 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r145() - { - if ($this->security && substr($this->yystack[ $this->yyidx + -3 ]->minor, 0, 1) === '_') { - $this->compiler->trigger_template_error(self::ERR1); +// line 799 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r101(){ + $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } - $this->_retvalue = - $this->yystack[ $this->yyidx + -3 ]->minor . - '(' . - implode(',', $this->yystack[ $this->yyidx + -1 ]->minor) . - ')'; +// line 810 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r102(){ + $this->_retvalue = $this->compiler->compileVariable('\''.substr($this->yystack[$this->yyidx + 0]->minor,1).'\''); } - - // line 1055 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r146() - { - if ($this->security) { - $this->compiler->trigger_template_error(self::ERR2); - } - $prefixVar = $this->compiler->getNewPrefixVariable(); - $this->compiler->appendPrefixCode("compiler->compileVariable('\'' . - substr($this->yystack[ $this->yyidx + - -3 ]->minor, 1) . - '\'') . - ';?>'); - $this->_retvalue = $prefixVar . '(' . implode(',', $this->yystack[ $this->yyidx + -1 ]->minor) . ')'; +// line 813 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r103(){ + if ($this->yystack[$this->yyidx + 0]->minor['var'] === '\'smarty\'') { + $smarty_var = $this->compiler->compileTag('private_special_variable',array(),$this->yystack[$this->yyidx + 0]->minor['smarty_internal_index']); + $this->_retvalue = $smarty_var; + } else { + // used for array reset,next,prev,end,current + $this->last_variable = $this->yystack[$this->yyidx + 0]->minor['var']; + $this->last_index = $this->yystack[$this->yyidx + 0]->minor['smarty_internal_index']; + $this->_retvalue = $this->compiler->compileVariable($this->yystack[$this->yyidx + 0]->minor['var']).$this->yystack[$this->yyidx + 0]->minor['smarty_internal_index']; } - - // line 1072 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r147() - { - $this->_retvalue = - array_merge($this->yystack[ $this->yyidx + -2 ]->minor, array($this->yystack[ $this->yyidx + 0 ]->minor)); } - - // line 1076 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r150() - { - $this->_retvalue = - array_merge($this->yystack[ $this->yyidx + -2 ]->minor, array( - array_merge($this->yystack[ $this->yyidx + -1 ]->minor, $this->yystack[ $this->yyidx + 0 ]->minor) - )); +// line 826 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r104(){ + $this->_retvalue = '$_smarty_tpl->tpl_vars['. $this->yystack[$this->yyidx + -2]->minor .']->'.$this->yystack[$this->yyidx + 0]->minor; } - - // line 1084 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r151() - { - $this->_retvalue = - array(array_merge($this->yystack[ $this->yyidx + -1 ]->minor, $this->yystack[ $this->yyidx + 0 ]->minor)); +// line 836 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r106(){ + $this->_retvalue = $this->compiler->compileConfigVariable('\'' . $this->yystack[$this->yyidx + -1]->minor . '\''); } - - // line 1092 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r153() - { - $this->_retvalue = array($this->yystack[ $this->yyidx + 0 ]->minor); +// line 840 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r107(){ + $this->_retvalue = '(is_array($tmp = ' . $this->compiler->compileConfigVariable('\'' . $this->yystack[$this->yyidx + -2]->minor . '\'') . ') ? $tmp'.$this->yystack[$this->yyidx + 0]->minor.' :null)'; } - - // line 1105 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r154() - { - $this->_retvalue = - array_merge($this->yystack[ $this->yyidx + -1 ]->minor, $this->yystack[ $this->yyidx + 0 ]->minor); +// line 844 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r108(){ + $this->_retvalue = $this->compiler->compileConfigVariable($this->yystack[$this->yyidx + -1]->minor); } - - // line 1114 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r157() - { - $this->_retvalue = - array(trim($this->yystack[ $this->yyidx + -1 ]->minor) . $this->yystack[ $this->yyidx + 0 ]->minor); +// line 848 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r109(){ + $this->_retvalue = '(is_array($tmp = ' . $this->compiler->compileConfigVariable($this->yystack[$this->yyidx + -2]->minor) . ') ? $tmp'.$this->yystack[$this->yyidx + 0]->minor.' : null)'; } - - // line 1119 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r159() - { - $this->_retvalue = array($this->yystack[ $this->yyidx + 0 ]->minor, '', 'method'); +// line 852 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r110(){ + $this->_retvalue = array('var'=>'\''.substr($this->yystack[$this->yyidx + -1]->minor,1).'\'', 'smarty_internal_index'=>$this->yystack[$this->yyidx + 0]->minor); } - - // line 1124 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r160() - { - $this->_retvalue = - array($this->yystack[ $this->yyidx + -1 ]->minor, $this->yystack[ $this->yyidx + 0 ]->minor, 'method'); +// line 855 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r111(){ + $this->_retvalue = array('var'=>$this->yystack[$this->yyidx + -1]->minor, 'smarty_internal_index'=>$this->yystack[$this->yyidx + 0]->minor); } - - // line 1129 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r161() - { - $this->_retvalue = array($this->yystack[ $this->yyidx + 0 ]->minor, ''); +// line 868 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r113(){ + return; } - - // line 1134 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r162() - { - $this->_retvalue = - array($this->yystack[ $this->yyidx + -1 ]->minor, $this->yystack[ $this->yyidx + 0 ]->minor, 'property'); +// line 874 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r114(){ + $this->_retvalue = '['.$this->compiler->compileVariable('\''.substr($this->yystack[$this->yyidx + 0]->minor,1).'\'').']'; } - - // line 1140 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r163() - { - $this->_retvalue = - array( - $this->yystack[ $this->yyidx + -2 ]->minor, - $this->yystack[ $this->yyidx + -1 ]->minor . $this->yystack[ $this->yyidx + 0 ]->minor, 'property' - ); +// line 877 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r115(){ + $this->_retvalue = '['.$this->compiler->compileVariable($this->yystack[$this->yyidx + 0]->minor).']'; } - - // line 1144 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r164() - { - $this->_retvalue = ' ' . trim($this->yystack[ $this->yyidx + 0 ]->minor) . ' '; +// line 881 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r116(){ + $this->_retvalue = '['.$this->compiler->compileVariable($this->yystack[$this->yyidx + -2]->minor).'->'.$this->yystack[$this->yyidx + 0]->minor.']'; } - - // line 1163 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r165() - { - static $lops = array( - 'eq' => ' == ', - 'ne' => ' != ', - 'neq' => ' != ', - 'gt' => ' > ', - 'ge' => ' >= ', - 'gte' => ' >= ', - 'lt' => ' < ', - 'le' => ' <= ', - 'lte' => ' <= ', - 'mod' => ' % ', - 'and' => ' && ', - 'or' => ' || ', - 'xor' => ' xor ', - ); - $op = strtolower(preg_replace('/\s*/', '', $this->yystack[ $this->yyidx + 0 ]->minor)); - $this->_retvalue = $lops[ $op ]; +// line 885 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r117(){ + $this->_retvalue = '[\''. $this->yystack[$this->yyidx + 0]->minor .'\']'; } - - // line 1176 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r166() - { - static $tlops = array( - 'isdivby' => array('op' => ' % ', 'pre' => '!('), - 'isnotdivby' => array('op' => ' % ', 'pre' => '('), - 'isevenby' => array('op' => ' / ', 'pre' => '!(1 & '), - 'isnotevenby' => array('op' => ' / ', 'pre' => '(1 & '), - 'isoddby' => array('op' => ' / ', 'pre' => '(1 & '), - 'isnotoddby' => array('op' => ' / ', 'pre' => '!(1 & '), - ); - $op = strtolower(preg_replace('/\s*/', '', $this->yystack[ $this->yyidx + 0 ]->minor)); - $this->_retvalue = $tlops[ $op ]; +// line 889 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r118(){ + $this->_retvalue = '['. $this->yystack[$this->yyidx + 0]->minor .']'; } - - // line 1190 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r167() - { - static $scond = array( - 'iseven' => '!(1 & ', +// line 894 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r119(){ + $this->_retvalue = '['. $this->yystack[$this->yyidx + -1]->minor .']'; + } +// line 899 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r120(){ + $this->_retvalue = '['.$this->compiler->compileTag('private_special_variable',array(),'[\'section\'][\''.$this->yystack[$this->yyidx + -1]->minor.'\'][\'index\']').']'; + } +// line 903 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r121(){ + $this->_retvalue = '['.$this->compiler->compileTag('private_special_variable',array(),'[\'section\'][\''.$this->yystack[$this->yyidx + -3]->minor.'\'][\''.$this->yystack[$this->yyidx + -1]->minor.'\']').']'; + } +// line 906 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r122(){ + $this->_retvalue = '['.$this->yystack[$this->yyidx + -1]->minor.']'; + } +// line 912 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r124(){ + $this->_retvalue = '['.$this->compiler->compileVariable('\''.substr($this->yystack[$this->yyidx + -1]->minor,1).'\'').']'; + } +// line 928 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r128(){ + $this->_retvalue = '[]'; + } +// line 938 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r129(){ + $this->_retvalue = '\''.substr($this->yystack[$this->yyidx + 0]->minor,1).'\''; + } +// line 942 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r130(){ + $this->_retvalue = '\'\''; + } +// line 947 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r131(){ + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor.'.'.$this->yystack[$this->yyidx + 0]->minor; + } +// line 955 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r133(){ + $var = trim(substr($this->yystack[$this->yyidx + 0]->minor, $this->compiler->getLdelLength(), -$this->compiler->getRdelLength()), ' $'); + $this->_retvalue = $this->compiler->compileVariable('\''.$var.'\''); + } +// line 961 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r134(){ + $this->_retvalue = '('.$this->yystack[$this->yyidx + -1]->minor.')'; + } +// line 968 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r135(){ + if ($this->yystack[$this->yyidx + -1]->minor['var'] === '\'smarty\'') { + $this->_retvalue = $this->compiler->compileTag('private_special_variable',array(),$this->yystack[$this->yyidx + -1]->minor['smarty_internal_index']).$this->yystack[$this->yyidx + 0]->minor; + } else { + $this->_retvalue = $this->compiler->compileVariable($this->yystack[$this->yyidx + -1]->minor['var']).$this->yystack[$this->yyidx + -1]->minor['smarty_internal_index'].$this->yystack[$this->yyidx + 0]->minor; + } + } +// line 977 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r136(){ + $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; + } +// line 982 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r137(){ + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; + } +// line 987 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r138(){ + if ($this->security && substr($this->yystack[$this->yyidx + -1]->minor,0,1) === '_') { + $this->compiler->trigger_template_error (self::ERR1); + } + $this->_retvalue = '->'.$this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor; + } +// line 994 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r139(){ + if ($this->security) { + $this->compiler->trigger_template_error (self::ERR2); + } + $this->_retvalue = '->{'.$this->compiler->compileVariable($this->yystack[$this->yyidx + -1]->minor).$this->yystack[$this->yyidx + 0]->minor.'}'; + } +// line 1001 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r140(){ + if ($this->security) { + $this->compiler->trigger_template_error (self::ERR2); + } + $this->_retvalue = '->{'.$this->yystack[$this->yyidx + -2]->minor.$this->yystack[$this->yyidx + 0]->minor.'}'; + } +// line 1008 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r141(){ + if ($this->security) { + $this->compiler->trigger_template_error (self::ERR2); + } + $this->_retvalue = '->{\''.$this->yystack[$this->yyidx + -4]->minor.'\'.'.$this->yystack[$this->yyidx + -2]->minor.$this->yystack[$this->yyidx + 0]->minor.'}'; + } +// line 1016 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r142(){ + $this->_retvalue = '->'.$this->yystack[$this->yyidx + 0]->minor; + } +// line 1024 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r143(){ + $this->_retvalue = $this->compiler->compilePHPFunctionCall($this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + -1]->minor); + } +// line 1032 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r144(){ + if ($this->security && substr($this->yystack[$this->yyidx + -3]->minor,0,1) === '_') { + $this->compiler->trigger_template_error (self::ERR1); + } + $this->_retvalue = $this->yystack[$this->yyidx + -3]->minor . '('. implode(',',$this->yystack[$this->yyidx + -1]->minor) .')'; + } +// line 1039 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r145(){ + if ($this->security) { + $this->compiler->trigger_template_error (self::ERR2); + } + $prefixVar = $this->compiler->getNewPrefixVariable(); + $this->compiler->appendPrefixCode("compiler->compileVariable('\''.substr($this->yystack[$this->yyidx + -3]->minor,1).'\'').';?>'); + $this->_retvalue = $prefixVar .'('. implode(',',$this->yystack[$this->yyidx + -1]->minor) .')'; + } +// line 1050 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r146(){ + $this->_retvalue = array_merge($this->yystack[$this->yyidx + -2]->minor,array($this->yystack[$this->yyidx + 0]->minor)); + } +// line 1067 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r149(){ + $this->_retvalue = array_merge($this->yystack[$this->yyidx + -2]->minor,array(array_merge($this->yystack[$this->yyidx + -1]->minor,$this->yystack[$this->yyidx + 0]->minor))); + } +// line 1071 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r150(){ + $this->_retvalue = array(array_merge($this->yystack[$this->yyidx + -1]->minor,$this->yystack[$this->yyidx + 0]->minor)); + } +// line 1079 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r152(){ + $this->_retvalue = array($this->yystack[$this->yyidx + 0]->minor); + } +// line 1087 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r153(){ + $this->_retvalue = array_merge($this->yystack[$this->yyidx + -1]->minor,$this->yystack[$this->yyidx + 0]->minor); + } +// line 1100 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r156(){ + $this->_retvalue = array(trim($this->yystack[$this->yyidx + -1]->minor).$this->yystack[$this->yyidx + 0]->minor); + } +// line 1109 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r158(){ + $this->_retvalue = array($this->yystack[$this->yyidx + 0]->minor, '', 'method'); + } +// line 1114 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r159(){ + $this->_retvalue = array($this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor, 'method'); + } +// line 1119 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r160(){ + $this->_retvalue = array($this->yystack[$this->yyidx + 0]->minor, ''); + } +// line 1124 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r161(){ + $this->_retvalue = array($this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor, 'property'); + } +// line 1129 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r162(){ + $this->_retvalue = array($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -1]->minor.$this->yystack[$this->yyidx + 0]->minor, 'property'); + } +// line 1135 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r163(){ + $this->_retvalue = ' '. trim($this->yystack[$this->yyidx + 0]->minor) . ' '; + } +// line 1139 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r164(){ + static $lops = array( + 'eq' => ' == ', + 'ne' => ' != ', + 'neq' => ' != ', + 'gt' => ' > ', + 'ge' => ' >= ', + 'gte' => ' >= ', + 'lt' => ' < ', + 'le' => ' <= ', + 'lte' => ' <= ', + 'mod' => ' % ', + 'and' => ' && ', + 'or' => ' || ', + 'xor' => ' xor ', + ); + $op = strtolower(preg_replace('/\s*/', '', $this->yystack[$this->yyidx + 0]->minor)); + $this->_retvalue = $lops[$op]; + } +// line 1158 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r165(){ + static $tlops = array( + 'isdivby' => array('op' => ' % ', 'pre' => '!('), + 'isnotdivby' => array('op' => ' % ', 'pre' => '('), + 'isevenby' => array('op' => ' / ', 'pre' => '!(1 & '), + 'isnotevenby' => array('op' => ' / ', 'pre' => '(1 & '), + 'isoddby' => array('op' => ' / ', 'pre' => '(1 & '), + 'isnotoddby' => array('op' => ' / ', 'pre' => '!(1 & '), + ); + $op = strtolower(preg_replace('/\s*/', '', $this->yystack[$this->yyidx + 0]->minor)); + $this->_retvalue = $tlops[$op]; + } +// line 1171 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r166(){ + static $scond = array ( + 'iseven' => '!(1 & ', 'isnoteven' => '(1 & ', - 'isodd' => '(1 & ', - 'isnotodd' => '!(1 & ', + 'isodd' => '(1 & ', + 'isnotodd' => '!(1 & ', ); - $op = strtolower(str_replace(' ', '', $this->yystack[ $this->yyidx + 0 ]->minor)); - $this->_retvalue = $scond[ $op ]; + $op = strtolower(str_replace(' ', '', $this->yystack[$this->yyidx + 0]->minor)); + $this->_retvalue = $scond[$op]; + } +// line 1185 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r167(){ + $this->_retvalue = 'array('.$this->yystack[$this->yyidx + -1]->minor.')'; + } +// line 1196 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r170(){ + $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor.','.$this->yystack[$this->yyidx + 0]->minor; + } +// line 1204 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r172(){ + $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor.'=>'.$this->yystack[$this->yyidx + 0]->minor; + } +// line 1208 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r173(){ + $this->_retvalue = '\''.$this->yystack[$this->yyidx + -2]->minor.'\'=>'.$this->yystack[$this->yyidx + 0]->minor; + } +// line 1224 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r176(){ + $this->compiler->leaveDoubleQuote(); + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor->to_smarty_php($this); + } +// line 1230 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r177(){ + $this->yystack[$this->yyidx + -1]->minor->append_subtree($this, $this->yystack[$this->yyidx + 0]->minor); + $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor; + } +// line 1235 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r178(){ + $this->_retvalue = new Smarty_Internal_ParseTree_Dq($this, $this->yystack[$this->yyidx + 0]->minor); + } +// line 1239 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r179(){ + $this->_retvalue = new Smarty_Internal_ParseTree_Code('(string)'.$this->yystack[$this->yyidx + -1]->minor); + } +// line 1243 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r180(){ + $this->_retvalue = new Smarty_Internal_ParseTree_Code('(string)('.$this->yystack[$this->yyidx + -1]->minor.')'); + } +// line 1247 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r181(){ + $this->_retvalue = new Smarty_Internal_ParseTree_Code('(string)$_smarty_tpl->tpl_vars[\''. substr($this->yystack[$this->yyidx + 0]->minor,1) .'\']->value'); + } +// line 1259 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r184(){ + $this->_retvalue = new Smarty_Internal_ParseTree_Tag($this, $this->yystack[$this->yyidx + 0]->minor); + } +// line 1263 "../smarty/lexer/smarty_internal_templateparser.y" + public function yy_r185(){ + $this->_retvalue = new Smarty_Internal_ParseTree_DqContent($this->yystack[$this->yyidx + 0]->minor); } - // line 1201 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r168() - { - $this->_retvalue = 'array(' . $this->yystack[ $this->yyidx + -1 ]->minor . ')'; - } - - // line 1209 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r171() - { - $this->_retvalue = $this->yystack[ $this->yyidx + -2 ]->minor . ',' . $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 1213 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r173() - { - $this->_retvalue = - $this->yystack[ $this->yyidx + -2 ]->minor . '=>' . $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 1229 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r174() - { - $this->_retvalue = - '\'' . $this->yystack[ $this->yyidx + -2 ]->minor . '\'=>' . $this->yystack[ $this->yyidx + 0 ]->minor; - } - - // line 1235 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r177() - { - $this->compiler->leaveDoubleQuote(); - $this->_retvalue = $this->yystack[ $this->yyidx + -1 ]->minor->to_smarty_php($this); - } - - // line 1240 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r178() - { - $this->yystack[ $this->yyidx + -1 ]->minor->append_subtree($this, $this->yystack[ $this->yyidx + 0 ]->minor); - $this->_retvalue = $this->yystack[ $this->yyidx + -1 ]->minor; - } - - // line 1244 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r179() - { - $this->_retvalue = new Smarty_Internal_ParseTree_Dq($this, $this->yystack[ $this->yyidx + 0 ]->minor); - } - - // line 1248 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r180() - { - $this->_retvalue = new Smarty_Internal_ParseTree_Code('(string)' . $this->yystack[ $this->yyidx + -1 ]->minor); - } - - // line 1252 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r181() - { - $this->_retvalue = - new Smarty_Internal_ParseTree_Code('(string)(' . $this->yystack[ $this->yyidx + -1 ]->minor . ')'); - } - - // line 1264 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r182() - { - $this->_retvalue = - new Smarty_Internal_ParseTree_Code('(string)$_smarty_tpl->tpl_vars[\'' . - substr($this->yystack[ $this->yyidx + 0 ]->minor, 1) . - '\']->value'); - } - - // line 1268 "../smarty/lexer/smarty_internal_templateparser.y" - public function yy_r185() - { - $this->_retvalue = new Smarty_Internal_ParseTree_Tag($this, $this->yystack[ $this->yyidx + 0 ]->minor); - } - - public function yy_r186() - { - $this->_retvalue = new Smarty_Internal_ParseTree_DqContent($this->yystack[ $this->yyidx + 0 ]->minor); - } + private $_retvalue; public function yy_reduce($yyruleno) { if ($this->yyTraceFILE && $yyruleno >= 0 - && $yyruleno < count(self::$yyRuleName)) { + && $yyruleno < count(self::$yyRuleName)) { fprintf($this->yyTraceFILE, "%sReduce (%d) [%s].\n", $this->yyTracePrompt, $yyruleno, - self::$yyRuleName[ $yyruleno ]); + self::$yyRuleName[$yyruleno]); } + $this->_retvalue = $yy_lefthand_side = null; - if (isset(self::$yyReduceMap[ $yyruleno ])) { + if (isset(self::$yyReduceMap[$yyruleno])) { // call the action $this->_retvalue = null; - $this->{'yy_r' . self::$yyReduceMap[ $yyruleno ]}(); + $this->{'yy_r' . self::$yyReduceMap[$yyruleno]}(); $yy_lefthand_side = $this->_retvalue; } - $yygoto = self::$yyRuleInfo[ $yyruleno ][ 0 ]; - $yysize = self::$yyRuleInfo[ $yyruleno ][ 1 ]; + $yygoto = self::$yyRuleInfo[$yyruleno][0]; + $yysize = self::$yyRuleInfo[$yyruleno][1]; $this->yyidx -= $yysize; for ($i = $yysize; $i; $i--) { // pop all of the right-hand side parameters array_pop($this->yystack); } - $yyact = $this->yy_find_reduce_action($this->yystack[ $this->yyidx ]->stateno, $yygoto); + $yyact = $this->yy_find_reduce_action($this->yystack[$this->yyidx]->stateno, $yygoto); if ($yyact < self::YYNSTATE) { if (!$this->yyTraceFILE && $yysize) { $this->yyidx++; @@ -3492,7 +2795,7 @@ class Smarty_Internal_Templateparser $x->stateno = $yyact; $x->major = $yygoto; $x->minor = $yy_lefthand_side; - $this->yystack[ $this->yyidx ] = $x; + $this->yystack[$this->yyidx] = $x; } else { $this->yy_shift($yyact, $yygoto, $yy_lefthand_side); } @@ -3505,37 +2808,38 @@ class Smarty_Internal_Templateparser { if ($this->yyTraceFILE) { fprintf($this->yyTraceFILE, "%sFail!\n", $this->yyTracePrompt); - } - while ($this->yyidx >= 0) { + } while ($this->yyidx >= 0) { $this->yy_pop_parser_stack(); } } public function yy_syntax_error($yymajor, $TOKEN) { - // line 214 "../smarty/lexer/smarty_internal_templateparser.y" - $this->internalError = true; - $this->yymajor = $yymajor; - $this->compiler->trigger_template_error(); +// line 213 "../smarty/lexer/smarty_internal_templateparser.y" + + $this->internalError = true; + $this->yymajor = $yymajor; + $this->compiler->trigger_template_error(); } public function yy_accept() { if ($this->yyTraceFILE) { fprintf($this->yyTraceFILE, "%sAccept!\n", $this->yyTracePrompt); - } - while ($this->yyidx >= 0) { + } while ($this->yyidx >= 0) { $this->yy_pop_parser_stack(); } - // line 207 "../smarty/lexer/smarty_internal_templateparser.y" - $this->successful = !$this->internalError; - $this->internalError = false; - $this->retvalue = $this->_retvalue; +// line 206 "../smarty/lexer/smarty_internal_templateparser.y" + + $this->successful = !$this->internalError; + $this->internalError = false; + $this->retvalue = $this->_retvalue; } public function doParse($yymajor, $yytokenvalue) { $yyerrorhit = 0; /* True if yymajor has invoked an error */ + if ($this->yyidx === null || $this->yyidx < 0) { $this->yyidx = 0; $this->yyerrcnt = -1; @@ -3545,15 +2849,17 @@ class Smarty_Internal_Templateparser $this->yystack = array(); $this->yystack[] = $x; } - $yyendofinput = ($yymajor == 0); + $yyendofinput = ($yymajor==0); + if ($this->yyTraceFILE) { fprintf($this->yyTraceFILE, "%sInput %s\n", - $this->yyTracePrompt, $this->yyTokenName[ $yymajor ]); + $this->yyTracePrompt, $this->yyTokenName[$yymajor]); } + do { $yyact = $this->yy_find_shift_action($yymajor); if ($yymajor < self::YYERRORSYMBOL && - !$this->yy_is_expected_token($yymajor)) { + !$this->yy_is_expected_token($yymajor)) { // force a syntax error $yyact = self::YY_ERROR_ACTION; } @@ -3576,22 +2882,22 @@ class Smarty_Internal_Templateparser if ($this->yyerrcnt < 0) { $this->yy_syntax_error($yymajor, $yytokenvalue); } - $yymx = $this->yystack[ $this->yyidx ]->major; + $yymx = $this->yystack[$this->yyidx]->major; if ($yymx === self::YYERRORSYMBOL || $yyerrorhit) { if ($this->yyTraceFILE) { fprintf($this->yyTraceFILE, "%sDiscard input token %s\n", - $this->yyTracePrompt, $this->yyTokenName[ $yymajor ]); + $this->yyTracePrompt, $this->yyTokenName[$yymajor]); } $this->yy_destructor($yymajor, $yytokenvalue); $yymajor = self::YYNOCODE; } else { while ($this->yyidx >= 0 && - $yymx !== self::YYERRORSYMBOL && - ($yyact = $this->yy_find_shift_action(self::YYERRORSYMBOL)) >= self::YYNSTATE - ) { + $yymx !== self::YYERRORSYMBOL && + ($yyact = $this->yy_find_shift_action(self::YYERRORSYMBOL)) >= self::YYNSTATE + ){ $this->yy_pop_parser_stack(); } - if ($this->yyidx < 0 || $yymajor == 0) { + if ($this->yyidx < 0 || $yymajor==0) { $this->yy_destructor($yymajor, $yytokenvalue); $this->yy_parse_failed(); $yymajor = self::YYNOCODE; diff --git a/tools/smarty/sysplugins/smarty_internal_testinstall.php b/tools/smarty/sysplugins/smarty_internal_testinstall.php index 504a4582c..c8ffd4cc6 100644 --- a/tools/smarty/sysplugins/smarty_internal_testinstall.php +++ b/tools/smarty/sysplugins/smarty_internal_testinstall.php @@ -144,7 +144,7 @@ class Smarty_Internal_TestInstall } // test if all registered plugins_dir are accessible // and if core plugins directory is still registered - $_core_plugins_dir = realpath(dirname(__FILE__) . '/../plugins'); + $_core_plugins_dir = realpath(__DIR__ . '/../plugins'); $_core_plugins_available = false; foreach ($smarty->getPluginsDir() as $plugin_dir) { $_plugin_dir = $plugin_dir; @@ -362,7 +362,6 @@ class Smarty_Internal_TestInstall 'smarty_internal_compile_function.php' => true, 'smarty_internal_compile_if.php' => true, 'smarty_internal_compile_include.php' => true, - 'smarty_internal_compile_include_php.php' => true, 'smarty_internal_compile_insert.php' => true, 'smarty_internal_compile_ldelim.php' => true, 'smarty_internal_compile_make_nocache.php' => true, @@ -373,7 +372,6 @@ class Smarty_Internal_TestInstall 'smarty_internal_compile_private_modifier.php' => true, 'smarty_internal_compile_private_object_block_function.php' => true, 'smarty_internal_compile_private_object_function.php' => true, - 'smarty_internal_compile_private_php.php' => true, 'smarty_internal_compile_private_print_expression.php' => true, 'smarty_internal_compile_private_registered_block.php' => true, 'smarty_internal_compile_private_registered_function.php' => true, @@ -388,7 +386,6 @@ class Smarty_Internal_TestInstall 'smarty_internal_config_file_compiler.php' => true, 'smarty_internal_data.php' => true, 'smarty_internal_debug.php' => true, - 'smarty_internal_errorhandler.php' => true, 'smarty_internal_extension_handler.php' => true, 'smarty_internal_method_addautoloadfilters.php' => true, 'smarty_internal_method_adddefaultmodifiers.php' => true, @@ -450,7 +447,6 @@ class Smarty_Internal_TestInstall 'smarty_internal_resource_extends.php' => true, 'smarty_internal_resource_file.php' => true, 'smarty_internal_resource_php.php' => true, - 'smarty_internal_resource_registered.php' => true, 'smarty_internal_resource_stream.php' => true, 'smarty_internal_resource_string.php' => true, 'smarty_internal_runtime_cachemodify.php' => true, diff --git a/tools/smarty/sysplugins/smarty_resource.php b/tools/smarty/sysplugins/smarty_resource.php index aae7e42f7..fe7751172 100644 --- a/tools/smarty/sysplugins/smarty_resource.php +++ b/tools/smarty/sysplugins/smarty_resource.php @@ -72,17 +72,15 @@ abstract class Smarty_Resource } // try registered resource if (isset($smarty->registered_resources[ $type ])) { - return $smarty->_cache[ 'resource_handlers' ][ $type ] = - $smarty->registered_resources[ $type ] instanceof Smarty_Resource ? - $smarty->registered_resources[ $type ] : new Smarty_Internal_Resource_Registered(); + return $smarty->_cache[ 'resource_handlers' ][ $type ] = $smarty->registered_resources[ $type ]; } // try sysplugins dir if (isset(self::$sysplugins[ $type ])) { - $_resource_class = 'Smarty_Internal_Resource_' . ucfirst($type); + $_resource_class = 'Smarty_Internal_Resource_' . smarty_ucfirst_ascii($type); return $smarty->_cache[ 'resource_handlers' ][ $type ] = new $_resource_class(); } // try plugins dir - $_resource_class = 'Smarty_Resource_' . ucfirst($type); + $_resource_class = 'Smarty_Resource_' . smarty_ucfirst_ascii($type); if ($smarty->loadPlugin($_resource_class)) { if (class_exists($_resource_class, false)) { return $smarty->_cache[ 'resource_handlers' ][ $type ] = new $_resource_class(); @@ -167,16 +165,16 @@ abstract class Smarty_Resource * wrapper for backward compatibility to versions < 3.1.22 * Either [$_template] or [$smarty, $template_resource] must be specified * - * @param Smarty_Internal_Template $_template template object - * @param Smarty $smarty smarty object - * @param string $template_resource resource identifier + * @param Smarty_Internal_Template|null $_template template object + * @param Smarty|null $smarty smarty object + * @param string $template_resource resource identifier * * @return \Smarty_Template_Source Source Object * @throws \SmartyException */ public static function source( - Smarty_Internal_Template $_template = null, - Smarty $smarty = null, + ?Smarty_Internal_Template $_template = null, + ?Smarty $smarty = null, $template_resource = null ) { return Smarty_Template_Source::load($_template, $smarty, $template_resource); @@ -195,10 +193,10 @@ abstract class Smarty_Resource /** * populate Source Object with meta data from Resource * - * @param Smarty_Template_Source $source source object - * @param Smarty_Internal_Template $_template template object + * @param Smarty_Template_Source $source source object + * @param Smarty_Internal_Template|null $_template template object */ - abstract public function populate(Smarty_Template_Source $source, Smarty_Internal_Template $_template = null); + abstract public function populate(Smarty_Template_Source $source, ?Smarty_Internal_Template $_template = null); /** * populate Source Object with timestamp and exists from Resource diff --git a/tools/smarty/sysplugins/smarty_resource_custom.php b/tools/smarty/sysplugins/smarty_resource_custom.php index 8d66be3ae..a73f559c3 100644 --- a/tools/smarty/sysplugins/smarty_resource_custom.php +++ b/tools/smarty/sysplugins/smarty_resource_custom.php @@ -42,12 +42,12 @@ abstract class Smarty_Resource_Custom extends Smarty_Resource /** * populate Source Object with meta data from Resource * - * @param Smarty_Template_Source $source source object - * @param Smarty_Internal_Template $_template template object + * @param Smarty_Template_Source $source source object + * @param Smarty_Internal_Template|null $_template template object */ - public function populate(Smarty_Template_Source $source, Smarty_Internal_Template $_template = null) + public function populate(Smarty_Template_Source $source, ?Smarty_Internal_Template $_template = null) { - $source->filepath = $source->type . ':' . substr(preg_replace('/[^A-Za-z0-9.]/', '', $source->name), 0, 25); + $source->filepath = $source->type . ':' . $this->generateSafeName($source->name); $source->uid = sha1($source->type . ':' . $source->name); $mtime = $this->fetchTimestamp($source->name); if ($mtime !== null) { @@ -88,6 +88,17 @@ abstract class Smarty_Resource_Custom extends Smarty_Resource */ public function getBasename(Smarty_Template_Source $source) { - return basename(substr(preg_replace('/[^A-Za-z0-9.]/', '', $source->name), 0, 25)); + return basename($this->generateSafeName($source->name)); + } + + /** + * Removes special characters from $name and limits its length to 127 characters. + * + * @param $name + * + * @return string + */ + private function generateSafeName($name): string { + return substr(preg_replace('/[^A-Za-z0-9._]/', '', (string) $name), 0, 127); } } diff --git a/tools/smarty/sysplugins/smarty_security.php b/tools/smarty/sysplugins/smarty_security.php index 441a7e284..49ae2a386 100644 --- a/tools/smarty/sysplugins/smarty_security.php +++ b/tools/smarty/sysplugins/smarty_security.php @@ -19,21 +19,9 @@ /** * This class does contain the security settings */ +#[\AllowDynamicProperties] class Smarty_Security { - /** - * This determines how Smarty handles "" tags in templates. - * possible values: - *
    - *
  • Smarty::PHP_PASSTHRU -> echo PHP tags as they are
  • - *
  • Smarty::PHP_QUOTE -> escape tags as entities
  • - *
  • Smarty::PHP_REMOVE -> remove php tags
  • - *
  • Smarty::PHP_ALLOW -> execute php tags
  • - *
- * - * @var integer - */ - public $php_handling = Smarty::PHP_PASSTHRU; /** * This is the list of template directories that are considered secure. @@ -118,7 +106,7 @@ class Smarty_Security * * @var array */ - public $php_modifiers = array('escape', 'count', 'nl2br',); + public $php_modifiers = array('escape', 'count', 'sizeof', 'nl2br',); /** * This is an array of allowed tags. @@ -265,7 +253,7 @@ class Smarty_Security * * @param string $function_name * @param object $compiler compiler object - * + * @deprecated * @return boolean true if function is trusted */ public function isTrustedPhpFunction($function_name, $compiler) @@ -341,7 +329,7 @@ class Smarty_Security * * @param string $modifier_name * @param object $compiler compiler object - * + * @deprecated * @return boolean true if modifier is trusted */ public function isTrustedPhpModifier($modifier_name, $compiler) @@ -568,35 +556,6 @@ class Smarty_Security throw new SmartyException("URI '{$uri}' not allowed by security setting"); } - /** - * Check if directory of file resource is trusted. - * - * @param string $filepath - * - * @return boolean true if directory is trusted - * @throws SmartyException if PHP directory is not trusted - */ - public function isTrustedPHPDir($filepath) - { - if (empty($this->trusted_dir)) { - throw new SmartyException("directory '{$filepath}' not allowed by security setting (no trusted_dir specified)"); - } - // check if index is outdated - if (!$this->_trusted_dir || $this->_trusted_dir !== $this->trusted_dir) { - $this->_php_resource_dir = array(); - $this->_trusted_dir = $this->trusted_dir; - foreach ((array)$this->trusted_dir as $directory) { - $directory = $this->smarty->_realpath($directory . '/', true); - $this->_php_resource_dir[ $directory ] = true; - } - } - $addPath = $this->_checkDir($filepath, $this->_php_resource_dir); - if ($addPath !== false) { - $this->_php_resource_dir = array_merge($this->_php_resource_dir, $addPath); - } - return true; - } - /** * Remove old directories and its sub folders, add new directories * diff --git a/tools/smarty/sysplugins/smarty_template_compiled.php b/tools/smarty/sysplugins/smarty_template_compiled.php index 37d8f0a9e..b78a3b600 100644 --- a/tools/smarty/sysplugins/smarty_template_compiled.php +++ b/tools/smarty/sysplugins/smarty_template_compiled.php @@ -85,7 +85,7 @@ class Smarty_Template_Compiled extends Smarty_Template_Resource_Base * * @param Smarty_Internal_Template $_template * - * @return string + * @return void * @throws Exception */ public function render(Smarty_Internal_Template $_template) diff --git a/tools/smarty/sysplugins/smarty_template_config.php b/tools/smarty/sysplugins/smarty_template_config.php index 850ae32e7..66297304d 100644 --- a/tools/smarty/sysplugins/smarty_template_config.php +++ b/tools/smarty/sysplugins/smarty_template_config.php @@ -63,16 +63,16 @@ class Smarty_Template_Config extends Smarty_Template_Source * initialize Source Object for given resource * Either [$_template] or [$smarty, $template_resource] must be specified * - * @param Smarty_Internal_Template $_template template object - * @param Smarty $smarty smarty object - * @param string $template_resource resource identifier + * @param Smarty_Internal_Template|null $_template template object + * @param Smarty|null $smarty smarty object + * @param string $template_resource resource identifier * * @return Smarty_Template_Config Source Object * @throws SmartyException */ public static function load( - Smarty_Internal_Template $_template = null, - Smarty $smarty = null, + ?Smarty_Internal_Template $_template = null, + ?Smarty $smarty = null, $template_resource = null ) { static $_incompatible_resources = array('extends' => true, 'php' => true); diff --git a/tools/smarty/sysplugins/smarty_template_source.php b/tools/smarty/sysplugins/smarty_template_source.php index 16b47f23c..06053a691 100644 --- a/tools/smarty/sysplugins/smarty_template_source.php +++ b/tools/smarty/sysplugins/smarty_template_source.php @@ -148,16 +148,16 @@ class Smarty_Template_Source * initialize Source Object for given resource * Either [$_template] or [$smarty, $template_resource] must be specified * - * @param Smarty_Internal_Template $_template template object - * @param Smarty $smarty smarty object - * @param string $template_resource resource identifier + * @param Smarty_Internal_Template|null $_template template object + * @param Smarty|null $smarty smarty object + * @param string $template_resource resource identifier * * @return Smarty_Template_Source Source Object * @throws SmartyException */ public static function load( - Smarty_Internal_Template $_template = null, - Smarty $smarty = null, + ?Smarty_Internal_Template $_template = null, + ?Smarty $smarty = null, $template_resource = null ) { if ($_template) { diff --git a/tools/smarty/sysplugins/smarty_variable.php b/tools/smarty/sysplugins/smarty_variable.php index 914d99bd7..6a534228b 100644 --- a/tools/smarty/sysplugins/smarty_variable.php +++ b/tools/smarty/sysplugins/smarty_variable.php @@ -7,6 +7,7 @@ * @package Smarty * @subpackage Template */ +#[\AllowDynamicProperties] class Smarty_Variable { /** diff --git a/tools/smarty/sysplugins/smartycompilerexception.php b/tools/smarty/sysplugins/smartycompilerexception.php index f7ad39b93..755749c28 100644 --- a/tools/smarty/sysplugins/smartycompilerexception.php +++ b/tools/smarty/sysplugins/smartycompilerexception.php @@ -7,6 +7,33 @@ */ class SmartyCompilerException extends SmartyException { + /** + * The constructor of the exception + * + * @param string $message The Exception message to throw. + * @param int $code The Exception code. + * @param string|null $filename The filename where the exception is thrown. + * @param int|null $line The line number where the exception is thrown. + * @param Throwable|null $previous The previous exception used for the exception chaining. + */ + public function __construct( + string $message = "", + int $code = 0, + ?string $filename = null, + ?int $line = null, + ?Throwable $previous = null + ) { + parent::__construct($message, $code, $previous); + + // These are optional parameters, should be be overridden only when present! + if ($filename) { + $this->file = $filename; + } + if ($line) { + $this->line = $line; + } + } + /** * @return string */ @@ -16,11 +43,12 @@ class SmartyCompilerException extends SmartyException } /** - * The line number of the template error - * - * @type int|null + * @param int $line */ - public $line = null; + public function setLine($line) + { + $this->line = $line; + } /** * The template source snippet relating to the error diff --git a/tools/swift/.htaccess b/tools/swift/.htaccess deleted file mode 100644 index 3de9e4008..000000000 --- a/tools/swift/.htaccess +++ /dev/null @@ -1,10 +0,0 @@ -# Apache 2.2 - - Order deny,allow - Deny from all - - -# Apache 2.4 - - Require all denied - diff --git a/tools/swift/CHANGES b/tools/swift/CHANGES deleted file mode 100644 index 3532ec2dc..000000000 --- a/tools/swift/CHANGES +++ /dev/null @@ -1,287 +0,0 @@ -Changelog -========= - -5.4.12 (2018-07-31) -------------------- - - * fixed typo - -5.4.11 (2018-07-31) -------------------- - - * fixed startTLS support for PHP 5.6- - -5.4.10 (2018-07-27) -------------------- - - * fixed startTLS only allowed tls1.0, now allowed: tls1.0, tls1.1, tls1.2 - -5.4.9 (2018-01-23) ------------------- - - * no changes, last version of the 5.x series - -5.4.8 (2017-05-01) ------------------- - - * fixed encoding inheritance in addPart() - * fixed sorting MIME children when their types are equal - -5.4.7 (2017-04-20) ------------------- - - * fixed NTLMAuthenticator clobbering bcmath scale - -5.4.6 (2017-02-13) ------------------- - - * removed exceptions thrown in destructors as they lead to fatal errors - * switched to use sha256 by default in DKIM as per the RFC - * fixed an 'Undefined variable: pipes' PHP notice - * fixed long To headers when using the mail transport - * fixed NTLMAuthenticator when no domain is passed with the username - * prevented fatal error during unserialization of a message - * fixed a PHP warning when sending a message that has a length of a multiple of 8192 - -5.4.5 (2016-12-29) ------------------- - - * SECURITY FIX: fixed CVE-2016-10074 by disallowing potentially unsafe shell characters - - Prior to 5.4.5, the mail transport (Swift_Transport_MailTransport) was vulnerable to passing - arbitrary shell arguments if the "From", "ReturnPath" or "Sender" header came - from a non-trusted source, potentially allowing Remote Code Execution - * deprecated the mail transport - -5.4.4 (2016-11-23) ------------------- - - * reverted escaping command-line args to mail (PHP mail() function already does it) - -5.4.3 (2016-07-08) ------------------- - - * fixed SimpleHeaderSet::has()/get() when the 0 index is removed - * removed the need to have mcrypt installed - * fixed broken MIME header encoding with quotes/colons and non-ascii chars - * allowed mail transport send for messages without To header - * fixed PHP 7 support - -5.4.2 (2016-05-01) ------------------- - - * fixed support for IPv6 sockets - * added auto-retry when sending messages from the memory spool - * fixed consecutive read calls in Swift_ByteStream_FileByteStream - * added support for iso-8859-15 encoding - * fixed PHP mail extra params on missing reversePath - * added methods to set custom stream context options - * fixed charset changes in QpContentEncoderProxy - * added return-path header to the ignoredHeaders list of DKIMSigner - * fixed crlf for subject using mail - * fixed add soft line break only when necessary - * fixed escaping command-line args to mail - -5.4.1 (2015-06-06) ------------------- - - * made Swiftmailer exceptions confirm to PHP base exception constructor signature - * fixed MAIL FROM & RCPT TO headers to be RFC compliant - -5.4.0 (2015-03-14) ------------------- - - * added the possibility to add extra certs to PKCS#7 signature - * fix base64 encoding with streams - * added a new RESULT_SPOOLED status for SpoolTransport - * fixed getBody() on attachments when called more than once - * removed dots from generated filenames in filespool - -5.3.1 (2014-12-05) ------------------- - - * fixed cloning of messages with attachments - -5.3.0 (2014-10-04) ------------------- - - * fixed cloning when using signers - * reverted removal of Swift_Encoding - * drop support for PHP 5.2.x - -5.2.2 (2014-09-20) ------------------- - - * fixed Japanese support - * fixed the memory spool when the message changes when in the pool - * added support for cloning messages - * fixed PHP warning in the redirect plugin - * changed the way to and cc-ed email are sent to only use one transaction - -5.2.1 (2014-06-13) ------------------- - - * SECURITY FIX: fixed CLI escaping when using sendmail as a transport - - Prior to 5.2.1, the sendmail transport (Swift_Transport_SendmailTransport) - was vulnerable to an arbitrary shell execution if the "From" header came - from a non-trusted source and no "Return-Path" is configured. - - * fixed parameter in DKIMSigner - * fixed compatibility with PHP < 5.4 - -5.2.0 (2014-05-08) ------------------- - - * fixed Swift_ByteStream_FileByteStream::read() to match to the specification - * fixed from-charset and to-charset arguments in mbstring_convert_encoding() usages - * fixed infinite loop in StreamBuffer - * fixed NullTransport to return the number of ignored emails instead of 0 - * Use phpunit and mockery for unit testing (realityking) - -5.1.0 (2014-03-18) ------------------- - - * fixed data writing to stream when sending large messages - * added support for libopendkim (https://github.com/xdecock/php-opendkim) - * merged SignedMessage and Message - * added Gmail XOAuth2 authentication - * updated the list of known mime types - * added NTLM authentication - -5.0.3 (2013-12-03) ------------------- - - * fixed double-dot bug - * fixed DKIM signer - -5.0.2 (2013-08-30) ------------------- - - * handled correct exception type while reading IoBuffer output - -5.0.1 (2013-06-17) ------------------- - - * changed the spool to only start the transport when a mail has to be sent - * fixed compatibility with PHP 5.2 - * fixed LICENSE file - -5.0.0 (2013-04-30) ------------------- - - * changed the license from LGPL to MIT - -4.3.1 (2013-04-11) ------------------- - - * removed usage of the native QP encoder when the charset is not UTF-8 - * fixed usage of uniqid to avoid collisions - * made a performance improvement when tokenizing large headers - * fixed usage of the PHP native QP encoder on PHP 5.4.7+ - -4.3.0 (2013-01-08) ------------------- - - * made the temporary directory configurable via the TMPDIR env variable - * added S/MIME signer and encryption support - -4.2.2 (2012-10-25) ------------------- - - * added the possibility to throttle messages per second in ThrottlerPlugin (mostly for Amazon SES) - * switched mime.qpcontentencoder to automatically use the PHP native encoder on PHP 5.4.7+ - * allowed specifying a whitelist with regular expressions in RedirectingPlugin - -4.2.1 (2012-07-13) ------------------- - - * changed the coding standards to PSR-1/2 - * fixed issue with autoloading - * added NativeQpContentEncoder to enhance performance (for PHP 5.3+) - -4.2.0 (2012-06-29) ------------------- - - * added documentation about how to use the Japanese support introduced in 4.1.8 - * added a way to override the default configuration in a lazy way - * changed the PEAR init script to lazy-load the initialization - * fixed a bug when calling Swift_Preferences before anything else (regression introduced in 4.1.8) - -4.1.8 (2012-06-17) ------------------- - - * added Japanese iso-2022-jp support - * changed the init script to lazy-load the initialization - * fixed docblocks (@id) which caused some problems with libraries parsing the dobclocks - * fixed Swift_Mime_Headers_IdentificationHeader::setId() when passed an array of ids - * fixed encoding of email addresses in headers - * added replacements setter to the Decorator plugin - -4.1.7 (2012-04-26) ------------------- - - * fixed QpEncoder safeMapShareId property - -4.1.6 (2012-03-23) ------------------- - - * reduced the size of serialized Messages - -4.1.5 (2012-01-04) ------------------- - - * enforced Swift_Spool::queueMessage() to return a Boolean - * made an optimization to the memory spool: start the transport only when required - * prevented stream_socket_client() from generating an error and throw a Swift_TransportException instead - * fixed a PHP warning when calling to mail() when safe_mode is off - * many doc tweaks - -4.1.4 (2011-12-16) ------------------- - - * added a memory spool (Swift_MemorySpool) - * fixed too many opened files when sending emails with attachments - -4.1.3 (2011-10-27) ------------------- - - * added STARTTLS support - * added missing @return tags on fluent methods - * added a MessageLogger plugin that logs all sent messages - * added composer.json - -4.1.2 (2011-09-13) ------------------- - - * fixed wrong detection of magic_quotes_runtime - * fixed fatal errors when no To or Subject header has been set - * fixed charset on parameter header continuations - * added documentation about how to install Swiftmailer from the PEAR channel - * fixed various typos and markup problem in the documentation - * fixed warning when cache directory does not exist - * fixed "slashes are escaped" bug - * changed require_once() to require() in autoload - -4.1.1 (2011-07-04) ------------------- - - * added missing file in PEAR package - -4.1.0 (2011-06-30) ------------------- - - * documentation has been converted to ReST - -4.1.0 RC1 (2011-06-17) ----------------------- - -New features: - - * changed the Decorator Plugin to allow replacements in all headers - * added Swift_Mime_Grammar and Swift_Validate to validate an email address - * modified the autoloader to lazy-initialize Swiftmailer - * removed Swift_Mailer::batchSend() - * added NullTransport - * added new plugins: RedirectingPlugin and ImpersonatePlugin - * added a way to send messages asynchronously (Spool) diff --git a/tools/swift/README b/tools/swift/README deleted file mode 100644 index 52c075758..000000000 --- a/tools/swift/README +++ /dev/null @@ -1,15 +0,0 @@ -Swift Mailer ------------- - -Swift Mailer is a component based mailing solution for PHP 5. -It is released under the MIT license. - -Homepage: https://swiftmailer.symfony.com/ -Documentation: https://swiftmailer.symfony.com/docs/introduction.html -Bugs: https://github.com/swiftmailer/swiftmailer/issues -Repository: https://github.com/swiftmailer/swiftmailer - -Swift Mailer is highly object-oriented by design and lends itself -to use in complex web application with a great deal of flexibility. - -For full details on usage, see the documentation. diff --git a/tools/swift/VERSION b/tools/swift/VERSION deleted file mode 100644 index 82a2d1d04..000000000 --- a/tools/swift/VERSION +++ /dev/null @@ -1 +0,0 @@ -Swift-5.4.12 diff --git a/tools/swift/classes/Swift.php b/tools/swift/classes/Swift.php deleted file mode 100644 index 82c381b73..000000000 --- a/tools/swift/classes/Swift.php +++ /dev/null @@ -1,80 +0,0 @@ -createDependenciesFor('mime.attachment') - ); - - $this->setBody($data); - $this->setFilename($filename); - if ($contentType) { - $this->setContentType($contentType); - } - } - - /** - * Create a new Attachment. - * - * @param string|Swift_OutputByteStream $data - * @param string $filename - * @param string $contentType - * - * @return Swift_Mime_Attachment - */ - public static function newInstance($data = null, $filename = null, $contentType = null) - { - return new self($data, $filename, $contentType); - } - - /** - * Create a new Attachment from a filesystem path. - * - * @param string $path - * @param string $contentType optional - * - * @return Swift_Mime_Attachment - */ - public static function fromPath($path, $contentType = null) - { - return self::newInstance()->setFile( - new Swift_ByteStream_FileByteStream($path), - $contentType - ); - } -} diff --git a/tools/swift/classes/Swift/ByteStream/AbstractFilterableInputStream.php b/tools/swift/classes/Swift/ByteStream/AbstractFilterableInputStream.php deleted file mode 100644 index a7b0e3a62..000000000 --- a/tools/swift/classes/Swift/ByteStream/AbstractFilterableInputStream.php +++ /dev/null @@ -1,181 +0,0 @@ -_filters[$key] = $filter; - } - - /** - * Remove an already present StreamFilter based on its $key. - * - * @param string $key - */ - public function removeFilter($key) - { - unset($this->_filters[$key]); - } - - /** - * Writes $bytes to the end of the stream. - * - * @param string $bytes - * - * @throws Swift_IoException - * - * @return int - */ - public function write($bytes) - { - $this->_writeBuffer .= $bytes; - foreach ($this->_filters as $filter) { - if ($filter->shouldBuffer($this->_writeBuffer)) { - return; - } - } - $this->_doWrite($this->_writeBuffer); - - return ++$this->_sequence; - } - - /** - * For any bytes that are currently buffered inside the stream, force them - * off the buffer. - * - * @throws Swift_IoException - */ - public function commit() - { - $this->_doWrite($this->_writeBuffer); - } - - /** - * Attach $is to this stream. - * - * The stream acts as an observer, receiving all data that is written. - * All {@link write()} and {@link flushBuffers()} operations will be mirrored. - * - * @param Swift_InputByteStream $is - */ - public function bind(Swift_InputByteStream $is) - { - $this->_mirrors[] = $is; - } - - /** - * Remove an already bound stream. - * - * If $is is not bound, no errors will be raised. - * If the stream currently has any buffered data it will be written to $is - * before unbinding occurs. - * - * @param Swift_InputByteStream $is - */ - public function unbind(Swift_InputByteStream $is) - { - foreach ($this->_mirrors as $k => $stream) { - if ($is === $stream) { - if ($this->_writeBuffer !== '') { - $stream->write($this->_writeBuffer); - } - unset($this->_mirrors[$k]); - } - } - } - - /** - * Flush the contents of the stream (empty it) and set the internal pointer - * to the beginning. - * - * @throws Swift_IoException - */ - public function flushBuffers() - { - if ($this->_writeBuffer !== '') { - $this->_doWrite($this->_writeBuffer); - } - $this->_flush(); - - foreach ($this->_mirrors as $stream) { - $stream->flushBuffers(); - } - } - - /** Run $bytes through all filters */ - private function _filter($bytes) - { - foreach ($this->_filters as $filter) { - $bytes = $filter->filter($bytes); - } - - return $bytes; - } - - /** Just write the bytes to the stream */ - private function _doWrite($bytes) - { - $this->_commit($this->_filter($bytes)); - - foreach ($this->_mirrors as $stream) { - $stream->write($bytes); - } - - $this->_writeBuffer = ''; - } -} diff --git a/tools/swift/classes/Swift/ByteStream/ArrayByteStream.php b/tools/swift/classes/Swift/ByteStream/ArrayByteStream.php deleted file mode 100644 index ef05a6d5e..000000000 --- a/tools/swift/classes/Swift/ByteStream/ArrayByteStream.php +++ /dev/null @@ -1,182 +0,0 @@ -_array = $stack; - $this->_arraySize = count($stack); - } elseif (is_string($stack)) { - $this->write($stack); - } else { - $this->_array = array(); - } - } - - /** - * Reads $length bytes from the stream into a string and moves the pointer - * through the stream by $length. - * - * If less bytes exist than are requested the - * remaining bytes are given instead. If no bytes are remaining at all, boolean - * false is returned. - * - * @param int $length - * - * @return string - */ - public function read($length) - { - if ($this->_offset == $this->_arraySize) { - return false; - } - - // Don't use array slice - $end = $length + $this->_offset; - $end = $this->_arraySize < $end ? $this->_arraySize : $end; - $ret = ''; - for (; $this->_offset < $end; ++$this->_offset) { - $ret .= $this->_array[$this->_offset]; - } - - return $ret; - } - - /** - * Writes $bytes to the end of the stream. - * - * @param string $bytes - */ - public function write($bytes) - { - $to_add = str_split($bytes); - foreach ($to_add as $value) { - $this->_array[] = $value; - } - $this->_arraySize = count($this->_array); - - foreach ($this->_mirrors as $stream) { - $stream->write($bytes); - } - } - - /** - * Not used. - */ - public function commit() - { - } - - /** - * Attach $is to this stream. - * - * The stream acts as an observer, receiving all data that is written. - * All {@link write()} and {@link flushBuffers()} operations will be mirrored. - * - * @param Swift_InputByteStream $is - */ - public function bind(Swift_InputByteStream $is) - { - $this->_mirrors[] = $is; - } - - /** - * Remove an already bound stream. - * - * If $is is not bound, no errors will be raised. - * If the stream currently has any buffered data it will be written to $is - * before unbinding occurs. - * - * @param Swift_InputByteStream $is - */ - public function unbind(Swift_InputByteStream $is) - { - foreach ($this->_mirrors as $k => $stream) { - if ($is === $stream) { - unset($this->_mirrors[$k]); - } - } - } - - /** - * Move the internal read pointer to $byteOffset in the stream. - * - * @param int $byteOffset - * - * @return bool - */ - public function setReadPointer($byteOffset) - { - if ($byteOffset > $this->_arraySize) { - $byteOffset = $this->_arraySize; - } elseif ($byteOffset < 0) { - $byteOffset = 0; - } - - $this->_offset = $byteOffset; - } - - /** - * Flush the contents of the stream (empty it) and set the internal pointer - * to the beginning. - */ - public function flushBuffers() - { - $this->_offset = 0; - $this->_array = array(); - $this->_arraySize = 0; - - foreach ($this->_mirrors as $stream) { - $stream->flushBuffers(); - } - } -} diff --git a/tools/swift/classes/Swift/ByteStream/FileByteStream.php b/tools/swift/classes/Swift/ByteStream/FileByteStream.php deleted file mode 100644 index 9ed852310..000000000 --- a/tools/swift/classes/Swift/ByteStream/FileByteStream.php +++ /dev/null @@ -1,231 +0,0 @@ -_path = $path; - $this->_mode = $writable ? 'w+b' : 'rb'; - - if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) { - $this->_quotes = true; - } - } - - /** - * Get the complete path to the file. - * - * @return string - */ - public function getPath() - { - return $this->_path; - } - - /** - * Reads $length bytes from the stream into a string and moves the pointer - * through the stream by $length. - * - * If less bytes exist than are requested the - * remaining bytes are given instead. If no bytes are remaining at all, boolean - * false is returned. - * - * @param int $length - * - * @throws Swift_IoException - * - * @return string|bool - */ - public function read($length) - { - $fp = $this->_getReadHandle(); - if (!feof($fp)) { - if ($this->_quotes) { - ini_set('magic_quotes_runtime', 0); - } - $bytes = fread($fp, $length); - if ($this->_quotes) { - ini_set('magic_quotes_runtime', 1); - } - $this->_offset = ftell($fp); - - // If we read one byte after reaching the end of the file - // feof() will return false and an empty string is returned - if ($bytes === '' && feof($fp)) { - $this->_resetReadHandle(); - - return false; - } - - return $bytes; - } - - $this->_resetReadHandle(); - - return false; - } - - /** - * Move the internal read pointer to $byteOffset in the stream. - * - * @param int $byteOffset - * - * @return bool - */ - public function setReadPointer($byteOffset) - { - if (isset($this->_reader)) { - $this->_seekReadStreamToPosition($byteOffset); - } - $this->_offset = $byteOffset; - } - - /** Just write the bytes to the file */ - protected function _commit($bytes) - { - fwrite($this->_getWriteHandle(), $bytes); - $this->_resetReadHandle(); - } - - /** Not used */ - protected function _flush() - { - } - - /** Get the resource for reading */ - private function _getReadHandle() - { - if (!isset($this->_reader)) { - $pointer = @fopen($this->_path, 'rb'); - if (!$pointer) { - throw new Swift_IoException( - 'Unable to open file for reading ['.$this->_path.']' - ); - } - $this->_reader = $pointer; - if ($this->_offset != 0) { - $this->_getReadStreamSeekableStatus(); - $this->_seekReadStreamToPosition($this->_offset); - } - } - - return $this->_reader; - } - - /** Get the resource for writing */ - private function _getWriteHandle() - { - if (!isset($this->_writer)) { - if (!$this->_writer = fopen($this->_path, $this->_mode)) { - throw new Swift_IoException( - 'Unable to open file for writing ['.$this->_path.']' - ); - } - } - - return $this->_writer; - } - - /** Force a reload of the resource for reading */ - private function _resetReadHandle() - { - if (isset($this->_reader)) { - fclose($this->_reader); - $this->_reader = null; - } - } - - /** Check if ReadOnly Stream is seekable */ - private function _getReadStreamSeekableStatus() - { - $metas = stream_get_meta_data($this->_reader); - $this->_seekable = $metas['seekable']; - } - - /** Streams in a readOnly stream ensuring copy if needed */ - private function _seekReadStreamToPosition($offset) - { - if ($this->_seekable === null) { - $this->_getReadStreamSeekableStatus(); - } - if ($this->_seekable === false) { - $currentPos = ftell($this->_reader); - if ($currentPos < $offset) { - $toDiscard = $offset - $currentPos; - fread($this->_reader, $toDiscard); - - return; - } - $this->_copyReadStream(); - } - fseek($this->_reader, $offset, SEEK_SET); - } - - /** Copy a readOnly Stream to ensure seekability */ - private function _copyReadStream() - { - if ($tmpFile = fopen('php://temp/maxmemory:4096', 'w+b')) { - /* We have opened a php:// Stream Should work without problem */ - } elseif (function_exists('sys_get_temp_dir') && is_writable(sys_get_temp_dir()) && ($tmpFile = tmpfile())) { - /* We have opened a tmpfile */ - } else { - throw new Swift_IoException('Unable to copy the file to make it seekable, sys_temp_dir is not writable, php://memory not available'); - } - $currentPos = ftell($this->_reader); - fclose($this->_reader); - $source = fopen($this->_path, 'rb'); - if (!$source) { - throw new Swift_IoException('Unable to open file for copying ['.$this->_path.']'); - } - fseek($tmpFile, 0, SEEK_SET); - while (!feof($source)) { - fwrite($tmpFile, fread($source, 4096)); - } - fseek($tmpFile, $currentPos, SEEK_SET); - fclose($source); - $this->_reader = $tmpFile; - } -} diff --git a/tools/swift/classes/Swift/ByteStream/TemporaryFileByteStream.php b/tools/swift/classes/Swift/ByteStream/TemporaryFileByteStream.php deleted file mode 100644 index 1c9a80c03..000000000 --- a/tools/swift/classes/Swift/ByteStream/TemporaryFileByteStream.php +++ /dev/null @@ -1,42 +0,0 @@ -getPath())) === false) { - throw new Swift_IoException('Failed to get temporary file content.'); - } - - return $content; - } - - public function __destruct() - { - if (file_exists($this->getPath())) { - @unlink($this->getPath()); - } - } -} diff --git a/tools/swift/classes/Swift/CharacterReader.php b/tools/swift/classes/Swift/CharacterReader.php deleted file mode 100644 index 4267adbc5..000000000 --- a/tools/swift/classes/Swift/CharacterReader.php +++ /dev/null @@ -1,67 +0,0 @@ - - */ -interface Swift_CharacterReader -{ - const MAP_TYPE_INVALID = 0x01; - const MAP_TYPE_FIXED_LEN = 0x02; - const MAP_TYPE_POSITIONS = 0x03; - - /** - * Returns the complete character map. - * - * @param string $string - * @param int $startOffset - * @param array $currentMap - * @param mixed $ignoredChars - * - * @return int - */ - public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars); - - /** - * Returns the mapType, see constants. - * - * @return int - */ - public function getMapType(); - - /** - * Returns an integer which specifies how many more bytes to read. - * - * A positive integer indicates the number of more bytes to fetch before invoking - * this method again. - * - * A value of zero means this is already a valid character. - * A value of -1 means this cannot possibly be a valid character. - * - * @param int[] $bytes - * @param int $size - * - * @return int - */ - public function validateByteSequence($bytes, $size); - - /** - * Returns the number of bytes which should be read to start each character. - * - * For fixed width character sets this should be the number of octets-per-character. - * For multibyte character sets this will probably be 1. - * - * @return int - */ - public function getInitialByteSize(); -} diff --git a/tools/swift/classes/Swift/CharacterReader/GenericFixedWidthReader.php b/tools/swift/classes/Swift/CharacterReader/GenericFixedWidthReader.php deleted file mode 100644 index 6a18e1dd1..000000000 --- a/tools/swift/classes/Swift/CharacterReader/GenericFixedWidthReader.php +++ /dev/null @@ -1,97 +0,0 @@ - - */ -class Swift_CharacterReader_GenericFixedWidthReader implements Swift_CharacterReader -{ - /** - * The number of bytes in a single character. - * - * @var int - */ - private $_width; - - /** - * Creates a new GenericFixedWidthReader using $width bytes per character. - * - * @param int $width - */ - public function __construct($width) - { - $this->_width = $width; - } - - /** - * Returns the complete character map. - * - * @param string $string - * @param int $startOffset - * @param array $currentMap - * @param mixed $ignoredChars - * - * @return int - */ - public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars) - { - $strlen = strlen($string); - // % and / are CPU intensive, so, maybe find a better way - $ignored = $strlen % $this->_width; - $ignoredChars = $ignored ? substr($string, -$ignored) : ''; - $currentMap = $this->_width; - - return ($strlen - $ignored) / $this->_width; - } - - /** - * Returns the mapType. - * - * @return int - */ - public function getMapType() - { - return self::MAP_TYPE_FIXED_LEN; - } - - /** - * Returns an integer which specifies how many more bytes to read. - * - * A positive integer indicates the number of more bytes to fetch before invoking - * this method again. - * - * A value of zero means this is already a valid character. - * A value of -1 means this cannot possibly be a valid character. - * - * @param string $bytes - * @param int $size - * - * @return int - */ - public function validateByteSequence($bytes, $size) - { - $needed = $this->_width - $size; - - return $needed > -1 ? $needed : -1; - } - - /** - * Returns the number of bytes which should be read to start each character. - * - * @return int - */ - public function getInitialByteSize() - { - return $this->_width; - } -} diff --git a/tools/swift/classes/Swift/CharacterReader/UsAsciiReader.php b/tools/swift/classes/Swift/CharacterReader/UsAsciiReader.php deleted file mode 100644 index 67da48f6c..000000000 --- a/tools/swift/classes/Swift/CharacterReader/UsAsciiReader.php +++ /dev/null @@ -1,84 +0,0 @@ - "\x07F") { - // Invalid char - $currentMap[$i + $startOffset] = $string[$i]; - } - } - - return $strlen; - } - - /** - * Returns mapType. - * - * @return int mapType - */ - public function getMapType() - { - return self::MAP_TYPE_INVALID; - } - - /** - * Returns an integer which specifies how many more bytes to read. - * - * A positive integer indicates the number of more bytes to fetch before invoking - * this method again. - * A value of zero means this is already a valid character. - * A value of -1 means this cannot possibly be a valid character. - * - * @param string $bytes - * @param int $size - * - * @return int - */ - public function validateByteSequence($bytes, $size) - { - $byte = reset($bytes); - if (1 == count($bytes) && $byte >= 0x00 && $byte <= 0x7F) { - return 0; - } - - return -1; - } - - /** - * Returns the number of bytes which should be read to start each character. - * - * @return int - */ - public function getInitialByteSize() - { - return 1; - } -} diff --git a/tools/swift/classes/Swift/CharacterReader/Utf8Reader.php b/tools/swift/classes/Swift/CharacterReader/Utf8Reader.php deleted file mode 100644 index 22746bd85..000000000 --- a/tools/swift/classes/Swift/CharacterReader/Utf8Reader.php +++ /dev/null @@ -1,176 +0,0 @@ - - */ -class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader -{ - /** Pre-computed for optimization */ - private static $length_map = array( - // N=0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x0N - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x1N - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x2N - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x3N - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x4N - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x5N - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x6N - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x7N - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x8N - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x9N - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xAN - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xBN - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xCN - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xDN - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEN - 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0, // 0xFN - ); - - private static $s_length_map = array( - "\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1, - "\x08" => 1, "\x09" => 1, "\x0a" => 1, "\x0b" => 1, "\x0c" => 1, "\x0d" => 1, "\x0e" => 1, "\x0f" => 1, - "\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1, - "\x18" => 1, "\x19" => 1, "\x1a" => 1, "\x1b" => 1, "\x1c" => 1, "\x1d" => 1, "\x1e" => 1, "\x1f" => 1, - "\x20" => 1, "\x21" => 1, "\x22" => 1, "\x23" => 1, "\x24" => 1, "\x25" => 1, "\x26" => 1, "\x27" => 1, - "\x28" => 1, "\x29" => 1, "\x2a" => 1, "\x2b" => 1, "\x2c" => 1, "\x2d" => 1, "\x2e" => 1, "\x2f" => 1, - "\x30" => 1, "\x31" => 1, "\x32" => 1, "\x33" => 1, "\x34" => 1, "\x35" => 1, "\x36" => 1, "\x37" => 1, - "\x38" => 1, "\x39" => 1, "\x3a" => 1, "\x3b" => 1, "\x3c" => 1, "\x3d" => 1, "\x3e" => 1, "\x3f" => 1, - "\x40" => 1, "\x41" => 1, "\x42" => 1, "\x43" => 1, "\x44" => 1, "\x45" => 1, "\x46" => 1, "\x47" => 1, - "\x48" => 1, "\x49" => 1, "\x4a" => 1, "\x4b" => 1, "\x4c" => 1, "\x4d" => 1, "\x4e" => 1, "\x4f" => 1, - "\x50" => 1, "\x51" => 1, "\x52" => 1, "\x53" => 1, "\x54" => 1, "\x55" => 1, "\x56" => 1, "\x57" => 1, - "\x58" => 1, "\x59" => 1, "\x5a" => 1, "\x5b" => 1, "\x5c" => 1, "\x5d" => 1, "\x5e" => 1, "\x5f" => 1, - "\x60" => 1, "\x61" => 1, "\x62" => 1, "\x63" => 1, "\x64" => 1, "\x65" => 1, "\x66" => 1, "\x67" => 1, - "\x68" => 1, "\x69" => 1, "\x6a" => 1, "\x6b" => 1, "\x6c" => 1, "\x6d" => 1, "\x6e" => 1, "\x6f" => 1, - "\x70" => 1, "\x71" => 1, "\x72" => 1, "\x73" => 1, "\x74" => 1, "\x75" => 1, "\x76" => 1, "\x77" => 1, - "\x78" => 1, "\x79" => 1, "\x7a" => 1, "\x7b" => 1, "\x7c" => 1, "\x7d" => 1, "\x7e" => 1, "\x7f" => 1, - "\x80" => 0, "\x81" => 0, "\x82" => 0, "\x83" => 0, "\x84" => 0, "\x85" => 0, "\x86" => 0, "\x87" => 0, - "\x88" => 0, "\x89" => 0, "\x8a" => 0, "\x8b" => 0, "\x8c" => 0, "\x8d" => 0, "\x8e" => 0, "\x8f" => 0, - "\x90" => 0, "\x91" => 0, "\x92" => 0, "\x93" => 0, "\x94" => 0, "\x95" => 0, "\x96" => 0, "\x97" => 0, - "\x98" => 0, "\x99" => 0, "\x9a" => 0, "\x9b" => 0, "\x9c" => 0, "\x9d" => 0, "\x9e" => 0, "\x9f" => 0, - "\xa0" => 0, "\xa1" => 0, "\xa2" => 0, "\xa3" => 0, "\xa4" => 0, "\xa5" => 0, "\xa6" => 0, "\xa7" => 0, - "\xa8" => 0, "\xa9" => 0, "\xaa" => 0, "\xab" => 0, "\xac" => 0, "\xad" => 0, "\xae" => 0, "\xaf" => 0, - "\xb0" => 0, "\xb1" => 0, "\xb2" => 0, "\xb3" => 0, "\xb4" => 0, "\xb5" => 0, "\xb6" => 0, "\xb7" => 0, - "\xb8" => 0, "\xb9" => 0, "\xba" => 0, "\xbb" => 0, "\xbc" => 0, "\xbd" => 0, "\xbe" => 0, "\xbf" => 0, - "\xc0" => 2, "\xc1" => 2, "\xc2" => 2, "\xc3" => 2, "\xc4" => 2, "\xc5" => 2, "\xc6" => 2, "\xc7" => 2, - "\xc8" => 2, "\xc9" => 2, "\xca" => 2, "\xcb" => 2, "\xcc" => 2, "\xcd" => 2, "\xce" => 2, "\xcf" => 2, - "\xd0" => 2, "\xd1" => 2, "\xd2" => 2, "\xd3" => 2, "\xd4" => 2, "\xd5" => 2, "\xd6" => 2, "\xd7" => 2, - "\xd8" => 2, "\xd9" => 2, "\xda" => 2, "\xdb" => 2, "\xdc" => 2, "\xdd" => 2, "\xde" => 2, "\xdf" => 2, - "\xe0" => 3, "\xe1" => 3, "\xe2" => 3, "\xe3" => 3, "\xe4" => 3, "\xe5" => 3, "\xe6" => 3, "\xe7" => 3, - "\xe8" => 3, "\xe9" => 3, "\xea" => 3, "\xeb" => 3, "\xec" => 3, "\xed" => 3, "\xee" => 3, "\xef" => 3, - "\xf0" => 4, "\xf1" => 4, "\xf2" => 4, "\xf3" => 4, "\xf4" => 4, "\xf5" => 4, "\xf6" => 4, "\xf7" => 4, - "\xf8" => 5, "\xf9" => 5, "\xfa" => 5, "\xfb" => 5, "\xfc" => 6, "\xfd" => 6, "\xfe" => 0, "\xff" => 0, - ); - - /** - * Returns the complete character map. - * - * @param string $string - * @param int $startOffset - * @param array $currentMap - * @param mixed $ignoredChars - * - * @return int - */ - public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars) - { - if (!isset($currentMap['i']) || !isset($currentMap['p'])) { - $currentMap['p'] = $currentMap['i'] = array(); - } - - $strlen = strlen($string); - $charPos = count($currentMap['p']); - $foundChars = 0; - $invalid = false; - for ($i = 0; $i < $strlen; ++$i) { - $char = $string[$i]; - $size = self::$s_length_map[$char]; - if ($size == 0) { - /* char is invalid, we must wait for a resync */ - $invalid = true; - continue; - } else { - if ($invalid == true) { - /* We mark the chars as invalid and start a new char */ - $currentMap['p'][$charPos + $foundChars] = $startOffset + $i; - $currentMap['i'][$charPos + $foundChars] = true; - ++$foundChars; - $invalid = false; - } - if (($i + $size) > $strlen) { - $ignoredChars = substr($string, $i); - break; - } - for ($j = 1; $j < $size; ++$j) { - $char = $string[$i + $j]; - if ($char > "\x7F" && $char < "\xC0") { - // Valid - continue parsing - } else { - /* char is invalid, we must wait for a resync */ - $invalid = true; - continue 2; - } - } - /* Ok we got a complete char here */ - $currentMap['p'][$charPos + $foundChars] = $startOffset + $i + $size; - $i += $j - 1; - ++$foundChars; - } - } - - return $foundChars; - } - - /** - * Returns mapType. - * - * @return int mapType - */ - public function getMapType() - { - return self::MAP_TYPE_POSITIONS; - } - - /** - * Returns an integer which specifies how many more bytes to read. - * - * A positive integer indicates the number of more bytes to fetch before invoking - * this method again. - * A value of zero means this is already a valid character. - * A value of -1 means this cannot possibly be a valid character. - * - * @param string $bytes - * @param int $size - * - * @return int - */ - public function validateByteSequence($bytes, $size) - { - if ($size < 1) { - return -1; - } - $needed = self::$length_map[$bytes[0]] - $size; - - return $needed > -1 ? $needed : -1; - } - - /** - * Returns the number of bytes which should be read to start each character. - * - * @return int - */ - public function getInitialByteSize() - { - return 1; - } -} diff --git a/tools/swift/classes/Swift/CharacterReaderFactory.php b/tools/swift/classes/Swift/CharacterReaderFactory.php deleted file mode 100644 index 15b6c6920..000000000 --- a/tools/swift/classes/Swift/CharacterReaderFactory.php +++ /dev/null @@ -1,26 +0,0 @@ -init(); - } - - public function __wakeup() - { - $this->init(); - } - - public function init() - { - if (count(self::$_map) > 0) { - return; - } - - $prefix = 'Swift_CharacterReader_'; - - $singleByte = array( - 'class' => $prefix.'GenericFixedWidthReader', - 'constructor' => array(1), - ); - - $doubleByte = array( - 'class' => $prefix.'GenericFixedWidthReader', - 'constructor' => array(2), - ); - - $fourBytes = array( - 'class' => $prefix.'GenericFixedWidthReader', - 'constructor' => array(4), - ); - - // Utf-8 - self::$_map['utf-?8'] = array( - 'class' => $prefix.'Utf8Reader', - 'constructor' => array(), - ); - - //7-8 bit charsets - self::$_map['(us-)?ascii'] = $singleByte; - self::$_map['(iso|iec)-?8859-?[0-9]+'] = $singleByte; - self::$_map['windows-?125[0-9]'] = $singleByte; - self::$_map['cp-?[0-9]+'] = $singleByte; - self::$_map['ansi'] = $singleByte; - self::$_map['macintosh'] = $singleByte; - self::$_map['koi-?7'] = $singleByte; - self::$_map['koi-?8-?.+'] = $singleByte; - self::$_map['mik'] = $singleByte; - self::$_map['(cork|t1)'] = $singleByte; - self::$_map['v?iscii'] = $singleByte; - - //16 bits - self::$_map['(ucs-?2|utf-?16)'] = $doubleByte; - - //32 bits - self::$_map['(ucs-?4|utf-?32)'] = $fourBytes; - - // Fallback - self::$_map['.*'] = $singleByte; - } - - /** - * Returns a CharacterReader suitable for the charset applied. - * - * @param string $charset - * - * @return Swift_CharacterReader - */ - public function getReaderFor($charset) - { - $charset = trim(strtolower($charset)); - foreach (self::$_map as $pattern => $spec) { - $re = '/^'.$pattern.'$/D'; - if (preg_match($re, $charset)) { - if (!array_key_exists($pattern, self::$_loaded)) { - $reflector = new ReflectionClass($spec['class']); - if ($reflector->getConstructor()) { - $reader = $reflector->newInstanceArgs($spec['constructor']); - } else { - $reader = $reflector->newInstance(); - } - self::$_loaded[$pattern] = $reader; - } - - return self::$_loaded[$pattern]; - } - } - } -} diff --git a/tools/swift/classes/Swift/CharacterStream.php b/tools/swift/classes/Swift/CharacterStream.php deleted file mode 100644 index 717924f5d..000000000 --- a/tools/swift/classes/Swift/CharacterStream.php +++ /dev/null @@ -1,89 +0,0 @@ -setCharacterReaderFactory($factory); - $this->setCharacterSet($charset); - } - - /** - * Set the character set used in this CharacterStream. - * - * @param string $charset - */ - public function setCharacterSet($charset) - { - $this->_charset = $charset; - $this->_charReader = null; - } - - /** - * Set the CharacterReaderFactory for multi charset support. - * - * @param Swift_CharacterReaderFactory $factory - */ - public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory) - { - $this->_charReaderFactory = $factory; - } - - /** - * Overwrite this character stream using the byte sequence in the byte stream. - * - * @param Swift_OutputByteStream $os output stream to read from - */ - public function importByteStream(Swift_OutputByteStream $os) - { - if (!isset($this->_charReader)) { - $this->_charReader = $this->_charReaderFactory - ->getReaderFor($this->_charset); - } - - $startLength = $this->_charReader->getInitialByteSize(); - while (false !== $bytes = $os->read($startLength)) { - $c = array(); - for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) { - $c[] = self::$_byteMap[$bytes[$i]]; - } - $size = count($c); - $need = $this->_charReader - ->validateByteSequence($c, $size); - if ($need > 0 && - false !== $bytes = $os->read($need)) { - for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) { - $c[] = self::$_byteMap[$bytes[$i]]; - } - } - $this->_array[] = $c; - ++$this->_array_size; - } - } - - /** - * Import a string a bytes into this CharacterStream, overwriting any existing - * data in the stream. - * - * @param string $string - */ - public function importString($string) - { - $this->flushContents(); - $this->write($string); - } - - /** - * Read $length characters from the stream and move the internal pointer - * $length further into the stream. - * - * @param int $length - * - * @return string - */ - public function read($length) - { - if ($this->_offset == $this->_array_size) { - return false; - } - - // Don't use array slice - $arrays = array(); - $end = $length + $this->_offset; - for ($i = $this->_offset; $i < $end; ++$i) { - if (!isset($this->_array[$i])) { - break; - } - $arrays[] = $this->_array[$i]; - } - $this->_offset += $i - $this->_offset; // Limit function calls - $chars = false; - foreach ($arrays as $array) { - $chars .= implode('', array_map('chr', $array)); - } - - return $chars; - } - - /** - * Read $length characters from the stream and return a 1-dimensional array - * containing there octet values. - * - * @param int $length - * - * @return int[] - */ - public function readBytes($length) - { - if ($this->_offset == $this->_array_size) { - return false; - } - $arrays = array(); - $end = $length + $this->_offset; - for ($i = $this->_offset; $i < $end; ++$i) { - if (!isset($this->_array[$i])) { - break; - } - $arrays[] = $this->_array[$i]; - } - $this->_offset += ($i - $this->_offset); // Limit function calls - - return call_user_func_array('array_merge', $arrays); - } - - /** - * Write $chars to the end of the stream. - * - * @param string $chars - */ - public function write($chars) - { - if (!isset($this->_charReader)) { - $this->_charReader = $this->_charReaderFactory->getReaderFor( - $this->_charset); - } - - $startLength = $this->_charReader->getInitialByteSize(); - - $fp = fopen('php://memory', 'w+b'); - fwrite($fp, $chars); - unset($chars); - fseek($fp, 0, SEEK_SET); - - $buffer = array(0); - $buf_pos = 1; - $buf_len = 1; - $has_datas = true; - do { - $bytes = array(); - // Buffer Filing - if ($buf_len - $buf_pos < $startLength) { - $buf = array_splice($buffer, $buf_pos); - $new = $this->_reloadBuffer($fp, 100); - if ($new) { - $buffer = array_merge($buf, $new); - $buf_len = count($buffer); - $buf_pos = 0; - } else { - $has_datas = false; - } - } - if ($buf_len - $buf_pos > 0) { - $size = 0; - for ($i = 0; $i < $startLength && isset($buffer[$buf_pos]); ++$i) { - ++$size; - $bytes[] = $buffer[$buf_pos++]; - } - $need = $this->_charReader->validateByteSequence( - $bytes, $size); - if ($need > 0) { - if ($buf_len - $buf_pos < $need) { - $new = $this->_reloadBuffer($fp, $need); - - if ($new) { - $buffer = array_merge($buffer, $new); - $buf_len = count($buffer); - } - } - for ($i = 0; $i < $need && isset($buffer[$buf_pos]); ++$i) { - $bytes[] = $buffer[$buf_pos++]; - } - } - $this->_array[] = $bytes; - ++$this->_array_size; - } - } while ($has_datas); - - fclose($fp); - } - - /** - * Move the internal pointer to $charOffset in the stream. - * - * @param int $charOffset - */ - public function setPointer($charOffset) - { - if ($charOffset > $this->_array_size) { - $charOffset = $this->_array_size; - } elseif ($charOffset < 0) { - $charOffset = 0; - } - $this->_offset = $charOffset; - } - - /** - * Empty the stream and reset the internal pointer. - */ - public function flushContents() - { - $this->_offset = 0; - $this->_array = array(); - $this->_array_size = 0; - } - - private function _reloadBuffer($fp, $len) - { - if (!feof($fp) && ($bytes = fread($fp, $len)) !== false) { - $buf = array(); - for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) { - $buf[] = self::$_byteMap[$bytes[$i]]; - } - - return $buf; - } - - return false; - } - - private static function _initializeMaps() - { - if (!isset(self::$_charMap)) { - self::$_charMap = array(); - for ($byte = 0; $byte < 256; ++$byte) { - self::$_charMap[$byte] = chr($byte); - } - self::$_byteMap = array_flip(self::$_charMap); - } - } -} diff --git a/tools/swift/classes/Swift/CharacterStream/NgCharacterStream.php b/tools/swift/classes/Swift/CharacterStream/NgCharacterStream.php deleted file mode 100644 index 58bd140fd..000000000 --- a/tools/swift/classes/Swift/CharacterStream/NgCharacterStream.php +++ /dev/null @@ -1,267 +0,0 @@ - - */ -class Swift_CharacterStream_NgCharacterStream implements Swift_CharacterStream -{ - /** - * The char reader (lazy-loaded) for the current charset. - * - * @var Swift_CharacterReader - */ - private $_charReader; - - /** - * A factory for creating CharacterReader instances. - * - * @var Swift_CharacterReaderFactory - */ - private $_charReaderFactory; - - /** - * The character set this stream is using. - * - * @var string - */ - private $_charset; - - /** - * The data's stored as-is. - * - * @var string - */ - private $_datas = ''; - - /** - * Number of bytes in the stream. - * - * @var int - */ - private $_datasSize = 0; - - /** - * Map. - * - * @var mixed - */ - private $_map; - - /** - * Map Type. - * - * @var int - */ - private $_mapType = 0; - - /** - * Number of characters in the stream. - * - * @var int - */ - private $_charCount = 0; - - /** - * Position in the stream. - * - * @var int - */ - private $_currentPos = 0; - - /** - * Constructor. - * - * @param Swift_CharacterReaderFactory $factory - * @param string $charset - */ - public function __construct(Swift_CharacterReaderFactory $factory, $charset) - { - $this->setCharacterReaderFactory($factory); - $this->setCharacterSet($charset); - } - - /* -- Changing parameters of the stream -- */ - - /** - * Set the character set used in this CharacterStream. - * - * @param string $charset - */ - public function setCharacterSet($charset) - { - $this->_charset = $charset; - $this->_charReader = null; - $this->_mapType = 0; - } - - /** - * Set the CharacterReaderFactory for multi charset support. - * - * @param Swift_CharacterReaderFactory $factory - */ - public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory) - { - $this->_charReaderFactory = $factory; - } - - /** - * @see Swift_CharacterStream::flushContents() - */ - public function flushContents() - { - $this->_datas = null; - $this->_map = null; - $this->_charCount = 0; - $this->_currentPos = 0; - $this->_datasSize = 0; - } - - /** - * @see Swift_CharacterStream::importByteStream() - * - * @param Swift_OutputByteStream $os - */ - public function importByteStream(Swift_OutputByteStream $os) - { - $this->flushContents(); - $blocks = 512; - $os->setReadPointer(0); - while (false !== ($read = $os->read($blocks))) { - $this->write($read); - } - } - - /** - * @see Swift_CharacterStream::importString() - * - * @param string $string - */ - public function importString($string) - { - $this->flushContents(); - $this->write($string); - } - - /** - * @see Swift_CharacterStream::read() - * - * @param int $length - * - * @return string - */ - public function read($length) - { - if ($this->_currentPos >= $this->_charCount) { - return false; - } - $ret = false; - $length = $this->_currentPos + $length > $this->_charCount ? $this->_charCount - $this->_currentPos : $length; - switch ($this->_mapType) { - case Swift_CharacterReader::MAP_TYPE_FIXED_LEN: - $len = $length * $this->_map; - $ret = substr($this->_datas, - $this->_currentPos * $this->_map, - $len); - $this->_currentPos += $length; - break; - - case Swift_CharacterReader::MAP_TYPE_INVALID: - $ret = ''; - for (; $this->_currentPos < $length; ++$this->_currentPos) { - if (isset($this->_map[$this->_currentPos])) { - $ret .= '?'; - } else { - $ret .= $this->_datas[$this->_currentPos]; - } - } - break; - - case Swift_CharacterReader::MAP_TYPE_POSITIONS: - $end = $this->_currentPos + $length; - $end = $end > $this->_charCount ? $this->_charCount : $end; - $ret = ''; - $start = 0; - if ($this->_currentPos > 0) { - $start = $this->_map['p'][$this->_currentPos - 1]; - } - $to = $start; - for (; $this->_currentPos < $end; ++$this->_currentPos) { - if (isset($this->_map['i'][$this->_currentPos])) { - $ret .= substr($this->_datas, $start, $to - $start).'?'; - $start = $this->_map['p'][$this->_currentPos]; - } else { - $to = $this->_map['p'][$this->_currentPos]; - } - } - $ret .= substr($this->_datas, $start, $to - $start); - break; - } - - return $ret; - } - - /** - * @see Swift_CharacterStream::readBytes() - * - * @param int $length - * - * @return int[] - */ - public function readBytes($length) - { - $read = $this->read($length); - if ($read !== false) { - $ret = array_map('ord', str_split($read, 1)); - - return $ret; - } - - return false; - } - - /** - * @see Swift_CharacterStream::setPointer() - * - * @param int $charOffset - */ - public function setPointer($charOffset) - { - if ($this->_charCount < $charOffset) { - $charOffset = $this->_charCount; - } - $this->_currentPos = $charOffset; - } - - /** - * @see Swift_CharacterStream::write() - * - * @param string $chars - */ - public function write($chars) - { - if (!isset($this->_charReader)) { - $this->_charReader = $this->_charReaderFactory->getReaderFor( - $this->_charset); - $this->_map = array(); - $this->_mapType = $this->_charReader->getMapType(); - } - $ignored = ''; - $this->_datas .= $chars; - $this->_charCount += $this->_charReader->getCharPositions(substr($this->_datas, $this->_datasSize), $this->_datasSize, $this->_map, $ignored); - if ($ignored !== false) { - $this->_datasSize = strlen($this->_datas) - strlen($ignored); - } else { - $this->_datasSize = strlen($this->_datas); - } - } -} diff --git a/tools/swift/classes/Swift/ConfigurableSpool.php b/tools/swift/classes/Swift/ConfigurableSpool.php deleted file mode 100644 index 4ae5bacfc..000000000 --- a/tools/swift/classes/Swift/ConfigurableSpool.php +++ /dev/null @@ -1,63 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Base class for Spools (implements time and message limits). - * - * @author Fabien Potencier - */ -abstract class Swift_ConfigurableSpool implements Swift_Spool -{ - /** The maximum number of messages to send per flush */ - private $_message_limit; - - /** The time limit per flush */ - private $_time_limit; - - /** - * Sets the maximum number of messages to send per flush. - * - * @param int $limit - */ - public function setMessageLimit($limit) - { - $this->_message_limit = (int) $limit; - } - - /** - * Gets the maximum number of messages to send per flush. - * - * @return int The limit - */ - public function getMessageLimit() - { - return $this->_message_limit; - } - - /** - * Sets the time limit (in seconds) per flush. - * - * @param int $limit The limit - */ - public function setTimeLimit($limit) - { - $this->_time_limit = (int) $limit; - } - - /** - * Gets the time limit (in seconds) per flush. - * - * @return int The limit - */ - public function getTimeLimit() - { - return $this->_time_limit; - } -} diff --git a/tools/swift/classes/Swift/DependencyContainer.php b/tools/swift/classes/Swift/DependencyContainer.php deleted file mode 100644 index befec9ac0..000000000 --- a/tools/swift/classes/Swift/DependencyContainer.php +++ /dev/null @@ -1,373 +0,0 @@ -_store); - } - - /** - * Test if an item is registered in this container with the given name. - * - * @see register() - * - * @param string $itemName - * - * @return bool - */ - public function has($itemName) - { - return array_key_exists($itemName, $this->_store) - && isset($this->_store[$itemName]['lookupType']); - } - - /** - * Lookup the item with the given $itemName. - * - * @see register() - * - * @param string $itemName - * - * @throws Swift_DependencyException If the dependency is not found - * - * @return mixed - */ - public function lookup($itemName) - { - if (!$this->has($itemName)) { - throw new Swift_DependencyException( - 'Cannot lookup dependency "'.$itemName.'" since it is not registered.' - ); - } - - switch ($this->_store[$itemName]['lookupType']) { - case self::TYPE_ALIAS: - return $this->_createAlias($itemName); - case self::TYPE_VALUE: - return $this->_getValue($itemName); - case self::TYPE_INSTANCE: - return $this->_createNewInstance($itemName); - case self::TYPE_SHARED: - return $this->_createSharedInstance($itemName); - } - } - - /** - * Create an array of arguments passed to the constructor of $itemName. - * - * @param string $itemName - * - * @return array - */ - public function createDependenciesFor($itemName) - { - $args = array(); - if (isset($this->_store[$itemName]['args'])) { - $args = $this->_resolveArgs($this->_store[$itemName]['args']); - } - - return $args; - } - - /** - * Register a new dependency with $itemName. - * - * This method returns the current DependencyContainer instance because it - * requires the use of the fluid interface to set the specific details for the - * dependency. - * - * @see asNewInstanceOf(), asSharedInstanceOf(), asValue() - * - * @param string $itemName - * - * @return $this - */ - public function register($itemName) - { - $this->_store[$itemName] = array(); - $this->_endPoint = &$this->_store[$itemName]; - - return $this; - } - - /** - * Specify the previously registered item as a literal value. - * - * {@link register()} must be called before this will work. - * - * @param mixed $value - * - * @return $this - */ - public function asValue($value) - { - $endPoint = &$this->_getEndPoint(); - $endPoint['lookupType'] = self::TYPE_VALUE; - $endPoint['value'] = $value; - - return $this; - } - - /** - * Specify the previously registered item as an alias of another item. - * - * @param string $lookup - * - * @return $this - */ - public function asAliasOf($lookup) - { - $endPoint = &$this->_getEndPoint(); - $endPoint['lookupType'] = self::TYPE_ALIAS; - $endPoint['ref'] = $lookup; - - return $this; - } - - /** - * Specify the previously registered item as a new instance of $className. - * - * {@link register()} must be called before this will work. - * Any arguments can be set with {@link withDependencies()}, - * {@link addConstructorValue()} or {@link addConstructorLookup()}. - * - * @see withDependencies(), addConstructorValue(), addConstructorLookup() - * - * @param string $className - * - * @return $this - */ - public function asNewInstanceOf($className) - { - $endPoint = &$this->_getEndPoint(); - $endPoint['lookupType'] = self::TYPE_INSTANCE; - $endPoint['className'] = $className; - - return $this; - } - - /** - * Specify the previously registered item as a shared instance of $className. - * - * {@link register()} must be called before this will work. - * - * @param string $className - * - * @return $this - */ - public function asSharedInstanceOf($className) - { - $endPoint = &$this->_getEndPoint(); - $endPoint['lookupType'] = self::TYPE_SHARED; - $endPoint['className'] = $className; - - return $this; - } - - /** - * Specify a list of injected dependencies for the previously registered item. - * - * This method takes an array of lookup names. - * - * @see addConstructorValue(), addConstructorLookup() - * - * @param array $lookups - * - * @return $this - */ - public function withDependencies(array $lookups) - { - $endPoint = &$this->_getEndPoint(); - $endPoint['args'] = array(); - foreach ($lookups as $lookup) { - $this->addConstructorLookup($lookup); - } - - return $this; - } - - /** - * Specify a literal (non looked up) value for the constructor of the - * previously registered item. - * - * @see withDependencies(), addConstructorLookup() - * - * @param mixed $value - * - * @return $this - */ - public function addConstructorValue($value) - { - $endPoint = &$this->_getEndPoint(); - if (!isset($endPoint['args'])) { - $endPoint['args'] = array(); - } - $endPoint['args'][] = array('type' => 'value', 'item' => $value); - - return $this; - } - - /** - * Specify a dependency lookup for the constructor of the previously - * registered item. - * - * @see withDependencies(), addConstructorValue() - * - * @param string $lookup - * - * @return $this - */ - public function addConstructorLookup($lookup) - { - $endPoint = &$this->_getEndPoint(); - if (!isset($this->_endPoint['args'])) { - $endPoint['args'] = array(); - } - $endPoint['args'][] = array('type' => 'lookup', 'item' => $lookup); - - return $this; - } - - /** Get the literal value with $itemName */ - private function _getValue($itemName) - { - return $this->_store[$itemName]['value']; - } - - /** Resolve an alias to another item */ - private function _createAlias($itemName) - { - return $this->lookup($this->_store[$itemName]['ref']); - } - - /** Create a fresh instance of $itemName */ - private function _createNewInstance($itemName) - { - $reflector = new ReflectionClass($this->_store[$itemName]['className']); - if ($reflector->getConstructor()) { - return $reflector->newInstanceArgs( - $this->createDependenciesFor($itemName) - ); - } - - return $reflector->newInstance(); - } - - /** Create and register a shared instance of $itemName */ - private function _createSharedInstance($itemName) - { - if (!isset($this->_store[$itemName]['instance'])) { - $this->_store[$itemName]['instance'] = $this->_createNewInstance($itemName); - } - - return $this->_store[$itemName]['instance']; - } - - /** Get the current endpoint in the store */ - private function &_getEndPoint() - { - if (!isset($this->_endPoint)) { - throw new BadMethodCallException( - 'Component must first be registered by calling register()' - ); - } - - return $this->_endPoint; - } - - /** Get an argument list with dependencies resolved */ - private function _resolveArgs(array $args) - { - $resolved = array(); - foreach ($args as $argDefinition) { - switch ($argDefinition['type']) { - case 'lookup': - $resolved[] = $this->_lookupRecursive($argDefinition['item']); - break; - case 'value': - $resolved[] = $argDefinition['item']; - break; - } - } - - return $resolved; - } - - /** Resolve a single dependency with an collections */ - private function _lookupRecursive($item) - { - if (is_array($item)) { - $collection = array(); - foreach ($item as $k => $v) { - $collection[$k] = $this->_lookupRecursive($v); - } - - return $collection; - } - - return $this->lookup($item); - } -} diff --git a/tools/swift/classes/Swift/DependencyException.php b/tools/swift/classes/Swift/DependencyException.php deleted file mode 100644 index 799d38d83..000000000 --- a/tools/swift/classes/Swift/DependencyException.php +++ /dev/null @@ -1,27 +0,0 @@ -createDependenciesFor('mime.embeddedfile') - ); - - $this->setBody($data); - $this->setFilename($filename); - if ($contentType) { - $this->setContentType($contentType); - } - } - - /** - * Create a new EmbeddedFile. - * - * @param string|Swift_OutputByteStream $data - * @param string $filename - * @param string $contentType - * - * @return Swift_Mime_EmbeddedFile - */ - public static function newInstance($data = null, $filename = null, $contentType = null) - { - return new self($data, $filename, $contentType); - } - - /** - * Create a new EmbeddedFile from a filesystem path. - * - * @param string $path - * - * @return Swift_Mime_EmbeddedFile - */ - public static function fromPath($path) - { - return self::newInstance()->setFile( - new Swift_ByteStream_FileByteStream($path) - ); - } -} diff --git a/tools/swift/classes/Swift/Encoder.php b/tools/swift/classes/Swift/Encoder.php deleted file mode 100644 index 2073abca1..000000000 --- a/tools/swift/classes/Swift/Encoder.php +++ /dev/null @@ -1,28 +0,0 @@ -= $maxLineLength || 76 < $maxLineLength) { - $maxLineLength = 76; - } - - $encodedString = base64_encode($string); - $firstLine = ''; - - if (0 != $firstLineOffset) { - $firstLine = substr( - $encodedString, 0, $maxLineLength - $firstLineOffset - )."\r\n"; - $encodedString = substr( - $encodedString, $maxLineLength - $firstLineOffset - ); - } - - return $firstLine.trim(chunk_split($encodedString, $maxLineLength, "\r\n")); - } - - /** - * Does nothing. - */ - public function charsetChanged($charset) - { - } -} diff --git a/tools/swift/classes/Swift/Encoder/Rfc2231Encoder.php b/tools/swift/classes/Swift/Encoder/Rfc2231Encoder.php deleted file mode 100644 index b0215e883..000000000 --- a/tools/swift/classes/Swift/Encoder/Rfc2231Encoder.php +++ /dev/null @@ -1,92 +0,0 @@ -_charStream = $charStream; - } - - /** - * Takes an unencoded string and produces a string encoded according to - * RFC 2231 from it. - * - * @param string $string - * @param int $firstLineOffset - * @param int $maxLineLength optional, 0 indicates the default of 75 bytes - * - * @return string - */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) - { - $lines = array(); - $lineCount = 0; - $lines[] = ''; - $currentLine = &$lines[$lineCount++]; - - if (0 >= $maxLineLength) { - $maxLineLength = 75; - } - - $this->_charStream->flushContents(); - $this->_charStream->importString($string); - - $thisLineLength = $maxLineLength - $firstLineOffset; - - while (false !== $char = $this->_charStream->read(4)) { - $encodedChar = rawurlencode($char); - if (0 != strlen($currentLine) - && strlen($currentLine.$encodedChar) > $thisLineLength) { - $lines[] = ''; - $currentLine = &$lines[$lineCount++]; - $thisLineLength = $maxLineLength; - } - $currentLine .= $encodedChar; - } - - return implode("\r\n", $lines); - } - - /** - * Updates the charset used. - * - * @param string $charset - */ - public function charsetChanged($charset) - { - $this->_charStream->setCharacterSet($charset); - } - - /** - * Make a deep copy of object. - */ - public function __clone() - { - $this->_charStream = clone $this->_charStream; - } -} diff --git a/tools/swift/classes/Swift/Encoding.php b/tools/swift/classes/Swift/Encoding.php deleted file mode 100644 index 245878706..000000000 --- a/tools/swift/classes/Swift/Encoding.php +++ /dev/null @@ -1,62 +0,0 @@ -lookup($key); - } -} diff --git a/tools/swift/classes/Swift/Events/CommandEvent.php b/tools/swift/classes/Swift/Events/CommandEvent.php deleted file mode 100644 index 674e6b5e4..000000000 --- a/tools/swift/classes/Swift/Events/CommandEvent.php +++ /dev/null @@ -1,65 +0,0 @@ -_command = $command; - $this->_successCodes = $successCodes; - } - - /** - * Get the command which was sent to the server. - * - * @return string - */ - public function getCommand() - { - return $this->_command; - } - - /** - * Get the numeric response codes which indicate success for this command. - * - * @return int[] - */ - public function getSuccessCodes() - { - return $this->_successCodes; - } -} diff --git a/tools/swift/classes/Swift/Events/CommandListener.php b/tools/swift/classes/Swift/Events/CommandListener.php deleted file mode 100644 index 7545404e7..000000000 --- a/tools/swift/classes/Swift/Events/CommandListener.php +++ /dev/null @@ -1,24 +0,0 @@ -_source = $source; - } - - /** - * Get the source object of this event. - * - * @return object - */ - public function getSource() - { - return $this->_source; - } - - /** - * Prevent this Event from bubbling any further up the stack. - * - * @param bool $cancel, optional - */ - public function cancelBubble($cancel = true) - { - $this->_bubbleCancelled = $cancel; - } - - /** - * Returns true if this Event will not bubble any further up the stack. - * - * @return bool - */ - public function bubbleCancelled() - { - return $this->_bubbleCancelled; - } -} diff --git a/tools/swift/classes/Swift/Events/ResponseEvent.php b/tools/swift/classes/Swift/Events/ResponseEvent.php deleted file mode 100644 index 2e92ba940..000000000 --- a/tools/swift/classes/Swift/Events/ResponseEvent.php +++ /dev/null @@ -1,65 +0,0 @@ -_response = $response; - $this->_valid = $valid; - } - - /** - * Get the response which was received from the server. - * - * @return string - */ - public function getResponse() - { - return $this->_response; - } - - /** - * Get the success status of this Event. - * - * @return bool - */ - public function isValid() - { - return $this->_valid; - } -} diff --git a/tools/swift/classes/Swift/Events/ResponseListener.php b/tools/swift/classes/Swift/Events/ResponseListener.php deleted file mode 100644 index c40919d21..000000000 --- a/tools/swift/classes/Swift/Events/ResponseListener.php +++ /dev/null @@ -1,24 +0,0 @@ -_message = $message; - $this->_result = self::RESULT_PENDING; - } - - /** - * Get the Transport used to send the Message. - * - * @return Swift_Transport - */ - public function getTransport() - { - return $this->getSource(); - } - - /** - * Get the Message being sent. - * - * @return Swift_Mime_Message - */ - public function getMessage() - { - return $this->_message; - } - - /** - * Set the array of addresses that failed in sending. - * - * @param array $recipients - */ - public function setFailedRecipients($recipients) - { - $this->_failedRecipients = $recipients; - } - - /** - * Get an recipient addresses which were not accepted for delivery. - * - * @return string[] - */ - public function getFailedRecipients() - { - return $this->_failedRecipients; - } - - /** - * Set the result of sending. - * - * @param int $result - */ - public function setResult($result) - { - $this->_result = $result; - } - - /** - * Get the result of this Event. - * - * The return value is a bitmask from - * {@see RESULT_PENDING, RESULT_SUCCESS, RESULT_TENTATIVE, RESULT_FAILED} - * - * @return int - */ - public function getResult() - { - return $this->_result; - } -} diff --git a/tools/swift/classes/Swift/Events/SendListener.php b/tools/swift/classes/Swift/Events/SendListener.php deleted file mode 100644 index d922e1bfa..000000000 --- a/tools/swift/classes/Swift/Events/SendListener.php +++ /dev/null @@ -1,31 +0,0 @@ -_eventMap = array( - 'Swift_Events_CommandEvent' => 'Swift_Events_CommandListener', - 'Swift_Events_ResponseEvent' => 'Swift_Events_ResponseListener', - 'Swift_Events_SendEvent' => 'Swift_Events_SendListener', - 'Swift_Events_TransportChangeEvent' => 'Swift_Events_TransportChangeListener', - 'Swift_Events_TransportExceptionEvent' => 'Swift_Events_TransportExceptionListener', - ); - } - - /** - * Create a new SendEvent for $source and $message. - * - * @param Swift_Transport $source - * @param Swift_Mime_Message - * - * @return Swift_Events_SendEvent - */ - public function createSendEvent(Swift_Transport $source, Swift_Mime_Message $message) - { - return new Swift_Events_SendEvent($source, $message); - } - - /** - * Create a new CommandEvent for $source and $command. - * - * @param Swift_Transport $source - * @param string $command That will be executed - * @param array $successCodes That are needed - * - * @return Swift_Events_CommandEvent - */ - public function createCommandEvent(Swift_Transport $source, $command, $successCodes = array()) - { - return new Swift_Events_CommandEvent($source, $command, $successCodes); - } - - /** - * Create a new ResponseEvent for $source and $response. - * - * @param Swift_Transport $source - * @param string $response - * @param bool $valid If the response is valid - * - * @return Swift_Events_ResponseEvent - */ - public function createResponseEvent(Swift_Transport $source, $response, $valid) - { - return new Swift_Events_ResponseEvent($source, $response, $valid); - } - - /** - * Create a new TransportChangeEvent for $source. - * - * @param Swift_Transport $source - * - * @return Swift_Events_TransportChangeEvent - */ - public function createTransportChangeEvent(Swift_Transport $source) - { - return new Swift_Events_TransportChangeEvent($source); - } - - /** - * Create a new TransportExceptionEvent for $source. - * - * @param Swift_Transport $source - * @param Swift_TransportException $ex - * - * @return Swift_Events_TransportExceptionEvent - */ - public function createTransportExceptionEvent(Swift_Transport $source, Swift_TransportException $ex) - { - return new Swift_Events_TransportExceptionEvent($source, $ex); - } - - /** - * Bind an event listener to this dispatcher. - * - * @param Swift_Events_EventListener $listener - */ - public function bindEventListener(Swift_Events_EventListener $listener) - { - foreach ($this->_listeners as $l) { - // Already loaded - if ($l === $listener) { - return; - } - } - $this->_listeners[] = $listener; - } - - /** - * Dispatch the given Event to all suitable listeners. - * - * @param Swift_Events_EventObject $evt - * @param string $target method - */ - public function dispatchEvent(Swift_Events_EventObject $evt, $target) - { - $this->_prepareBubbleQueue($evt); - $this->_bubble($evt, $target); - } - - /** Queue listeners on a stack ready for $evt to be bubbled up it */ - private function _prepareBubbleQueue(Swift_Events_EventObject $evt) - { - $this->_bubbleQueue = array(); - $evtClass = get_class($evt); - foreach ($this->_listeners as $listener) { - if (array_key_exists($evtClass, $this->_eventMap) - && ($listener instanceof $this->_eventMap[$evtClass])) { - $this->_bubbleQueue[] = $listener; - } - } - } - - /** Bubble $evt up the stack calling $target() on each listener */ - private function _bubble(Swift_Events_EventObject $evt, $target) - { - if (!$evt->bubbleCancelled() && $listener = array_shift($this->_bubbleQueue)) { - $listener->$target($evt); - $this->_bubble($evt, $target); - } - } -} diff --git a/tools/swift/classes/Swift/Events/TransportChangeEvent.php b/tools/swift/classes/Swift/Events/TransportChangeEvent.php deleted file mode 100644 index a8972fda9..000000000 --- a/tools/swift/classes/Swift/Events/TransportChangeEvent.php +++ /dev/null @@ -1,27 +0,0 @@ -getSource(); - } -} diff --git a/tools/swift/classes/Swift/Events/TransportChangeListener.php b/tools/swift/classes/Swift/Events/TransportChangeListener.php deleted file mode 100644 index 253165de8..000000000 --- a/tools/swift/classes/Swift/Events/TransportChangeListener.php +++ /dev/null @@ -1,45 +0,0 @@ -_exception = $ex; - } - - /** - * Get the TransportException thrown. - * - * @return Swift_TransportException - */ - public function getException() - { - return $this->_exception; - } -} diff --git a/tools/swift/classes/Swift/Events/TransportExceptionListener.php b/tools/swift/classes/Swift/Events/TransportExceptionListener.php deleted file mode 100644 index cc3c09937..000000000 --- a/tools/swift/classes/Swift/Events/TransportExceptionListener.php +++ /dev/null @@ -1,24 +0,0 @@ -createDependenciesFor('transport.failover') - ); - - $this->setTransports($transports); - } - - /** - * Create a new FailoverTransport instance. - * - * @param Swift_Transport[] $transports - * - * @return self - */ - public static function newInstance($transports = array()) - { - return new self($transports); - } -} diff --git a/tools/swift/classes/Swift/FileSpool.php b/tools/swift/classes/Swift/FileSpool.php deleted file mode 100644 index c82c5dbf1..000000000 --- a/tools/swift/classes/Swift/FileSpool.php +++ /dev/null @@ -1,208 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Stores Messages on the filesystem. - * - * @author Fabien Potencier - * @author Xavier De Cock - */ -class Swift_FileSpool extends Swift_ConfigurableSpool -{ - /** The spool directory */ - private $_path; - - /** - * File WriteRetry Limit. - * - * @var int - */ - private $_retryLimit = 10; - - /** - * Create a new FileSpool. - * - * @param string $path - * - * @throws Swift_IoException - */ - public function __construct($path) - { - $this->_path = $path; - - if (!file_exists($this->_path)) { - if (!mkdir($this->_path, 0777, true)) { - throw new Swift_IoException(sprintf('Unable to create path "%s".', $this->_path)); - } - } - } - - /** - * Tests if this Spool mechanism has started. - * - * @return bool - */ - public function isStarted() - { - return true; - } - - /** - * Starts this Spool mechanism. - */ - public function start() - { - } - - /** - * Stops this Spool mechanism. - */ - public function stop() - { - } - - /** - * Allow to manage the enqueuing retry limit. - * - * Default, is ten and allows over 64^20 different fileNames - * - * @param int $limit - */ - public function setRetryLimit($limit) - { - $this->_retryLimit = $limit; - } - - /** - * Queues a message. - * - * @param Swift_Mime_Message $message The message to store - * - * @throws Swift_IoException - * - * @return bool - */ - public function queueMessage(Swift_Mime_Message $message) - { - $ser = serialize($message); - $fileName = $this->_path.'/'.$this->getRandomString(10); - for ($i = 0; $i < $this->_retryLimit; ++$i) { - /* We try an exclusive creation of the file. This is an atomic operation, it avoid locking mechanism */ - $fp = @fopen($fileName.'.message', 'x'); - if (false !== $fp) { - if (false === fwrite($fp, $ser)) { - return false; - } - - return fclose($fp); - } else { - /* The file already exists, we try a longer fileName */ - $fileName .= $this->getRandomString(1); - } - } - - throw new Swift_IoException(sprintf('Unable to create a file for enqueuing Message in "%s".', $this->_path)); - } - - /** - * Execute a recovery if for any reason a process is sending for too long. - * - * @param int $timeout in second Defaults is for very slow smtp responses - */ - public function recover($timeout = 900) - { - foreach (new DirectoryIterator($this->_path) as $file) { - $file = $file->getRealPath(); - - if (substr($file, -16) == '.message.sending') { - $lockedtime = filectime($file); - if ((time() - $lockedtime) > $timeout) { - rename($file, substr($file, 0, -8)); - } - } - } - } - - /** - * Sends messages using the given transport instance. - * - * @param Swift_Transport $transport A transport instance - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int The number of sent e-mail's - */ - public function flushQueue(Swift_Transport $transport, &$failedRecipients = null) - { - $directoryIterator = new DirectoryIterator($this->_path); - - /* Start the transport only if there are queued files to send */ - if (!$transport->isStarted()) { - foreach ($directoryIterator as $file) { - if (substr($file->getRealPath(), -8) == '.message') { - $transport->start(); - break; - } - } - } - - $failedRecipients = (array) $failedRecipients; - $count = 0; - $time = time(); - foreach ($directoryIterator as $file) { - $file = $file->getRealPath(); - - if (substr($file, -8) != '.message') { - continue; - } - - /* We try a rename, it's an atomic operation, and avoid locking the file */ - if (rename($file, $file.'.sending')) { - $message = unserialize(file_get_contents($file.'.sending')); - - $count += $transport->send($message, $failedRecipients); - - unlink($file.'.sending'); - } else { - /* This message has just been catched by another process */ - continue; - } - - if ($this->getMessageLimit() && $count >= $this->getMessageLimit()) { - break; - } - - if ($this->getTimeLimit() && (time() - $time) >= $this->getTimeLimit()) { - break; - } - } - - return $count; - } - - /** - * Returns a random string needed to generate a fileName for the queue. - * - * @param int $count - * - * @return string - */ - protected function getRandomString($count) - { - // This string MUST stay FS safe, avoid special chars - $base = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-'; - $ret = ''; - $strlen = strlen($base); - for ($i = 0; $i < $count; ++$i) { - $ret .= $base[((int) rand(0, $strlen - 1))]; - } - - return $ret; - } -} diff --git a/tools/swift/classes/Swift/FileStream.php b/tools/swift/classes/Swift/FileStream.php deleted file mode 100644 index 0b24db1ce..000000000 --- a/tools/swift/classes/Swift/FileStream.php +++ /dev/null @@ -1,24 +0,0 @@ -setFile(new Swift_ByteStream_FileByteStream($path)); - } -} diff --git a/tools/swift/classes/Swift/InputByteStream.php b/tools/swift/classes/Swift/InputByteStream.php deleted file mode 100644 index 56efc7593..000000000 --- a/tools/swift/classes/Swift/InputByteStream.php +++ /dev/null @@ -1,75 +0,0 @@ -_stream = $stream; - } - - /** - * Set a string into the cache under $itemKey for the namespace $nsKey. - * - * @see MODE_WRITE, MODE_APPEND - * - * @param string $nsKey - * @param string $itemKey - * @param string $string - * @param int $mode - */ - public function setString($nsKey, $itemKey, $string, $mode) - { - $this->_prepareCache($nsKey); - switch ($mode) { - case self::MODE_WRITE: - $this->_contents[$nsKey][$itemKey] = $string; - break; - case self::MODE_APPEND: - if (!$this->hasKey($nsKey, $itemKey)) { - $this->_contents[$nsKey][$itemKey] = ''; - } - $this->_contents[$nsKey][$itemKey] .= $string; - break; - default: - throw new Swift_SwiftException( - 'Invalid mode ['.$mode.'] used to set nsKey='. - $nsKey.', itemKey='.$itemKey - ); - } - } - - /** - * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. - * - * @see MODE_WRITE, MODE_APPEND - * - * @param string $nsKey - * @param string $itemKey - * @param Swift_OutputByteStream $os - * @param int $mode - */ - public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode) - { - $this->_prepareCache($nsKey); - switch ($mode) { - case self::MODE_WRITE: - $this->clearKey($nsKey, $itemKey); - case self::MODE_APPEND: - if (!$this->hasKey($nsKey, $itemKey)) { - $this->_contents[$nsKey][$itemKey] = ''; - } - while (false !== $bytes = $os->read(8192)) { - $this->_contents[$nsKey][$itemKey] .= $bytes; - } - break; - default: - throw new Swift_SwiftException( - 'Invalid mode ['.$mode.'] used to set nsKey='. - $nsKey.', itemKey='.$itemKey - ); - } - } - - /** - * Provides a ByteStream which when written to, writes data to $itemKey. - * - * NOTE: The stream will always write in append mode. - * - * @param string $nsKey - * @param string $itemKey - * @param Swift_InputByteStream $writeThrough - * - * @return Swift_InputByteStream - */ - public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) - { - $is = clone $this->_stream; - $is->setKeyCache($this); - $is->setNsKey($nsKey); - $is->setItemKey($itemKey); - if (isset($writeThrough)) { - $is->setWriteThroughStream($writeThrough); - } - - return $is; - } - - /** - * Get data back out of the cache as a string. - * - * @param string $nsKey - * @param string $itemKey - * - * @return string - */ - public function getString($nsKey, $itemKey) - { - $this->_prepareCache($nsKey); - if ($this->hasKey($nsKey, $itemKey)) { - return $this->_contents[$nsKey][$itemKey]; - } - } - - /** - * Get data back out of the cache as a ByteStream. - * - * @param string $nsKey - * @param string $itemKey - * @param Swift_InputByteStream $is to write the data to - */ - public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is) - { - $this->_prepareCache($nsKey); - $is->write($this->getString($nsKey, $itemKey)); - } - - /** - * Check if the given $itemKey exists in the namespace $nsKey. - * - * @param string $nsKey - * @param string $itemKey - * - * @return bool - */ - public function hasKey($nsKey, $itemKey) - { - $this->_prepareCache($nsKey); - - return array_key_exists($itemKey, $this->_contents[$nsKey]); - } - - /** - * Clear data for $itemKey in the namespace $nsKey if it exists. - * - * @param string $nsKey - * @param string $itemKey - */ - public function clearKey($nsKey, $itemKey) - { - unset($this->_contents[$nsKey][$itemKey]); - } - - /** - * Clear all data in the namespace $nsKey if it exists. - * - * @param string $nsKey - */ - public function clearAll($nsKey) - { - unset($this->_contents[$nsKey]); - } - - /** - * Initialize the namespace of $nsKey if needed. - * - * @param string $nsKey - */ - private function _prepareCache($nsKey) - { - if (!array_key_exists($nsKey, $this->_contents)) { - $this->_contents[$nsKey] = array(); - } - } -} diff --git a/tools/swift/classes/Swift/KeyCache/DiskKeyCache.php b/tools/swift/classes/Swift/KeyCache/DiskKeyCache.php deleted file mode 100644 index 453f50a15..000000000 --- a/tools/swift/classes/Swift/KeyCache/DiskKeyCache.php +++ /dev/null @@ -1,321 +0,0 @@ -_stream = $stream; - $this->_path = $path; - - if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) { - $this->_quotes = true; - } - } - - /** - * Set a string into the cache under $itemKey for the namespace $nsKey. - * - * @see MODE_WRITE, MODE_APPEND - * - * @param string $nsKey - * @param string $itemKey - * @param string $string - * @param int $mode - * - * @throws Swift_IoException - */ - public function setString($nsKey, $itemKey, $string, $mode) - { - $this->_prepareCache($nsKey); - switch ($mode) { - case self::MODE_WRITE: - $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); - break; - case self::MODE_APPEND: - $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_END); - break; - default: - throw new Swift_SwiftException( - 'Invalid mode ['.$mode.'] used to set nsKey='. - $nsKey.', itemKey='.$itemKey - ); - break; - } - fwrite($fp, $string); - $this->_freeHandle($nsKey, $itemKey); - } - - /** - * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. - * - * @see MODE_WRITE, MODE_APPEND - * - * @param string $nsKey - * @param string $itemKey - * @param Swift_OutputByteStream $os - * @param int $mode - * - * @throws Swift_IoException - */ - public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode) - { - $this->_prepareCache($nsKey); - switch ($mode) { - case self::MODE_WRITE: - $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); - break; - case self::MODE_APPEND: - $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_END); - break; - default: - throw new Swift_SwiftException( - 'Invalid mode ['.$mode.'] used to set nsKey='. - $nsKey.', itemKey='.$itemKey - ); - break; - } - while (false !== $bytes = $os->read(8192)) { - fwrite($fp, $bytes); - } - $this->_freeHandle($nsKey, $itemKey); - } - - /** - * Provides a ByteStream which when written to, writes data to $itemKey. - * - * NOTE: The stream will always write in append mode. - * - * @param string $nsKey - * @param string $itemKey - * @param Swift_InputByteStream $writeThrough - * - * @return Swift_InputByteStream - */ - public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) - { - $is = clone $this->_stream; - $is->setKeyCache($this); - $is->setNsKey($nsKey); - $is->setItemKey($itemKey); - if (isset($writeThrough)) { - $is->setWriteThroughStream($writeThrough); - } - - return $is; - } - - /** - * Get data back out of the cache as a string. - * - * @param string $nsKey - * @param string $itemKey - * - * @throws Swift_IoException - * - * @return string - */ - public function getString($nsKey, $itemKey) - { - $this->_prepareCache($nsKey); - if ($this->hasKey($nsKey, $itemKey)) { - $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); - if ($this->_quotes) { - ini_set('magic_quotes_runtime', 0); - } - $str = ''; - while (!feof($fp) && false !== $bytes = fread($fp, 8192)) { - $str .= $bytes; - } - if ($this->_quotes) { - ini_set('magic_quotes_runtime', 1); - } - $this->_freeHandle($nsKey, $itemKey); - - return $str; - } - } - - /** - * Get data back out of the cache as a ByteStream. - * - * @param string $nsKey - * @param string $itemKey - * @param Swift_InputByteStream $is to write the data to - */ - public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is) - { - if ($this->hasKey($nsKey, $itemKey)) { - $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); - if ($this->_quotes) { - ini_set('magic_quotes_runtime', 0); - } - while (!feof($fp) && false !== $bytes = fread($fp, 8192)) { - $is->write($bytes); - } - if ($this->_quotes) { - ini_set('magic_quotes_runtime', 1); - } - $this->_freeHandle($nsKey, $itemKey); - } - } - - /** - * Check if the given $itemKey exists in the namespace $nsKey. - * - * @param string $nsKey - * @param string $itemKey - * - * @return bool - */ - public function hasKey($nsKey, $itemKey) - { - return is_file($this->_path.'/'.$nsKey.'/'.$itemKey); - } - - /** - * Clear data for $itemKey in the namespace $nsKey if it exists. - * - * @param string $nsKey - * @param string $itemKey - */ - public function clearKey($nsKey, $itemKey) - { - if ($this->hasKey($nsKey, $itemKey)) { - $this->_freeHandle($nsKey, $itemKey); - unlink($this->_path.'/'.$nsKey.'/'.$itemKey); - } - } - - /** - * Clear all data in the namespace $nsKey if it exists. - * - * @param string $nsKey - */ - public function clearAll($nsKey) - { - if (array_key_exists($nsKey, $this->_keys)) { - foreach ($this->_keys[$nsKey] as $itemKey => $null) { - $this->clearKey($nsKey, $itemKey); - } - if (is_dir($this->_path.'/'.$nsKey)) { - rmdir($this->_path.'/'.$nsKey); - } - unset($this->_keys[$nsKey]); - } - } - - /** - * Initialize the namespace of $nsKey if needed. - * - * @param string $nsKey - */ - private function _prepareCache($nsKey) - { - $cacheDir = $this->_path.'/'.$nsKey; - if (!is_dir($cacheDir)) { - if (!mkdir($cacheDir)) { - throw new Swift_IoException('Failed to create cache directory '.$cacheDir); - } - $this->_keys[$nsKey] = array(); - } - } - - /** - * Get a file handle on the cache item. - * - * @param string $nsKey - * @param string $itemKey - * @param int $position - * - * @return resource - */ - private function _getHandle($nsKey, $itemKey, $position) - { - if (!isset($this->_keys[$nsKey][$itemKey])) { - $openMode = $this->hasKey($nsKey, $itemKey) ? 'r+b' : 'w+b'; - $fp = fopen($this->_path.'/'.$nsKey.'/'.$itemKey, $openMode); - $this->_keys[$nsKey][$itemKey] = $fp; - } - if (self::POSITION_START == $position) { - fseek($this->_keys[$nsKey][$itemKey], 0, SEEK_SET); - } elseif (self::POSITION_END == $position) { - fseek($this->_keys[$nsKey][$itemKey], 0, SEEK_END); - } - - return $this->_keys[$nsKey][$itemKey]; - } - - private function _freeHandle($nsKey, $itemKey) - { - $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_CURRENT); - fclose($fp); - $this->_keys[$nsKey][$itemKey] = null; - } - - /** - * Destructor. - */ - public function __destruct() - { - foreach ($this->_keys as $nsKey => $null) { - $this->clearAll($nsKey); - } - } -} diff --git a/tools/swift/classes/Swift/KeyCache/KeyCacheInputStream.php b/tools/swift/classes/Swift/KeyCache/KeyCacheInputStream.php deleted file mode 100644 index af80bdca6..000000000 --- a/tools/swift/classes/Swift/KeyCache/KeyCacheInputStream.php +++ /dev/null @@ -1,51 +0,0 @@ -_keyCache = $keyCache; - } - - /** - * Specify a stream to write through for each write(). - * - * @param Swift_InputByteStream $is - */ - public function setWriteThroughStream(Swift_InputByteStream $is) - { - $this->_writeThrough = $is; - } - - /** - * Writes $bytes to the end of the stream. - * - * @param string $bytes - * @param Swift_InputByteStream $is optional - */ - public function write($bytes, Swift_InputByteStream $is = null) - { - $this->_keyCache->setString( - $this->_nsKey, $this->_itemKey, $bytes, Swift_KeyCache::MODE_APPEND - ); - if (isset($is)) { - $is->write($bytes); - } - if (isset($this->_writeThrough)) { - $this->_writeThrough->write($bytes); - } - } - - /** - * Not used. - */ - public function commit() - { - } - - /** - * Not used. - */ - public function bind(Swift_InputByteStream $is) - { - } - - /** - * Not used. - */ - public function unbind(Swift_InputByteStream $is) - { - } - - /** - * Flush the contents of the stream (empty it) and set the internal pointer - * to the beginning. - */ - public function flushBuffers() - { - $this->_keyCache->clearKey($this->_nsKey, $this->_itemKey); - } - - /** - * Set the nsKey which will be written to. - * - * @param string $nsKey - */ - public function setNsKey($nsKey) - { - $this->_nsKey = $nsKey; - } - - /** - * Set the itemKey which will be written to. - * - * @param string $itemKey - */ - public function setItemKey($itemKey) - { - $this->_itemKey = $itemKey; - } - - /** - * Any implementation should be cloneable, allowing the clone to access a - * separate $nsKey and $itemKey. - */ - public function __clone() - { - $this->_writeThrough = null; - } -} diff --git a/tools/swift/classes/Swift/LoadBalancedTransport.php b/tools/swift/classes/Swift/LoadBalancedTransport.php deleted file mode 100644 index e151b8a9c..000000000 --- a/tools/swift/classes/Swift/LoadBalancedTransport.php +++ /dev/null @@ -1,45 +0,0 @@ -createDependenciesFor('transport.loadbalanced') - ); - - $this->setTransports($transports); - } - - /** - * Create a new LoadBalancedTransport instance. - * - * @param array $transports - * - * @return self - */ - public static function newInstance($transports = array()) - { - return new self($transports); - } -} diff --git a/tools/swift/classes/Swift/MailTransport.php b/tools/swift/classes/Swift/MailTransport.php deleted file mode 100644 index 18556989a..000000000 --- a/tools/swift/classes/Swift/MailTransport.php +++ /dev/null @@ -1,47 +0,0 @@ -createDependenciesFor('transport.mail') - ); - - $this->setExtraParams($extraParams); - } - - /** - * Create a new MailTransport instance. - * - * @param string $extraParams To be passed to mail() - * - * @return self - */ - public static function newInstance($extraParams = '-f%s') - { - return new self($extraParams); - } -} diff --git a/tools/swift/classes/Swift/Mailer.php b/tools/swift/classes/Swift/Mailer.php deleted file mode 100644 index 8314fe8fc..000000000 --- a/tools/swift/classes/Swift/Mailer.php +++ /dev/null @@ -1,114 +0,0 @@ -_transport = $transport; - } - - /** - * Create a new Mailer instance. - * - * @param Swift_Transport $transport - * - * @return self - */ - public static function newInstance(Swift_Transport $transport) - { - return new self($transport); - } - - /** - * Create a new class instance of one of the message services. - * - * For example 'mimepart' would create a 'message.mimepart' instance - * - * @param string $service - * - * @return object - */ - public function createMessage($service = 'message') - { - return Swift_DependencyContainer::getInstance() - ->lookup('message.'.$service); - } - - /** - * Send the given Message like it would be sent in a mail client. - * - * All recipients (with the exception of Bcc) will be able to see the other - * recipients this message was sent to. - * - * Recipient/sender data will be retrieved from the Message object. - * - * The return value is the number of recipients who were accepted for - * delivery. - * - * @param Swift_Mime_Message $message - * @param array $failedRecipients An array of failures by-reference - * - * @return int The number of successful recipients. Can be 0 which indicates failure - */ - public function send(Swift_Mime_Message $message, &$failedRecipients = null) - { - $failedRecipients = (array) $failedRecipients; - - if (!$this->_transport->isStarted()) { - $this->_transport->start(); - } - - $sent = 0; - - try { - $sent = $this->_transport->send($message, $failedRecipients); - } catch (Swift_RfcComplianceException $e) { - foreach ($message->getTo() as $address => $name) { - $failedRecipients[] = $address; - } - } - - return $sent; - } - - /** - * Register a plugin using a known unique key (e.g. myPlugin). - * - * @param Swift_Events_EventListener $plugin - */ - public function registerPlugin(Swift_Events_EventListener $plugin) - { - $this->_transport->registerPlugin($plugin); - } - - /** - * The Transport used to send messages. - * - * @return Swift_Transport - */ - public function getTransport() - { - return $this->_transport; - } -} diff --git a/tools/swift/classes/Swift/Mailer/ArrayRecipientIterator.php b/tools/swift/classes/Swift/Mailer/ArrayRecipientIterator.php deleted file mode 100644 index e3e6cad05..000000000 --- a/tools/swift/classes/Swift/Mailer/ArrayRecipientIterator.php +++ /dev/null @@ -1,55 +0,0 @@ -_recipients = $recipients; - } - - /** - * Returns true only if there are more recipients to send to. - * - * @return bool - */ - public function hasNext() - { - return !empty($this->_recipients); - } - - /** - * Returns an array where the keys are the addresses of recipients and the - * values are the names. e.g. ('foo@bar' => 'Foo') or ('foo@bar' => NULL). - * - * @return array - */ - public function nextRecipient() - { - return array_splice($this->_recipients, 0, 1); - } -} diff --git a/tools/swift/classes/Swift/Mailer/RecipientIterator.php b/tools/swift/classes/Swift/Mailer/RecipientIterator.php deleted file mode 100644 index 650f3ec3d..000000000 --- a/tools/swift/classes/Swift/Mailer/RecipientIterator.php +++ /dev/null @@ -1,32 +0,0 @@ - 'Foo') or ('foo@bar' => NULL). - * - * @return array - */ - public function nextRecipient(); -} diff --git a/tools/swift/classes/Swift/MemorySpool.php b/tools/swift/classes/Swift/MemorySpool.php deleted file mode 100644 index 2cafb6751..000000000 --- a/tools/swift/classes/Swift/MemorySpool.php +++ /dev/null @@ -1,110 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Stores Messages in memory. - * - * @author Fabien Potencier - */ -class Swift_MemorySpool implements Swift_Spool -{ - protected $messages = array(); - private $flushRetries = 3; - - /** - * Tests if this Transport mechanism has started. - * - * @return bool - */ - public function isStarted() - { - return true; - } - - /** - * Starts this Transport mechanism. - */ - public function start() - { - } - - /** - * Stops this Transport mechanism. - */ - public function stop() - { - } - - /** - * @param int $retries - */ - public function setFlushRetries($retries) - { - $this->flushRetries = $retries; - } - - /** - * Stores a message in the queue. - * - * @param Swift_Mime_Message $message The message to store - * - * @return bool Whether the operation has succeeded - */ - public function queueMessage(Swift_Mime_Message $message) - { - //clone the message to make sure it is not changed while in the queue - $this->messages[] = clone $message; - - return true; - } - - /** - * Sends messages using the given transport instance. - * - * @param Swift_Transport $transport A transport instance - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int The number of sent emails - */ - public function flushQueue(Swift_Transport $transport, &$failedRecipients = null) - { - if (!$this->messages) { - return 0; - } - - if (!$transport->isStarted()) { - $transport->start(); - } - - $count = 0; - $retries = $this->flushRetries; - while ($retries--) { - try { - while ($message = array_pop($this->messages)) { - $count += $transport->send($message, $failedRecipients); - } - } catch (Swift_TransportException $exception) { - if ($retries) { - // re-queue the message at the end of the queue to give a chance - // to the other messages to be sent, in case the failure was due to - // this message and not just the transport failing - array_unshift($this->messages, $message); - - // wait half a second before we try again - usleep(500000); - } else { - throw $exception; - } - } - } - - return $count; - } -} diff --git a/tools/swift/classes/Swift/Message.php b/tools/swift/classes/Swift/Message.php deleted file mode 100644 index 242cbf314..000000000 --- a/tools/swift/classes/Swift/Message.php +++ /dev/null @@ -1,289 +0,0 @@ -createDependenciesFor('mime.message') - ); - - if (!isset($charset)) { - $charset = Swift_DependencyContainer::getInstance() - ->lookup('properties.charset'); - } - $this->setSubject($subject); - $this->setBody($body); - $this->setCharset($charset); - if ($contentType) { - $this->setContentType($contentType); - } - } - - /** - * Create a new Message. - * - * @param string $subject - * @param string $body - * @param string $contentType - * @param string $charset - * - * @return $this - */ - public static function newInstance($subject = null, $body = null, $contentType = null, $charset = null) - { - return new self($subject, $body, $contentType, $charset); - } - - /** - * Add a MimePart to this Message. - * - * @param string|Swift_OutputByteStream $body - * @param string $contentType - * @param string $charset - * - * @return $this - */ - public function addPart($body, $contentType = null, $charset = null) - { - return $this->attach(Swift_MimePart::newInstance($body, $contentType, $charset)->setEncoder($this->getEncoder())); - } - - /** - * Detach a signature handler from a message. - * - * @param Swift_Signer $signer - * - * @return $this - */ - public function attachSigner(Swift_Signer $signer) - { - if ($signer instanceof Swift_Signers_HeaderSigner) { - $this->headerSigners[] = $signer; - } elseif ($signer instanceof Swift_Signers_BodySigner) { - $this->bodySigners[] = $signer; - } - - return $this; - } - - /** - * Attach a new signature handler to the message. - * - * @param Swift_Signer $signer - * - * @return $this - */ - public function detachSigner(Swift_Signer $signer) - { - if ($signer instanceof Swift_Signers_HeaderSigner) { - foreach ($this->headerSigners as $k => $headerSigner) { - if ($headerSigner === $signer) { - unset($this->headerSigners[$k]); - - return $this; - } - } - } elseif ($signer instanceof Swift_Signers_BodySigner) { - foreach ($this->bodySigners as $k => $bodySigner) { - if ($bodySigner === $signer) { - unset($this->bodySigners[$k]); - - return $this; - } - } - } - - return $this; - } - - /** - * Get this message as a complete string. - * - * @return string - */ - public function toString() - { - if (empty($this->headerSigners) && empty($this->bodySigners)) { - return parent::toString(); - } - - $this->saveMessage(); - - $this->doSign(); - - $string = parent::toString(); - - $this->restoreMessage(); - - return $string; - } - - /** - * Write this message to a {@link Swift_InputByteStream}. - * - * @param Swift_InputByteStream $is - */ - public function toByteStream(Swift_InputByteStream $is) - { - if (empty($this->headerSigners) && empty($this->bodySigners)) { - parent::toByteStream($is); - - return; - } - - $this->saveMessage(); - - $this->doSign(); - - parent::toByteStream($is); - - $this->restoreMessage(); - } - - public function __wakeup() - { - Swift_DependencyContainer::getInstance()->createDependenciesFor('mime.message'); - } - - /** - * loops through signers and apply the signatures. - */ - protected function doSign() - { - foreach ($this->bodySigners as $signer) { - $altered = $signer->getAlteredHeaders(); - $this->saveHeaders($altered); - $signer->signMessage($this); - } - - foreach ($this->headerSigners as $signer) { - $altered = $signer->getAlteredHeaders(); - $this->saveHeaders($altered); - $signer->reset(); - - $signer->setHeaders($this->getHeaders()); - - $signer->startBody(); - $this->_bodyToByteStream($signer); - $signer->endBody(); - - $signer->addSignature($this->getHeaders()); - } - } - - /** - * save the message before any signature is applied. - */ - protected function saveMessage() - { - $this->savedMessage = array('headers' => array()); - $this->savedMessage['body'] = $this->getBody(); - $this->savedMessage['children'] = $this->getChildren(); - if (count($this->savedMessage['children']) > 0 && $this->getBody() != '') { - $this->setChildren(array_merge(array($this->_becomeMimePart()), $this->savedMessage['children'])); - $this->setBody(''); - } - } - - /** - * save the original headers. - * - * @param array $altered - */ - protected function saveHeaders(array $altered) - { - foreach ($altered as $head) { - $lc = strtolower($head); - - if (!isset($this->savedMessage['headers'][$lc])) { - $this->savedMessage['headers'][$lc] = $this->getHeaders()->getAll($head); - } - } - } - - /** - * Remove or restore altered headers. - */ - protected function restoreHeaders() - { - foreach ($this->savedMessage['headers'] as $name => $savedValue) { - $headers = $this->getHeaders()->getAll($name); - - foreach ($headers as $key => $value) { - if (!isset($savedValue[$key])) { - $this->getHeaders()->remove($name, $key); - } - } - } - } - - /** - * Restore message body. - */ - protected function restoreMessage() - { - $this->setBody($this->savedMessage['body']); - $this->setChildren($this->savedMessage['children']); - - $this->restoreHeaders(); - $this->savedMessage = array(); - } - - /** - * Clone Message Signers. - * - * @see Swift_Mime_SimpleMimeEntity::__clone() - */ - public function __clone() - { - parent::__clone(); - foreach ($this->bodySigners as $key => $bodySigner) { - $this->bodySigners[$key] = clone $bodySigner; - } - - foreach ($this->headerSigners as $key => $headerSigner) { - $this->headerSigners[$key] = clone $headerSigner; - } - } -} diff --git a/tools/swift/classes/Swift/Mime/Attachment.php b/tools/swift/classes/Swift/Mime/Attachment.php deleted file mode 100644 index d5ba14b91..000000000 --- a/tools/swift/classes/Swift/Mime/Attachment.php +++ /dev/null @@ -1,149 +0,0 @@ -setDisposition('attachment'); - $this->setContentType('application/octet-stream'); - $this->_mimeTypes = $mimeTypes; - } - - /** - * Get the nesting level used for this attachment. - * - * Always returns {@link LEVEL_MIXED}. - * - * @return int - */ - public function getNestingLevel() - { - return self::LEVEL_MIXED; - } - - /** - * Get the Content-Disposition of this attachment. - * - * By default attachments have a disposition of "attachment". - * - * @return string - */ - public function getDisposition() - { - return $this->_getHeaderFieldModel('Content-Disposition'); - } - - /** - * Set the Content-Disposition of this attachment. - * - * @param string $disposition - * - * @return $this - */ - public function setDisposition($disposition) - { - if (!$this->_setHeaderFieldModel('Content-Disposition', $disposition)) { - $this->getHeaders()->addParameterizedHeader('Content-Disposition', $disposition); - } - - return $this; - } - - /** - * Get the filename of this attachment when downloaded. - * - * @return string - */ - public function getFilename() - { - return $this->_getHeaderParameter('Content-Disposition', 'filename'); - } - - /** - * Set the filename of this attachment. - * - * @param string $filename - * - * @return $this - */ - public function setFilename($filename) - { - $this->_setHeaderParameter('Content-Disposition', 'filename', $filename); - $this->_setHeaderParameter('Content-Type', 'name', $filename); - - return $this; - } - - /** - * Get the file size of this attachment. - * - * @return int - */ - public function getSize() - { - return $this->_getHeaderParameter('Content-Disposition', 'size'); - } - - /** - * Set the file size of this attachment. - * - * @param int $size - * - * @return $this - */ - public function setSize($size) - { - $this->_setHeaderParameter('Content-Disposition', 'size', $size); - - return $this; - } - - /** - * Set the file that this attachment is for. - * - * @param Swift_FileStream $file - * @param string $contentType optional - * - * @return $this - */ - public function setFile(Swift_FileStream $file, $contentType = null) - { - $this->setFilename(basename($file->getPath())); - $this->setBody($file, $contentType); - if (!isset($contentType)) { - $extension = strtolower(substr($file->getPath(), strrpos($file->getPath(), '.') + 1)); - - if (array_key_exists($extension, $this->_mimeTypes)) { - $this->setContentType($this->_mimeTypes[$extension]); - } - } - - return $this; - } -} diff --git a/tools/swift/classes/Swift/Mime/CharsetObserver.php b/tools/swift/classes/Swift/Mime/CharsetObserver.php deleted file mode 100644 index b49c3a873..000000000 --- a/tools/swift/classes/Swift/Mime/CharsetObserver.php +++ /dev/null @@ -1,24 +0,0 @@ -= $maxLineLength || 76 < $maxLineLength) { - $maxLineLength = 76; - } - - $remainder = 0; - $base64ReadBufferRemainderBytes = null; - - // To reduce memory usage, the output buffer is streamed to the input buffer like so: - // Output Stream => base64encode => wrap line length => Input Stream - // HOWEVER it's important to note that base64_encode() should only be passed whole triplets of data (except for the final chunk of data) - // otherwise it will assume the input data has *ended* and it will incorrectly pad/terminate the base64 data mid-stream. - // We use $base64ReadBufferRemainderBytes to carry over 1-2 "remainder" bytes from the each chunk from OutputStream and pre-pend those onto the - // chunk of bytes read in the next iteration. - // When the OutputStream is empty, we must flush any remainder bytes. - while (true) { - $readBytes = $os->read(8192); - $atEOF = ($readBytes === false); - - if ($atEOF) { - $streamTheseBytes = $base64ReadBufferRemainderBytes; - } else { - $streamTheseBytes = $base64ReadBufferRemainderBytes.$readBytes; - } - $base64ReadBufferRemainderBytes = null; - $bytesLength = strlen($streamTheseBytes); - - if ($bytesLength === 0) { // no data left to encode - break; - } - - // if we're not on the last block of the ouput stream, make sure $streamTheseBytes ends with a complete triplet of data - // and carry over remainder 1-2 bytes to the next loop iteration - if (!$atEOF) { - $excessBytes = $bytesLength % 3; - if ($excessBytes !== 0) { - $base64ReadBufferRemainderBytes = substr($streamTheseBytes, -$excessBytes); - $streamTheseBytes = substr($streamTheseBytes, 0, $bytesLength - $excessBytes); - } - } - - $encoded = base64_encode($streamTheseBytes); - $encodedTransformed = ''; - $thisMaxLineLength = $maxLineLength - $remainder - $firstLineOffset; - - while ($thisMaxLineLength < strlen($encoded)) { - $encodedTransformed .= substr($encoded, 0, $thisMaxLineLength)."\r\n"; - $firstLineOffset = 0; - $encoded = substr($encoded, $thisMaxLineLength); - $thisMaxLineLength = $maxLineLength; - $remainder = 0; - } - - if (0 < $remainingLength = strlen($encoded)) { - $remainder += $remainingLength; - $encodedTransformed .= $encoded; - $encoded = null; - } - - $is->write($encodedTransformed); - - if ($atEOF) { - break; - } - } - } - - /** - * Get the name of this encoding scheme. - * Returns the string 'base64'. - * - * @return string - */ - public function getName() - { - return 'base64'; - } -} diff --git a/tools/swift/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php b/tools/swift/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php deleted file mode 100644 index 710b5ac9e..000000000 --- a/tools/swift/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php +++ /dev/null @@ -1,123 +0,0 @@ -charset = $charset ? $charset : 'utf-8'; - } - - /** - * Notify this observer that the entity's charset has changed. - * - * @param string $charset - */ - public function charsetChanged($charset) - { - $this->charset = $charset; - } - - /** - * Encode $in to $out. - * - * @param Swift_OutputByteStream $os to read from - * @param Swift_InputByteStream $is to write to - * @param int $firstLineOffset - * @param int $maxLineLength 0 indicates the default length for this encoding - * - * @throws RuntimeException - */ - public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) - { - if ($this->charset !== 'utf-8') { - throw new RuntimeException( - sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset)); - } - - $string = ''; - - while (false !== $bytes = $os->read(8192)) { - $string .= $bytes; - } - - $is->write($this->encodeString($string)); - } - - /** - * Get the MIME name of this content encoding scheme. - * - * @return string - */ - public function getName() - { - return 'quoted-printable'; - } - - /** - * Encode a given string to produce an encoded string. - * - * @param string $string - * @param int $firstLineOffset if first line needs to be shorter - * @param int $maxLineLength 0 indicates the default length for this encoding - * - * @throws RuntimeException - * - * @return string - */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) - { - if ($this->charset !== 'utf-8') { - throw new RuntimeException( - sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset)); - } - - return $this->_standardize(quoted_printable_encode($string)); - } - - /** - * Make sure CRLF is correct and HT/SPACE are in valid places. - * - * @param string $string - * - * @return string - */ - protected function _standardize($string) - { - // transform CR or LF to CRLF - $string = preg_replace('~=0D(?!=0A)|(?_name = $name; - $this->_canonical = $canonical; - } - - /** - * Encode a given string to produce an encoded string. - * - * @param string $string - * @param int $firstLineOffset ignored - * @param int $maxLineLength - 0 means no wrapping will occur - * - * @return string - */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) - { - if ($this->_canonical) { - $string = $this->_canonicalize($string); - } - - return $this->_safeWordWrap($string, $maxLineLength, "\r\n"); - } - - /** - * Encode stream $in to stream $out. - * - * @param Swift_OutputByteStream $os - * @param Swift_InputByteStream $is - * @param int $firstLineOffset ignored - * @param int $maxLineLength optional, 0 means no wrapping will occur - */ - public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) - { - $leftOver = ''; - while (false !== $bytes = $os->read(8192)) { - $toencode = $leftOver.$bytes; - if ($this->_canonical) { - $toencode = $this->_canonicalize($toencode); - } - $wrapped = $this->_safeWordWrap($toencode, $maxLineLength, "\r\n"); - $lastLinePos = strrpos($wrapped, "\r\n"); - $leftOver = substr($wrapped, $lastLinePos); - $wrapped = substr($wrapped, 0, $lastLinePos); - - $is->write($wrapped); - } - if (strlen($leftOver)) { - $is->write($leftOver); - } - } - - /** - * Get the name of this encoding scheme. - * - * @return string - */ - public function getName() - { - return $this->_name; - } - - /** - * Not used. - */ - public function charsetChanged($charset) - { - } - - /** - * A safer (but weaker) wordwrap for unicode. - * - * @param string $string - * @param int $length - * @param string $le - * - * @return string - */ - private function _safeWordwrap($string, $length = 75, $le = "\r\n") - { - if (0 >= $length) { - return $string; - } - - $originalLines = explode($le, $string); - - $lines = array(); - $lineCount = 0; - - foreach ($originalLines as $originalLine) { - $lines[] = ''; - $currentLine = &$lines[$lineCount++]; - - //$chunks = preg_split('/(?<=[\ \t,\.!\?\-&\+\/])/', $originalLine); - $chunks = preg_split('/(?<=\s)/', $originalLine); - - foreach ($chunks as $chunk) { - if (0 != strlen($currentLine) - && strlen($currentLine.$chunk) > $length) { - $lines[] = ''; - $currentLine = &$lines[$lineCount++]; - } - $currentLine .= $chunk; - } - } - - return implode("\r\n", $lines); - } - - /** - * Canonicalize string input (fix CRLF). - * - * @param string $string - * - * @return string - */ - private function _canonicalize($string) - { - return str_replace( - array("\r\n", "\r", "\n"), - array("\n", "\n", "\r\n"), - $string - ); - } -} diff --git a/tools/swift/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php b/tools/swift/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php deleted file mode 100644 index 5cc907b8e..000000000 --- a/tools/swift/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php +++ /dev/null @@ -1,134 +0,0 @@ -_dotEscape = $dotEscape; - parent::__construct($charStream, $filter); - } - - public function __sleep() - { - return array('_charStream', '_filter', '_dotEscape'); - } - - protected function getSafeMapShareId() - { - return get_class($this).($this->_dotEscape ? '.dotEscape' : ''); - } - - protected function initSafeMap() - { - parent::initSafeMap(); - if ($this->_dotEscape) { - /* Encode . as =2e for buggy remote servers */ - unset($this->_safeMap[0x2e]); - } - } - - /** - * Encode stream $in to stream $out. - * - * QP encoded strings have a maximum line length of 76 characters. - * If the first line needs to be shorter, indicate the difference with - * $firstLineOffset. - * - * @param Swift_OutputByteStream $os output stream - * @param Swift_InputByteStream $is input stream - * @param int $firstLineOffset - * @param int $maxLineLength - */ - public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) - { - if ($maxLineLength > 76 || $maxLineLength <= 0) { - $maxLineLength = 76; - } - - $thisLineLength = $maxLineLength - $firstLineOffset; - - $this->_charStream->flushContents(); - $this->_charStream->importByteStream($os); - - $currentLine = ''; - $prepend = ''; - $size = $lineLen = 0; - - while (false !== $bytes = $this->_nextSequence()) { - // If we're filtering the input - if (isset($this->_filter)) { - // If we can't filter because we need more bytes - while ($this->_filter->shouldBuffer($bytes)) { - // Then collect bytes into the buffer - if (false === $moreBytes = $this->_nextSequence(1)) { - break; - } - - foreach ($moreBytes as $b) { - $bytes[] = $b; - } - } - // And filter them - $bytes = $this->_filter->filter($bytes); - } - - $enc = $this->_encodeByteSequence($bytes, $size); - - $i = strpos($enc, '=0D=0A'); - $newLineLength = $lineLen + ($i === false ? $size : $i); - - if ($currentLine && $newLineLength >= $thisLineLength) { - $is->write($prepend.$this->_standardize($currentLine)); - $currentLine = ''; - $prepend = "=\r\n"; - $thisLineLength = $maxLineLength; - $lineLen = 0; - } - - $currentLine .= $enc; - - if ($i === false) { - $lineLen += $size; - } else { - // 6 is the length of '=0D=0A'. - $lineLen = $size - strrpos($enc, '=0D=0A') - 6; - } - } - if (strlen($currentLine)) { - $is->write($prepend.$this->_standardize($currentLine)); - } - } - - /** - * Get the name of this encoding scheme. - * Returns the string 'quoted-printable'. - * - * @return string - */ - public function getName() - { - return 'quoted-printable'; - } -} diff --git a/tools/swift/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php b/tools/swift/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php deleted file mode 100644 index 3214e1cf3..000000000 --- a/tools/swift/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php +++ /dev/null @@ -1,98 +0,0 @@ - - */ -class Swift_Mime_ContentEncoder_QpContentEncoderProxy implements Swift_Mime_ContentEncoder -{ - /** - * @var Swift_Mime_ContentEncoder_QpContentEncoder - */ - private $safeEncoder; - - /** - * @var Swift_Mime_ContentEncoder_NativeQpContentEncoder - */ - private $nativeEncoder; - - /** - * @var null|string - */ - private $charset; - - /** - * Constructor. - * - * @param Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder - * @param Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder - * @param string|null $charset - */ - public function __construct(Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder, Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder, $charset) - { - $this->safeEncoder = $safeEncoder; - $this->nativeEncoder = $nativeEncoder; - $this->charset = $charset; - } - - /** - * Make a deep copy of object. - */ - public function __clone() - { - $this->safeEncoder = clone $this->safeEncoder; - $this->nativeEncoder = clone $this->nativeEncoder; - } - - /** - * {@inheritdoc} - */ - public function charsetChanged($charset) - { - $this->charset = $charset; - $this->safeEncoder->charsetChanged($charset); - } - - /** - * {@inheritdoc} - */ - public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) - { - $this->getEncoder()->encodeByteStream($os, $is, $firstLineOffset, $maxLineLength); - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return 'quoted-printable'; - } - - /** - * {@inheritdoc} - */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) - { - return $this->getEncoder()->encodeString($string, $firstLineOffset, $maxLineLength); - } - - /** - * @return Swift_Mime_ContentEncoder - */ - private function getEncoder() - { - return 'utf-8' === $this->charset ? $this->nativeEncoder : $this->safeEncoder; - } -} diff --git a/tools/swift/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php b/tools/swift/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php deleted file mode 100644 index 0b8526e38..000000000 --- a/tools/swift/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php +++ /dev/null @@ -1,64 +0,0 @@ - - */ -class Swift_Mime_ContentEncoder_RawContentEncoder implements Swift_Mime_ContentEncoder -{ - /** - * Encode a given string to produce an encoded string. - * - * @param string $string - * @param int $firstLineOffset ignored - * @param int $maxLineLength ignored - * - * @return string - */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) - { - return $string; - } - - /** - * Encode stream $in to stream $out. - * - * @param Swift_OutputByteStream $in - * @param Swift_InputByteStream $out - * @param int $firstLineOffset ignored - * @param int $maxLineLength ignored - */ - public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) - { - while (false !== ($bytes = $os->read(8192))) { - $is->write($bytes); - } - } - - /** - * Get the name of this encoding scheme. - * - * @return string - */ - public function getName() - { - return 'raw'; - } - - /** - * Not used. - */ - public function charsetChanged($charset) - { - } -} diff --git a/tools/swift/classes/Swift/Mime/EmbeddedFile.php b/tools/swift/classes/Swift/Mime/EmbeddedFile.php deleted file mode 100644 index 6af757124..000000000 --- a/tools/swift/classes/Swift/Mime/EmbeddedFile.php +++ /dev/null @@ -1,45 +0,0 @@ -setDisposition('inline'); - $this->setId($this->getId()); - } - - /** - * Get the nesting level of this EmbeddedFile. - * - * Returns {@see LEVEL_RELATED}. - * - * @return int - */ - public function getNestingLevel() - { - return self::LEVEL_RELATED; - } -} diff --git a/tools/swift/classes/Swift/Mime/EncodingObserver.php b/tools/swift/classes/Swift/Mime/EncodingObserver.php deleted file mode 100644 index cc44a6efb..000000000 --- a/tools/swift/classes/Swift/Mime/EncodingObserver.php +++ /dev/null @@ -1,24 +0,0 @@ -init(); - } - - public function __wakeup() - { - $this->init(); - } - - protected function init() - { - if (count(self::$_specials) > 0) { - return; - } - - self::$_specials = array( - '(', ')', '<', '>', '[', ']', - ':', ';', '@', ',', '.', '"', - ); - - /*** Refer to RFC 2822 for ABNF grammar ***/ - - // All basic building blocks - self::$_grammar['NO-WS-CTL'] = '[\x01-\x08\x0B\x0C\x0E-\x19\x7F]'; - self::$_grammar['WSP'] = '[ \t]'; - self::$_grammar['CRLF'] = '(?:\r\n)'; - self::$_grammar['FWS'] = '(?:(?:'.self::$_grammar['WSP'].'*'. - self::$_grammar['CRLF'].')?'.self::$_grammar['WSP'].')'; - self::$_grammar['text'] = '[\x00-\x08\x0B\x0C\x0E-\x7F]'; - self::$_grammar['quoted-pair'] = '(?:\\\\'.self::$_grammar['text'].')'; - self::$_grammar['ctext'] = '(?:'.self::$_grammar['NO-WS-CTL']. - '|[\x21-\x27\x2A-\x5B\x5D-\x7E])'; - // Uses recursive PCRE (?1) -- could be a weak point?? - self::$_grammar['ccontent'] = '(?:'.self::$_grammar['ctext'].'|'. - self::$_grammar['quoted-pair'].'|(?1))'; - self::$_grammar['comment'] = '(\((?:'.self::$_grammar['FWS'].'|'. - self::$_grammar['ccontent'].')*'.self::$_grammar['FWS'].'?\))'; - self::$_grammar['CFWS'] = '(?:(?:'.self::$_grammar['FWS'].'?'. - self::$_grammar['comment'].')*(?:(?:'.self::$_grammar['FWS'].'?'. - self::$_grammar['comment'].')|'.self::$_grammar['FWS'].'))'; - self::$_grammar['qtext'] = '(?:'.self::$_grammar['NO-WS-CTL']. - '|[\x21\x23-\x5B\x5D-\x7E])'; - self::$_grammar['qcontent'] = '(?:'.self::$_grammar['qtext'].'|'. - self::$_grammar['quoted-pair'].')'; - self::$_grammar['quoted-string'] = '(?:'.self::$_grammar['CFWS'].'?"'. - '('.self::$_grammar['FWS'].'?'.self::$_grammar['qcontent'].')*'. - self::$_grammar['FWS'].'?"'.self::$_grammar['CFWS'].'?)'; - self::$_grammar['atext'] = '[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]'; - self::$_grammar['atom'] = '(?:'.self::$_grammar['CFWS'].'?'. - self::$_grammar['atext'].'+'.self::$_grammar['CFWS'].'?)'; - self::$_grammar['dot-atom-text'] = '(?:'.self::$_grammar['atext'].'+'. - '(\.'.self::$_grammar['atext'].'+)*)'; - self::$_grammar['dot-atom'] = '(?:'.self::$_grammar['CFWS'].'?'. - self::$_grammar['dot-atom-text'].'+'.self::$_grammar['CFWS'].'?)'; - self::$_grammar['word'] = '(?:'.self::$_grammar['atom'].'|'. - self::$_grammar['quoted-string'].')'; - self::$_grammar['phrase'] = '(?:'.self::$_grammar['word'].'+?)'; - self::$_grammar['no-fold-quote'] = '(?:"(?:'.self::$_grammar['qtext']. - '|'.self::$_grammar['quoted-pair'].')*")'; - self::$_grammar['dtext'] = '(?:'.self::$_grammar['NO-WS-CTL']. - '|[\x21-\x5A\x5E-\x7E])'; - self::$_grammar['no-fold-literal'] = '(?:\[(?:'.self::$_grammar['dtext']. - '|'.self::$_grammar['quoted-pair'].')*\])'; - - // Message IDs - self::$_grammar['id-left'] = '(?:'.self::$_grammar['dot-atom-text'].'|'. - self::$_grammar['no-fold-quote'].')'; - self::$_grammar['id-right'] = '(?:'.self::$_grammar['dot-atom-text'].'|'. - self::$_grammar['no-fold-literal'].')'; - - // Addresses, mailboxes and paths - self::$_grammar['local-part'] = '(?:'.self::$_grammar['dot-atom'].'|'. - self::$_grammar['quoted-string'].')'; - self::$_grammar['dcontent'] = '(?:'.self::$_grammar['dtext'].'|'. - self::$_grammar['quoted-pair'].')'; - self::$_grammar['domain-literal'] = '(?:'.self::$_grammar['CFWS'].'?\[('. - self::$_grammar['FWS'].'?'.self::$_grammar['dcontent'].')*?'. - self::$_grammar['FWS'].'?\]'.self::$_grammar['CFWS'].'?)'; - self::$_grammar['domain'] = '(?:'.self::$_grammar['dot-atom'].'|'. - self::$_grammar['domain-literal'].')'; - self::$_grammar['addr-spec'] = '(?:'.self::$_grammar['local-part'].'@'. - self::$_grammar['domain'].')'; - } - - /** - * Get the grammar defined for $name token. - * - * @param string $name exactly as written in the RFC - * - * @return string - */ - public function getDefinition($name) - { - if (array_key_exists($name, self::$_grammar)) { - return self::$_grammar[$name]; - } - - throw new Swift_RfcComplianceException( - "No such grammar '".$name."' defined." - ); - } - - /** - * Returns the tokens defined in RFC 2822 (and some related RFCs). - * - * @return array - */ - public function getGrammarDefinitions() - { - return self::$_grammar; - } - - /** - * Returns the current special characters used in the syntax which need to be escaped. - * - * @return array - */ - public function getSpecials() - { - return self::$_specials; - } - - /** - * Escape special characters in a string (convert to quoted-pairs). - * - * @param string $token - * @param string[] $include additional chars to escape - * @param string[] $exclude chars from escaping - * - * @return string - */ - public function escapeSpecials($token, $include = array(), $exclude = array()) - { - foreach (array_merge(array('\\'), array_diff(self::$_specials, $exclude), $include) as $char) { - $token = str_replace($char, '\\'.$char, $token); - } - - return $token; - } -} diff --git a/tools/swift/classes/Swift/Mime/Header.php b/tools/swift/classes/Swift/Mime/Header.php deleted file mode 100644 index a8ddd2721..000000000 --- a/tools/swift/classes/Swift/Mime/Header.php +++ /dev/null @@ -1,93 +0,0 @@ -getName(), "\r\n"); - mb_internal_encoding($old); - - return $newstring; - } - - return parent::encodeString($string, $firstLineOffset, $maxLineLength); - } -} diff --git a/tools/swift/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php b/tools/swift/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php deleted file mode 100644 index 510dd6637..000000000 --- a/tools/swift/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php +++ /dev/null @@ -1,65 +0,0 @@ -_safeMap[$byte] = chr($byte); - } - } - - /** - * Get the name of this encoding scheme. - * - * Returns the string 'Q'. - * - * @return string - */ - public function getName() - { - return 'Q'; - } - - /** - * Takes an unencoded string and produces a QP encoded string from it. - * - * @param string $string string to encode - * @param int $firstLineOffset optional - * @param int $maxLineLength optional, 0 indicates the default of 76 chars - * - * @return string - */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) - { - return str_replace(array(' ', '=20', "=\r\n"), array('_', '_', "\r\n"), - parent::encodeString($string, $firstLineOffset, $maxLineLength) - ); - } -} diff --git a/tools/swift/classes/Swift/Mime/HeaderFactory.php b/tools/swift/classes/Swift/Mime/HeaderFactory.php deleted file mode 100644 index c65f26d72..000000000 --- a/tools/swift/classes/Swift/Mime/HeaderFactory.php +++ /dev/null @@ -1,78 +0,0 @@ -setGrammar($grammar); - } - - /** - * Set the character set used in this Header. - * - * @param string $charset - */ - public function setCharset($charset) - { - $this->clearCachedValueIf($charset != $this->_charset); - $this->_charset = $charset; - if (isset($this->_encoder)) { - $this->_encoder->charsetChanged($charset); - } - } - - /** - * Get the character set used in this Header. - * - * @return string - */ - public function getCharset() - { - return $this->_charset; - } - - /** - * Set the language used in this Header. - * - * For example, for US English, 'en-us'. - * This can be unspecified. - * - * @param string $lang - */ - public function setLanguage($lang) - { - $this->clearCachedValueIf($this->_lang != $lang); - $this->_lang = $lang; - } - - /** - * Get the language used in this Header. - * - * @return string - */ - public function getLanguage() - { - return $this->_lang; - } - - /** - * Set the encoder used for encoding the header. - * - * @param Swift_Mime_HeaderEncoder $encoder - */ - public function setEncoder(Swift_Mime_HeaderEncoder $encoder) - { - $this->_encoder = $encoder; - $this->setCachedValue(null); - } - - /** - * Get the encoder used for encoding this Header. - * - * @return Swift_Mime_HeaderEncoder - */ - public function getEncoder() - { - return $this->_encoder; - } - - /** - * Set the grammar used for the header. - * - * @param Swift_Mime_Grammar $grammar - */ - public function setGrammar(Swift_Mime_Grammar $grammar) - { - $this->_grammar = $grammar; - $this->setCachedValue(null); - } - - /** - * Get the grammar used for this Header. - * - * @return Swift_Mime_Grammar - */ - public function getGrammar() - { - return $this->_grammar; - } - - /** - * Get the name of this header (e.g. charset). - * - * @return string - */ - public function getFieldName() - { - return $this->_name; - } - - /** - * Set the maximum length of lines in the header (excluding EOL). - * - * @param int $lineLength - */ - public function setMaxLineLength($lineLength) - { - $this->clearCachedValueIf($this->_lineLength != $lineLength); - $this->_lineLength = $lineLength; - } - - /** - * Get the maximum permitted length of lines in this Header. - * - * @return int - */ - public function getMaxLineLength() - { - return $this->_lineLength; - } - - /** - * Get this Header rendered as a RFC 2822 compliant string. - * - * @throws Swift_RfcComplianceException - * - * @return string - */ - public function toString() - { - return $this->_tokensToString($this->toTokens()); - } - - /** - * Returns a string representation of this object. - * - * @return string - * - * @see toString() - */ - public function __toString() - { - return $this->toString(); - } - - /** - * Set the name of this Header field. - * - * @param string $name - */ - protected function setFieldName($name) - { - $this->_name = $name; - } - - /** - * Produces a compliant, formatted RFC 2822 'phrase' based on the string given. - * - * @param Swift_Mime_Header $header - * @param string $string as displayed - * @param string $charset of the text - * @param Swift_Mime_HeaderEncoder $encoder - * @param bool $shorten the first line to make remove for header name - * - * @return string - */ - protected function createPhrase(Swift_Mime_Header $header, $string, $charset, Swift_Mime_HeaderEncoder $encoder = null, $shorten = false) - { - // Treat token as exactly what was given - $phraseStr = $string; - // If it's not valid - if (!preg_match('/^'.$this->getGrammar()->getDefinition('phrase').'$/D', $phraseStr)) { - // .. but it is just ascii text, try escaping some characters - // and make it a quoted-string - if (preg_match('/^'.$this->getGrammar()->getDefinition('text').'*$/D', $phraseStr)) { - $phraseStr = $this->getGrammar()->escapeSpecials( - $phraseStr, array('"'), $this->getGrammar()->getSpecials() - ); - $phraseStr = '"'.$phraseStr.'"'; - } else { - // ... otherwise it needs encoding - // Determine space remaining on line if first line - if ($shorten) { - $usedLength = strlen($header->getFieldName().': '); - } else { - $usedLength = 0; - } - $phraseStr = $this->encodeWords($header, $string, $usedLength); - } - } - - return $phraseStr; - } - - /** - * Encode needed word tokens within a string of input. - * - * @param Swift_Mime_Header $header - * @param string $input - * @param string $usedLength optional - * - * @return string - */ - protected function encodeWords(Swift_Mime_Header $header, $input, $usedLength = -1) - { - $value = ''; - - $tokens = $this->getEncodableWordTokens($input); - - foreach ($tokens as $token) { - // See RFC 2822, Sect 2.2 (really 2.2 ??) - if ($this->tokenNeedsEncoding($token)) { - // Don't encode starting WSP - $firstChar = substr($token, 0, 1); - switch ($firstChar) { - case ' ': - case "\t": - $value .= $firstChar; - $token = substr($token, 1); - } - - if (-1 == $usedLength) { - $usedLength = strlen($header->getFieldName().': ') + strlen($value); - } - $value .= $this->getTokenAsEncodedWord($token, $usedLength); - - $header->setMaxLineLength(76); // Forcefully override - } else { - $value .= $token; - } - } - - return $value; - } - - /** - * Test if a token needs to be encoded or not. - * - * @param string $token - * - * @return bool - */ - protected function tokenNeedsEncoding($token) - { - return preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token); - } - - /** - * Splits a string into tokens in blocks of words which can be encoded quickly. - * - * @param string $string - * - * @return string[] - */ - protected function getEncodableWordTokens($string) - { - $tokens = array(); - - $encodedToken = ''; - // Split at all whitespace boundaries - foreach (preg_split('~(?=[\t ])~', $string) as $token) { - if ($this->tokenNeedsEncoding($token)) { - $encodedToken .= $token; - } else { - if (strlen($encodedToken) > 0) { - $tokens[] = $encodedToken; - $encodedToken = ''; - } - $tokens[] = $token; - } - } - if (strlen($encodedToken)) { - $tokens[] = $encodedToken; - } - - return $tokens; - } - - /** - * Get a token as an encoded word for safe insertion into headers. - * - * @param string $token token to encode - * @param int $firstLineOffset optional - * - * @return string - */ - protected function getTokenAsEncodedWord($token, $firstLineOffset = 0) - { - // Adjust $firstLineOffset to account for space needed for syntax - $charsetDecl = $this->_charset; - if (isset($this->_lang)) { - $charsetDecl .= '*'.$this->_lang; - } - $encodingWrapperLength = strlen( - '=?'.$charsetDecl.'?'.$this->_encoder->getName().'??=' - ); - - if ($firstLineOffset >= 75) { - //Does this logic need to be here? - $firstLineOffset = 0; - } - - $encodedTextLines = explode("\r\n", - $this->_encoder->encodeString( - $token, $firstLineOffset, 75 - $encodingWrapperLength, $this->_charset - ) - ); - - if (strtolower($this->_charset) !== 'iso-2022-jp') { - // special encoding for iso-2022-jp using mb_encode_mimeheader - foreach ($encodedTextLines as $lineNum => $line) { - $encodedTextLines[$lineNum] = '=?'.$charsetDecl. - '?'.$this->_encoder->getName(). - '?'.$line.'?='; - } - } - - return implode("\r\n ", $encodedTextLines); - } - - /** - * Generates tokens from the given string which include CRLF as individual tokens. - * - * @param string $token - * - * @return string[] - */ - protected function generateTokenLines($token) - { - return preg_split('~(\r\n)~', $token, -1, PREG_SPLIT_DELIM_CAPTURE); - } - - /** - * Set a value into the cache. - * - * @param string $value - */ - protected function setCachedValue($value) - { - $this->_cachedValue = $value; - } - - /** - * Get the value in the cache. - * - * @return string - */ - protected function getCachedValue() - { - return $this->_cachedValue; - } - - /** - * Clear the cached value if $condition is met. - * - * @param bool $condition - */ - protected function clearCachedValueIf($condition) - { - if ($condition) { - $this->setCachedValue(null); - } - } - - /** - * Generate a list of all tokens in the final header. - * - * @param string $string The string to tokenize - * - * @return array An array of tokens as strings - */ - protected function toTokens($string = null) - { - if (null === $string) { - $string = $this->getFieldBody(); - } - - $tokens = array(); - - // Generate atoms; split at all invisible boundaries followed by WSP - foreach (preg_split('~(?=[ \t])~', $string) as $token) { - $newTokens = $this->generateTokenLines($token); - foreach ($newTokens as $newToken) { - $tokens[] = $newToken; - } - } - - return $tokens; - } - - /** - * Takes an array of tokens which appear in the header and turns them into - * an RFC 2822 compliant string, adding FWSP where needed. - * - * @param string[] $tokens - * - * @return string - */ - private function _tokensToString(array $tokens) - { - $lineCount = 0; - $headerLines = array(); - $headerLines[] = $this->_name.': '; - $currentLine = &$headerLines[$lineCount++]; - - // Build all tokens back into compliant header - foreach ($tokens as $i => $token) { - // Line longer than specified maximum or token was just a new line - if (("\r\n" == $token) || - ($i > 0 && strlen($currentLine.$token) > $this->_lineLength) - && 0 < strlen($currentLine)) { - $headerLines[] = ''; - $currentLine = &$headerLines[$lineCount++]; - } - - // Append token to the line - if ("\r\n" != $token) { - $currentLine .= $token; - } - } - - // Implode with FWS (RFC 2822, 2.2.3) - return implode("\r\n", $headerLines)."\r\n"; - } -} diff --git a/tools/swift/classes/Swift/Mime/Headers/DateHeader.php b/tools/swift/classes/Swift/Mime/Headers/DateHeader.php deleted file mode 100644 index 4075cbfa1..000000000 --- a/tools/swift/classes/Swift/Mime/Headers/DateHeader.php +++ /dev/null @@ -1,125 +0,0 @@ - - * - * - * - * @param string $name of Header - * @param Swift_Mime_Grammar $grammar - */ - public function __construct($name, Swift_Mime_Grammar $grammar) - { - $this->setFieldName($name); - parent::__construct($grammar); - } - - /** - * Get the type of Header that this instance represents. - * - * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX - * @see TYPE_DATE, TYPE_ID, TYPE_PATH - * - * @return int - */ - public function getFieldType() - { - return self::TYPE_DATE; - } - - /** - * Set the model for the field body. - * - * This method takes a UNIX timestamp. - * - * @param int $model - */ - public function setFieldBodyModel($model) - { - $this->setTimestamp($model); - } - - /** - * Get the model for the field body. - * - * This method returns a UNIX timestamp. - * - * @return mixed - */ - public function getFieldBodyModel() - { - return $this->getTimestamp(); - } - - /** - * Get the UNIX timestamp of the Date in this Header. - * - * @return int - */ - public function getTimestamp() - { - return $this->_timestamp; - } - - /** - * Set the UNIX timestamp of the Date in this Header. - * - * @param int $timestamp - */ - public function setTimestamp($timestamp) - { - if (null !== $timestamp) { - $timestamp = (int) $timestamp; - } - $this->clearCachedValueIf($this->_timestamp != $timestamp); - $this->_timestamp = $timestamp; - } - - /** - * Get the string value of the body in this Header. - * - * This is not necessarily RFC 2822 compliant since folding white space will - * not be added at this stage (see {@link toString()} for that). - * - * @see toString() - * - * @return string - */ - public function getFieldBody() - { - if (!$this->getCachedValue()) { - if (isset($this->_timestamp)) { - $this->setCachedValue(date('r', $this->_timestamp)); - } - } - - return $this->getCachedValue(); - } -} diff --git a/tools/swift/classes/Swift/Mime/Headers/IdentificationHeader.php b/tools/swift/classes/Swift/Mime/Headers/IdentificationHeader.php deleted file mode 100644 index b114506b4..000000000 --- a/tools/swift/classes/Swift/Mime/Headers/IdentificationHeader.php +++ /dev/null @@ -1,180 +0,0 @@ -setFieldName($name); - parent::__construct($grammar); - } - - /** - * Get the type of Header that this instance represents. - * - * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX - * @see TYPE_DATE, TYPE_ID, TYPE_PATH - * - * @return int - */ - public function getFieldType() - { - return self::TYPE_ID; - } - - /** - * Set the model for the field body. - * - * This method takes a string ID, or an array of IDs. - * - * @param mixed $model - * - * @throws Swift_RfcComplianceException - */ - public function setFieldBodyModel($model) - { - $this->setId($model); - } - - /** - * Get the model for the field body. - * - * This method returns an array of IDs - * - * @return array - */ - public function getFieldBodyModel() - { - return $this->getIds(); - } - - /** - * Set the ID used in the value of this header. - * - * @param string|array $id - * - * @throws Swift_RfcComplianceException - */ - public function setId($id) - { - $this->setIds(is_array($id) ? $id : array($id)); - } - - /** - * Get the ID used in the value of this Header. - * - * If multiple IDs are set only the first is returned. - * - * @return string - */ - public function getId() - { - if (count($this->_ids) > 0) { - return $this->_ids[0]; - } - } - - /** - * Set a collection of IDs to use in the value of this Header. - * - * @param string[] $ids - * - * @throws Swift_RfcComplianceException - */ - public function setIds(array $ids) - { - $actualIds = array(); - - foreach ($ids as $id) { - $this->_assertValidId($id); - $actualIds[] = $id; - } - - $this->clearCachedValueIf($this->_ids != $actualIds); - $this->_ids = $actualIds; - } - - /** - * Get the list of IDs used in this Header. - * - * @return string[] - */ - public function getIds() - { - return $this->_ids; - } - - /** - * Get the string value of the body in this Header. - * - * This is not necessarily RFC 2822 compliant since folding white space will - * not be added at this stage (see {@see toString()} for that). - * - * @see toString() - * - * @throws Swift_RfcComplianceException - * - * @return string - */ - public function getFieldBody() - { - if (!$this->getCachedValue()) { - $angleAddrs = array(); - - foreach ($this->_ids as $id) { - $angleAddrs[] = '<'.$id.'>'; - } - - $this->setCachedValue(implode(' ', $angleAddrs)); - } - - return $this->getCachedValue(); - } - - /** - * Throws an Exception if the id passed does not comply with RFC 2822. - * - * @param string $id - * - * @throws Swift_RfcComplianceException - */ - private function _assertValidId($id) - { - if (!preg_match( - '/^'.$this->getGrammar()->getDefinition('id-left').'@'. - $this->getGrammar()->getDefinition('id-right').'$/D', - $id - )) { - throw new Swift_RfcComplianceException( - 'Invalid ID given <'.$id.'>' - ); - } - } -} diff --git a/tools/swift/classes/Swift/Mime/Headers/MailboxHeader.php b/tools/swift/classes/Swift/Mime/Headers/MailboxHeader.php deleted file mode 100644 index e4567fc80..000000000 --- a/tools/swift/classes/Swift/Mime/Headers/MailboxHeader.php +++ /dev/null @@ -1,351 +0,0 @@ -setFieldName($name); - $this->setEncoder($encoder); - parent::__construct($grammar); - } - - /** - * Get the type of Header that this instance represents. - * - * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX - * @see TYPE_DATE, TYPE_ID, TYPE_PATH - * - * @return int - */ - public function getFieldType() - { - return self::TYPE_MAILBOX; - } - - /** - * Set the model for the field body. - * - * This method takes a string, or an array of addresses. - * - * @param mixed $model - * - * @throws Swift_RfcComplianceException - */ - public function setFieldBodyModel($model) - { - $this->setNameAddresses($model); - } - - /** - * Get the model for the field body. - * - * This method returns an associative array like {@link getNameAddresses()} - * - * @throws Swift_RfcComplianceException - * - * @return array - */ - public function getFieldBodyModel() - { - return $this->getNameAddresses(); - } - - /** - * Set a list of mailboxes to be shown in this Header. - * - * The mailboxes can be a simple array of addresses, or an array of - * key=>value pairs where (email => personalName). - * Example: - * - * setNameAddresses(array( - * 'chris@swiftmailer.org' => 'Chris Corbyn', - * 'mark@swiftmailer.org' //No associated personal name - * )); - * ?> - * - * - * @see __construct() - * @see setAddresses() - * @see setValue() - * - * @param string|string[] $mailboxes - * - * @throws Swift_RfcComplianceException - */ - public function setNameAddresses($mailboxes) - { - $this->_mailboxes = $this->normalizeMailboxes((array) $mailboxes); - $this->setCachedValue(null); //Clear any cached value - } - - /** - * Get the full mailbox list of this Header as an array of valid RFC 2822 strings. - * - * Example: - * - * 'Chris Corbyn', - * 'mark@swiftmailer.org' => 'Mark Corbyn') - * ); - * print_r($header->getNameAddressStrings()); - * // array ( - * // 0 => Chris Corbyn , - * // 1 => Mark Corbyn - * // ) - * ?> - * - * - * @see getNameAddresses() - * @see toString() - * - * @throws Swift_RfcComplianceException - * - * @return string[] - */ - public function getNameAddressStrings() - { - return $this->_createNameAddressStrings($this->getNameAddresses()); - } - - /** - * Get all mailboxes in this Header as key=>value pairs. - * - * The key is the address and the value is the name (or null if none set). - * Example: - * - * 'Chris Corbyn', - * 'mark@swiftmailer.org' => 'Mark Corbyn') - * ); - * print_r($header->getNameAddresses()); - * // array ( - * // chris@swiftmailer.org => Chris Corbyn, - * // mark@swiftmailer.org => Mark Corbyn - * // ) - * ?> - * - * - * @see getAddresses() - * @see getNameAddressStrings() - * - * @return string[] - */ - public function getNameAddresses() - { - return $this->_mailboxes; - } - - /** - * Makes this Header represent a list of plain email addresses with no names. - * - * Example: - * - * setAddresses( - * array('one@domain.tld', 'two@domain.tld', 'three@domain.tld') - * ); - * ?> - * - * - * @see setNameAddresses() - * @see setValue() - * - * @param string[] $addresses - * - * @throws Swift_RfcComplianceException - */ - public function setAddresses($addresses) - { - $this->setNameAddresses(array_values((array) $addresses)); - } - - /** - * Get all email addresses in this Header. - * - * @see getNameAddresses() - * - * @return string[] - */ - public function getAddresses() - { - return array_keys($this->_mailboxes); - } - - /** - * Remove one or more addresses from this Header. - * - * @param string|string[] $addresses - */ - public function removeAddresses($addresses) - { - $this->setCachedValue(null); - foreach ((array) $addresses as $address) { - unset($this->_mailboxes[$address]); - } - } - - /** - * Get the string value of the body in this Header. - * - * This is not necessarily RFC 2822 compliant since folding white space will - * not be added at this stage (see {@link toString()} for that). - * - * @see toString() - * - * @throws Swift_RfcComplianceException - * - * @return string - */ - public function getFieldBody() - { - // Compute the string value of the header only if needed - if (null === $this->getCachedValue()) { - $this->setCachedValue($this->createMailboxListString($this->_mailboxes)); - } - - return $this->getCachedValue(); - } - - /** - * Normalizes a user-input list of mailboxes into consistent key=>value pairs. - * - * @param string[] $mailboxes - * - * @return string[] - */ - protected function normalizeMailboxes(array $mailboxes) - { - $actualMailboxes = array(); - - foreach ($mailboxes as $key => $value) { - if (is_string($key)) { - //key is email addr - $address = $key; - $name = $value; - } else { - $address = $value; - $name = null; - } - $this->_assertValidAddress($address); - $actualMailboxes[$address] = $name; - } - - return $actualMailboxes; - } - - /** - * Produces a compliant, formatted display-name based on the string given. - * - * @param string $displayName as displayed - * @param bool $shorten the first line to make remove for header name - * - * @return string - */ - protected function createDisplayNameString($displayName, $shorten = false) - { - return $this->createPhrase($this, $displayName, $this->getCharset(), $this->getEncoder(), $shorten); - } - - /** - * Creates a string form of all the mailboxes in the passed array. - * - * @param string[] $mailboxes - * - * @throws Swift_RfcComplianceException - * - * @return string - */ - protected function createMailboxListString(array $mailboxes) - { - return implode(', ', $this->_createNameAddressStrings($mailboxes)); - } - - /** - * Redefine the encoding requirements for mailboxes. - * - * All "specials" must be encoded as the full header value will not be quoted - * - * @see RFC 2822 3.2.1 - * - * @param string $token - * - * @return bool - */ - protected function tokenNeedsEncoding($token) - { - return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); - } - - /** - * Return an array of strings conforming the the name-addr spec of RFC 2822. - * - * @param string[] $mailboxes - * - * @return string[] - */ - private function _createNameAddressStrings(array $mailboxes) - { - $strings = array(); - - foreach ($mailboxes as $email => $name) { - $mailboxStr = $email; - if (null !== $name) { - $nameStr = $this->createDisplayNameString($name, empty($strings)); - $mailboxStr = $nameStr.' <'.$mailboxStr.'>'; - } - $strings[] = $mailboxStr; - } - - return $strings; - } - - /** - * Throws an Exception if the address passed does not comply with RFC 2822. - * - * @param string $address - * - * @throws Swift_RfcComplianceException If invalid. - */ - private function _assertValidAddress($address) - { - if (!preg_match('/^'.$this->getGrammar()->getDefinition('addr-spec').'$/D', - $address)) { - throw new Swift_RfcComplianceException( - 'Address in mailbox given ['.$address. - '] does not comply with RFC 2822, 3.6.2.' - ); - } - } -} diff --git a/tools/swift/classes/Swift/Mime/Headers/OpenDKIMHeader.php b/tools/swift/classes/Swift/Mime/Headers/OpenDKIMHeader.php deleted file mode 100644 index d74955007..000000000 --- a/tools/swift/classes/Swift/Mime/Headers/OpenDKIMHeader.php +++ /dev/null @@ -1,133 +0,0 @@ - - */ -class Swift_Mime_Headers_OpenDKIMHeader implements Swift_Mime_Header -{ - /** - * The value of this Header. - * - * @var string - */ - private $_value; - - /** - * The name of this Header. - * - * @var string - */ - private $_fieldName; - - /** - * @param string $name - */ - public function __construct($name) - { - $this->_fieldName = $name; - } - - /** - * Get the type of Header that this instance represents. - * - * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX - * @see TYPE_DATE, TYPE_ID, TYPE_PATH - * - * @return int - */ - public function getFieldType() - { - return self::TYPE_TEXT; - } - - /** - * Set the model for the field body. - * - * This method takes a string for the field value. - * - * @param string $model - */ - public function setFieldBodyModel($model) - { - $this->setValue($model); - } - - /** - * Get the model for the field body. - * - * This method returns a string. - * - * @return string - */ - public function getFieldBodyModel() - { - return $this->getValue(); - } - - /** - * Get the (unencoded) value of this header. - * - * @return string - */ - public function getValue() - { - return $this->_value; - } - - /** - * Set the (unencoded) value of this header. - * - * @param string $value - */ - public function setValue($value) - { - $this->_value = $value; - } - - /** - * Get the value of this header prepared for rendering. - * - * @return string - */ - public function getFieldBody() - { - return $this->_value; - } - - /** - * Get this Header rendered as a RFC 2822 compliant string. - * - * @return string - */ - public function toString() - { - return $this->_fieldName.': '.$this->_value; - } - - /** - * Set the Header FieldName. - * - * @see Swift_Mime_Header::getFieldName() - */ - public function getFieldName() - { - return $this->_fieldName; - } - - /** - * Ignored. - */ - public function setCharset($charset) - { - } -} diff --git a/tools/swift/classes/Swift/Mime/Headers/ParameterizedHeader.php b/tools/swift/classes/Swift/Mime/Headers/ParameterizedHeader.php deleted file mode 100644 index c1777d333..000000000 --- a/tools/swift/classes/Swift/Mime/Headers/ParameterizedHeader.php +++ /dev/null @@ -1,258 +0,0 @@ -_paramEncoder = $paramEncoder; - } - - /** - * Get the type of Header that this instance represents. - * - * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX - * @see TYPE_DATE, TYPE_ID, TYPE_PATH - * - * @return int - */ - public function getFieldType() - { - return self::TYPE_PARAMETERIZED; - } - - /** - * Set the character set used in this Header. - * - * @param string $charset - */ - public function setCharset($charset) - { - parent::setCharset($charset); - if (isset($this->_paramEncoder)) { - $this->_paramEncoder->charsetChanged($charset); - } - } - - /** - * Set the value of $parameter. - * - * @param string $parameter - * @param string $value - */ - public function setParameter($parameter, $value) - { - $this->setParameters(array_merge($this->getParameters(), array($parameter => $value))); - } - - /** - * Get the value of $parameter. - * - * @param string $parameter - * - * @return string - */ - public function getParameter($parameter) - { - $params = $this->getParameters(); - - return array_key_exists($parameter, $params) ? $params[$parameter] : null; - } - - /** - * Set an associative array of parameter names mapped to values. - * - * @param string[] $parameters - */ - public function setParameters(array $parameters) - { - $this->clearCachedValueIf($this->_params != $parameters); - $this->_params = $parameters; - } - - /** - * Returns an associative array of parameter names mapped to values. - * - * @return string[] - */ - public function getParameters() - { - return $this->_params; - } - - /** - * Get the value of this header prepared for rendering. - * - * @return string - */ - public function getFieldBody() //TODO: Check caching here - { - $body = parent::getFieldBody(); - foreach ($this->_params as $name => $value) { - if (null !== $value) { - // Add the parameter - $body .= '; '.$this->_createParameter($name, $value); - } - } - - return $body; - } - - /** - * Generate a list of all tokens in the final header. - * - * This doesn't need to be overridden in theory, but it is for implementation - * reasons to prevent potential breakage of attributes. - * - * @param string $string The string to tokenize - * - * @return array An array of tokens as strings - */ - protected function toTokens($string = null) - { - $tokens = parent::toTokens(parent::getFieldBody()); - - // Try creating any parameters - foreach ($this->_params as $name => $value) { - if (null !== $value) { - // Add the semi-colon separator - $tokens[count($tokens) - 1] .= ';'; - $tokens = array_merge($tokens, $this->generateTokenLines( - ' '.$this->_createParameter($name, $value) - )); - } - } - - return $tokens; - } - - /** - * Render a RFC 2047 compliant header parameter from the $name and $value. - * - * @param string $name - * @param string $value - * - * @return string - */ - private function _createParameter($name, $value) - { - $origValue = $value; - - $encoded = false; - // Allow room for parameter name, indices, "=" and DQUOTEs - $maxValueLength = $this->getMaxLineLength() - strlen($name.'=*N"";') - 1; - $firstLineOffset = 0; - - // If it's not already a valid parameter value... - if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { - // TODO: text, or something else?? - // ... and it's not ascii - if (!preg_match('/^'.$this->getGrammar()->getDefinition('text').'*$/D', $value)) { - $encoded = true; - // Allow space for the indices, charset and language - $maxValueLength = $this->getMaxLineLength() - strlen($name.'*N*="";') - 1; - $firstLineOffset = strlen( - $this->getCharset()."'".$this->getLanguage()."'" - ); - } - } - - // Encode if we need to - if ($encoded || strlen($value) > $maxValueLength) { - if (isset($this->_paramEncoder)) { - $value = $this->_paramEncoder->encodeString( - $origValue, $firstLineOffset, $maxValueLength, $this->getCharset() - ); - } else { - // We have to go against RFC 2183/2231 in some areas for interoperability - $value = $this->getTokenAsEncodedWord($origValue); - $encoded = false; - } - } - - $valueLines = isset($this->_paramEncoder) ? explode("\r\n", $value) : array($value); - - // Need to add indices - if (count($valueLines) > 1) { - $paramLines = array(); - foreach ($valueLines as $i => $line) { - $paramLines[] = $name.'*'.$i. - $this->_getEndOfParameterValue($line, true, $i == 0); - } - - return implode(";\r\n ", $paramLines); - } else { - return $name.$this->_getEndOfParameterValue( - $valueLines[0], $encoded, true - ); - } - } - - /** - * Returns the parameter value from the "=" and beyond. - * - * @param string $value to append - * @param bool $encoded - * @param bool $firstLine - * - * @return string - */ - private function _getEndOfParameterValue($value, $encoded = false, $firstLine = false) - { - if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { - $value = '"'.$value.'"'; - } - $prepend = '='; - if ($encoded) { - $prepend = '*='; - if ($firstLine) { - $prepend = '*='.$this->getCharset()."'".$this->getLanguage(). - "'"; - } - } - - return $prepend.$value; - } -} diff --git a/tools/swift/classes/Swift/Mime/Headers/PathHeader.php b/tools/swift/classes/Swift/Mime/Headers/PathHeader.php deleted file mode 100644 index 4a814b122..000000000 --- a/tools/swift/classes/Swift/Mime/Headers/PathHeader.php +++ /dev/null @@ -1,143 +0,0 @@ -setFieldName($name); - parent::__construct($grammar); - } - - /** - * Get the type of Header that this instance represents. - * - * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX - * @see TYPE_DATE, TYPE_ID, TYPE_PATH - * - * @return int - */ - public function getFieldType() - { - return self::TYPE_PATH; - } - - /** - * Set the model for the field body. - * This method takes a string for an address. - * - * @param string $model - * - * @throws Swift_RfcComplianceException - */ - public function setFieldBodyModel($model) - { - $this->setAddress($model); - } - - /** - * Get the model for the field body. - * This method returns a string email address. - * - * @return mixed - */ - public function getFieldBodyModel() - { - return $this->getAddress(); - } - - /** - * Set the Address which should appear in this Header. - * - * @param string $address - * - * @throws Swift_RfcComplianceException - */ - public function setAddress($address) - { - if (null === $address) { - $this->_address = null; - } elseif ('' == $address) { - $this->_address = ''; - } else { - $this->_assertValidAddress($address); - $this->_address = $address; - } - $this->setCachedValue(null); - } - - /** - * Get the address which is used in this Header (if any). - * - * Null is returned if no address is set. - * - * @return string - */ - public function getAddress() - { - return $this->_address; - } - - /** - * Get the string value of the body in this Header. - * - * This is not necessarily RFC 2822 compliant since folding white space will - * not be added at this stage (see {@link toString()} for that). - * - * @see toString() - * - * @return string - */ - public function getFieldBody() - { - if (!$this->getCachedValue()) { - if (isset($this->_address)) { - $this->setCachedValue('<'.$this->_address.'>'); - } - } - - return $this->getCachedValue(); - } - - /** - * Throws an Exception if the address passed does not comply with RFC 2822. - * - * @param string $address - * - * @throws Swift_RfcComplianceException If address is invalid - */ - private function _assertValidAddress($address) - { - if (!preg_match('/^'.$this->getGrammar()->getDefinition('addr-spec').'$/D', - $address)) { - throw new Swift_RfcComplianceException( - 'Address set in PathHeader does not comply with addr-spec of RFC 2822.' - ); - } - } -} diff --git a/tools/swift/classes/Swift/Mime/Headers/UnstructuredHeader.php b/tools/swift/classes/Swift/Mime/Headers/UnstructuredHeader.php deleted file mode 100644 index 86177f14a..000000000 --- a/tools/swift/classes/Swift/Mime/Headers/UnstructuredHeader.php +++ /dev/null @@ -1,112 +0,0 @@ -setFieldName($name); - $this->setEncoder($encoder); - parent::__construct($grammar); - } - - /** - * Get the type of Header that this instance represents. - * - * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX - * @see TYPE_DATE, TYPE_ID, TYPE_PATH - * - * @return int - */ - public function getFieldType() - { - return self::TYPE_TEXT; - } - - /** - * Set the model for the field body. - * - * This method takes a string for the field value. - * - * @param string $model - */ - public function setFieldBodyModel($model) - { - $this->setValue($model); - } - - /** - * Get the model for the field body. - * - * This method returns a string. - * - * @return string - */ - public function getFieldBodyModel() - { - return $this->getValue(); - } - - /** - * Get the (unencoded) value of this header. - * - * @return string - */ - public function getValue() - { - return $this->_value; - } - - /** - * Set the (unencoded) value of this header. - * - * @param string $value - */ - public function setValue($value) - { - $this->clearCachedValueIf($this->_value != $value); - $this->_value = $value; - } - - /** - * Get the value of this header prepared for rendering. - * - * @return string - */ - public function getFieldBody() - { - if (!$this->getCachedValue()) { - $this->setCachedValue( - $this->encodeWords($this, $this->_value) - ); - } - - return $this->getCachedValue(); - } -} diff --git a/tools/swift/classes/Swift/Mime/Message.php b/tools/swift/classes/Swift/Mime/Message.php deleted file mode 100644 index 9b36d2162..000000000 --- a/tools/swift/classes/Swift/Mime/Message.php +++ /dev/null @@ -1,223 +0,0 @@ - 'Real Name'). - * - * If the second parameter is provided and the first is a string, then $name - * is associated with the address. - * - * @param mixed $address - * @param string $name optional - */ - public function setSender($address, $name = null); - - /** - * Get the sender address for this message. - * - * This has a higher significance than the From address. - * - * @return string - */ - public function getSender(); - - /** - * Set the From address of this message. - * - * It is permissible for multiple From addresses to be set using an array. - * - * If multiple From addresses are used, you SHOULD set the Sender address and - * according to RFC 2822, MUST set the sender address. - * - * An array can be used if display names are to be provided: i.e. - * array('email@address.com' => 'Real Name'). - * - * If the second parameter is provided and the first is a string, then $name - * is associated with the address. - * - * @param mixed $addresses - * @param string $name optional - */ - public function setFrom($addresses, $name = null); - - /** - * Get the From address(es) of this message. - * - * This method always returns an associative array where the keys are the - * addresses. - * - * @return string[] - */ - public function getFrom(); - - /** - * Set the Reply-To address(es). - * - * Any replies from the receiver will be sent to this address. - * - * It is permissible for multiple reply-to addresses to be set using an array. - * - * This method has the same synopsis as {@link setFrom()} and {@link setTo()}. - * - * If the second parameter is provided and the first is a string, then $name - * is associated with the address. - * - * @param mixed $addresses - * @param string $name optional - */ - public function setReplyTo($addresses, $name = null); - - /** - * Get the Reply-To addresses for this message. - * - * This method always returns an associative array where the keys provide the - * email addresses. - * - * @return string[] - */ - public function getReplyTo(); - - /** - * Set the To address(es). - * - * Recipients set in this field will receive a copy of this message. - * - * This method has the same synopsis as {@link setFrom()} and {@link setCc()}. - * - * If the second parameter is provided and the first is a string, then $name - * is associated with the address. - * - * @param mixed $addresses - * @param string $name optional - */ - public function setTo($addresses, $name = null); - - /** - * Get the To addresses for this message. - * - * This method always returns an associative array, whereby the keys provide - * the actual email addresses. - * - * @return string[] - */ - public function getTo(); - - /** - * Set the Cc address(es). - * - * Recipients set in this field will receive a 'carbon-copy' of this message. - * - * This method has the same synopsis as {@link setFrom()} and {@link setTo()}. - * - * @param mixed $addresses - * @param string $name optional - */ - public function setCc($addresses, $name = null); - - /** - * Get the Cc addresses for this message. - * - * This method always returns an associative array, whereby the keys provide - * the actual email addresses. - * - * @return string[] - */ - public function getCc(); - - /** - * Set the Bcc address(es). - * - * Recipients set in this field will receive a 'blind-carbon-copy' of this - * message. - * - * In other words, they will get the message, but any other recipients of the - * message will have no such knowledge of their receipt of it. - * - * This method has the same synopsis as {@link setFrom()} and {@link setTo()}. - * - * @param mixed $addresses - * @param string $name optional - */ - public function setBcc($addresses, $name = null); - - /** - * Get the Bcc addresses for this message. - * - * This method always returns an associative array, whereby the keys provide - * the actual email addresses. - * - * @return string[] - */ - public function getBcc(); -} diff --git a/tools/swift/classes/Swift/Mime/MimeEntity.php b/tools/swift/classes/Swift/Mime/MimeEntity.php deleted file mode 100644 index 30f460cdc..000000000 --- a/tools/swift/classes/Swift/Mime/MimeEntity.php +++ /dev/null @@ -1,117 +0,0 @@ -setContentType('text/plain'); - if (null !== $charset) { - $this->setCharset($charset); - } - } - - /** - * Set the body of this entity, either as a string, or as an instance of - * {@link Swift_OutputByteStream}. - * - * @param mixed $body - * @param string $contentType optional - * @param string $charset optional - * - * @return $this - */ - public function setBody($body, $contentType = null, $charset = null) - { - if (isset($charset)) { - $this->setCharset($charset); - } - $body = $this->_convertString($body); - - parent::setBody($body, $contentType); - - return $this; - } - - /** - * Get the character set of this entity. - * - * @return string - */ - public function getCharset() - { - return $this->_getHeaderParameter('Content-Type', 'charset'); - } - - /** - * Set the character set of this entity. - * - * @param string $charset - * - * @return $this - */ - public function setCharset($charset) - { - $this->_setHeaderParameter('Content-Type', 'charset', $charset); - if ($charset !== $this->_userCharset) { - $this->_clearCache(); - } - $this->_userCharset = $charset; - parent::charsetChanged($charset); - - return $this; - } - - /** - * Get the format of this entity (i.e. flowed or fixed). - * - * @return string - */ - public function getFormat() - { - return $this->_getHeaderParameter('Content-Type', 'format'); - } - - /** - * Set the format of this entity (flowed or fixed). - * - * @param string $format - * - * @return $this - */ - public function setFormat($format) - { - $this->_setHeaderParameter('Content-Type', 'format', $format); - $this->_userFormat = $format; - - return $this; - } - - /** - * Test if delsp is being used for this entity. - * - * @return bool - */ - public function getDelSp() - { - return 'yes' == $this->_getHeaderParameter('Content-Type', 'delsp') ? true : false; - } - - /** - * Turn delsp on or off for this entity. - * - * @param bool $delsp - * - * @return $this - */ - public function setDelSp($delsp = true) - { - $this->_setHeaderParameter('Content-Type', 'delsp', $delsp ? 'yes' : null); - $this->_userDelSp = $delsp; - - return $this; - } - - /** - * Get the nesting level of this entity. - * - * @see LEVEL_TOP, LEVEL_ALTERNATIVE, LEVEL_MIXED, LEVEL_RELATED - * - * @return int - */ - public function getNestingLevel() - { - return $this->_nestingLevel; - } - - /** - * Receive notification that the charset has changed on this document, or a - * parent document. - * - * @param string $charset - */ - public function charsetChanged($charset) - { - $this->setCharset($charset); - } - - /** Fix the content-type and encoding of this entity */ - protected function _fixHeaders() - { - parent::_fixHeaders(); - if (count($this->getChildren())) { - $this->_setHeaderParameter('Content-Type', 'charset', null); - $this->_setHeaderParameter('Content-Type', 'format', null); - $this->_setHeaderParameter('Content-Type', 'delsp', null); - } else { - $this->setCharset($this->_userCharset); - $this->setFormat($this->_userFormat); - $this->setDelSp($this->_userDelSp); - } - } - - /** Set the nesting level of this entity */ - protected function _setNestingLevel($level) - { - $this->_nestingLevel = $level; - } - - /** Encode charset when charset is not utf-8 */ - protected function _convertString($string) - { - $charset = strtolower($this->getCharset()); - if (!in_array($charset, array('utf-8', 'iso-8859-1', 'iso-8859-15', ''))) { - // mb_convert_encoding must be the first one to check, since iconv cannot convert some words. - if (function_exists('mb_convert_encoding')) { - $string = mb_convert_encoding($string, $charset, 'utf-8'); - } elseif (function_exists('iconv')) { - $string = iconv('utf-8//TRANSLIT//IGNORE', $charset, $string); - } else { - throw new Swift_SwiftException('No suitable convert encoding function (use UTF-8 as your charset or install the mbstring or iconv extension).'); - } - - return $string; - } - - return $string; - } -} diff --git a/tools/swift/classes/Swift/Mime/ParameterizedHeader.php b/tools/swift/classes/Swift/Mime/ParameterizedHeader.php deleted file mode 100644 index e15c6ef95..000000000 --- a/tools/swift/classes/Swift/Mime/ParameterizedHeader.php +++ /dev/null @@ -1,34 +0,0 @@ -_encoder = $encoder; - $this->_paramEncoder = $paramEncoder; - $this->_grammar = $grammar; - $this->_charset = $charset; - } - - /** - * Create a new Mailbox Header with a list of $addresses. - * - * @param string $name - * @param array|string|null $addresses - * - * @return Swift_Mime_Header - */ - public function createMailboxHeader($name, $addresses = null) - { - $header = new Swift_Mime_Headers_MailboxHeader($name, $this->_encoder, $this->_grammar); - if (isset($addresses)) { - $header->setFieldBodyModel($addresses); - } - $this->_setHeaderCharset($header); - - return $header; - } - - /** - * Create a new Date header using $timestamp (UNIX time). - * - * @param string $name - * @param int|null $timestamp - * - * @return Swift_Mime_Header - */ - public function createDateHeader($name, $timestamp = null) - { - $header = new Swift_Mime_Headers_DateHeader($name, $this->_grammar); - if (isset($timestamp)) { - $header->setFieldBodyModel($timestamp); - } - $this->_setHeaderCharset($header); - - return $header; - } - - /** - * Create a new basic text header with $name and $value. - * - * @param string $name - * @param string $value - * - * @return Swift_Mime_Header - */ - public function createTextHeader($name, $value = null) - { - $header = new Swift_Mime_Headers_UnstructuredHeader($name, $this->_encoder, $this->_grammar); - if (isset($value)) { - $header->setFieldBodyModel($value); - } - $this->_setHeaderCharset($header); - - return $header; - } - - /** - * Create a new ParameterizedHeader with $name, $value and $params. - * - * @param string $name - * @param string $value - * @param array $params - * - * @return Swift_Mime_ParameterizedHeader - */ - public function createParameterizedHeader($name, $value = null, - $params = array()) - { - $header = new Swift_Mime_Headers_ParameterizedHeader($name, $this->_encoder, strtolower($name) == 'content-disposition' ? $this->_paramEncoder : null, $this->_grammar); - if (isset($value)) { - $header->setFieldBodyModel($value); - } - foreach ($params as $k => $v) { - $header->setParameter($k, $v); - } - $this->_setHeaderCharset($header); - - return $header; - } - - /** - * Create a new ID header for Message-ID or Content-ID. - * - * @param string $name - * @param string|array $ids - * - * @return Swift_Mime_Header - */ - public function createIdHeader($name, $ids = null) - { - $header = new Swift_Mime_Headers_IdentificationHeader($name, $this->_grammar); - if (isset($ids)) { - $header->setFieldBodyModel($ids); - } - $this->_setHeaderCharset($header); - - return $header; - } - - /** - * Create a new Path header with an address (path) in it. - * - * @param string $name - * @param string $path - * - * @return Swift_Mime_Header - */ - public function createPathHeader($name, $path = null) - { - $header = new Swift_Mime_Headers_PathHeader($name, $this->_grammar); - if (isset($path)) { - $header->setFieldBodyModel($path); - } - $this->_setHeaderCharset($header); - - return $header; - } - - /** - * Notify this observer that the entity's charset has changed. - * - * @param string $charset - */ - public function charsetChanged($charset) - { - $this->_charset = $charset; - $this->_encoder->charsetChanged($charset); - $this->_paramEncoder->charsetChanged($charset); - } - - /** - * Make a deep copy of object. - */ - public function __clone() - { - $this->_encoder = clone $this->_encoder; - $this->_paramEncoder = clone $this->_paramEncoder; - } - - /** Apply the charset to the Header */ - private function _setHeaderCharset(Swift_Mime_Header $header) - { - if (isset($this->_charset)) { - $header->setCharset($this->_charset); - } - } -} diff --git a/tools/swift/classes/Swift/Mime/SimpleHeaderSet.php b/tools/swift/classes/Swift/Mime/SimpleHeaderSet.php deleted file mode 100644 index a06ce7247..000000000 --- a/tools/swift/classes/Swift/Mime/SimpleHeaderSet.php +++ /dev/null @@ -1,414 +0,0 @@ -_factory = $factory; - if (isset($charset)) { - $this->setCharset($charset); - } - } - - /** - * Set the charset used by these headers. - * - * @param string $charset - */ - public function setCharset($charset) - { - $this->_charset = $charset; - $this->_factory->charsetChanged($charset); - $this->_notifyHeadersOfCharset($charset); - } - - /** - * Add a new Mailbox Header with a list of $addresses. - * - * @param string $name - * @param array|string $addresses - */ - public function addMailboxHeader($name, $addresses = null) - { - $this->_storeHeader($name, - $this->_factory->createMailboxHeader($name, $addresses)); - } - - /** - * Add a new Date header using $timestamp (UNIX time). - * - * @param string $name - * @param int $timestamp - */ - public function addDateHeader($name, $timestamp = null) - { - $this->_storeHeader($name, - $this->_factory->createDateHeader($name, $timestamp)); - } - - /** - * Add a new basic text header with $name and $value. - * - * @param string $name - * @param string $value - */ - public function addTextHeader($name, $value = null) - { - $this->_storeHeader($name, - $this->_factory->createTextHeader($name, $value)); - } - - /** - * Add a new ParameterizedHeader with $name, $value and $params. - * - * @param string $name - * @param string $value - * @param array $params - */ - public function addParameterizedHeader($name, $value = null, $params = array()) - { - $this->_storeHeader($name, $this->_factory->createParameterizedHeader($name, $value, $params)); - } - - /** - * Add a new ID header for Message-ID or Content-ID. - * - * @param string $name - * @param string|array $ids - */ - public function addIdHeader($name, $ids = null) - { - $this->_storeHeader($name, $this->_factory->createIdHeader($name, $ids)); - } - - /** - * Add a new Path header with an address (path) in it. - * - * @param string $name - * @param string $path - */ - public function addPathHeader($name, $path = null) - { - $this->_storeHeader($name, $this->_factory->createPathHeader($name, $path)); - } - - /** - * Returns true if at least one header with the given $name exists. - * - * If multiple headers match, the actual one may be specified by $index. - * - * @param string $name - * @param int $index - * - * @return bool - */ - public function has($name, $index = 0) - { - $lowerName = strtolower($name); - - if (!array_key_exists($lowerName, $this->_headers)) { - return false; - } - - if (func_num_args() < 2) { - // index was not specified, so we only need to check that there is at least one header value set - return (bool) count($this->_headers[$lowerName]); - } - - return array_key_exists($index, $this->_headers[$lowerName]); - } - - /** - * Set a header in the HeaderSet. - * - * The header may be a previously fetched header via {@link get()} or it may - * be one that has been created separately. - * - * If $index is specified, the header will be inserted into the set at this - * offset. - * - * @param Swift_Mime_Header $header - * @param int $index - */ - public function set(Swift_Mime_Header $header, $index = 0) - { - $this->_storeHeader($header->getFieldName(), $header, $index); - } - - /** - * Get the header with the given $name. - * - * If multiple headers match, the actual one may be specified by $index. - * Returns NULL if none present. - * - * @param string $name - * @param int $index - * - * @return Swift_Mime_Header - */ - public function get($name, $index = 0) - { - $name = strtolower($name); - - if (func_num_args() < 2) { - if ($this->has($name)) { - $values = array_values($this->_headers[$name]); - - return array_shift($values); - } - } else { - if ($this->has($name, $index)) { - return $this->_headers[$name][$index]; - } - } - } - - /** - * Get all headers with the given $name. - * - * @param string $name - * - * @return array - */ - public function getAll($name = null) - { - if (!isset($name)) { - $headers = array(); - foreach ($this->_headers as $collection) { - $headers = array_merge($headers, $collection); - } - - return $headers; - } - - $lowerName = strtolower($name); - if (!array_key_exists($lowerName, $this->_headers)) { - return array(); - } - - return $this->_headers[$lowerName]; - } - - /** - * Return the name of all Headers. - * - * @return array - */ - public function listAll() - { - $headers = $this->_headers; - if ($this->_canSort()) { - uksort($headers, array($this, '_sortHeaders')); - } - - return array_keys($headers); - } - - /** - * Remove the header with the given $name if it's set. - * - * If multiple headers match, the actual one may be specified by $index. - * - * @param string $name - * @param int $index - */ - public function remove($name, $index = 0) - { - $lowerName = strtolower($name); - unset($this->_headers[$lowerName][$index]); - } - - /** - * Remove all headers with the given $name. - * - * @param string $name - */ - public function removeAll($name) - { - $lowerName = strtolower($name); - unset($this->_headers[$lowerName]); - } - - /** - * Create a new instance of this HeaderSet. - * - * @return self - */ - public function newInstance() - { - return new self($this->_factory); - } - - /** - * Define a list of Header names as an array in the correct order. - * - * These Headers will be output in the given order where present. - * - * @param array $sequence - */ - public function defineOrdering(array $sequence) - { - $this->_order = array_flip(array_map('strtolower', $sequence)); - } - - /** - * Set a list of header names which must always be displayed when set. - * - * Usually headers without a field value won't be output unless set here. - * - * @param array $names - */ - public function setAlwaysDisplayed(array $names) - { - $this->_required = array_flip(array_map('strtolower', $names)); - } - - /** - * Notify this observer that the entity's charset has changed. - * - * @param string $charset - */ - public function charsetChanged($charset) - { - $this->setCharset($charset); - } - - /** - * Returns a string with a representation of all headers. - * - * @return string - */ - public function toString() - { - $string = ''; - $headers = $this->_headers; - if ($this->_canSort()) { - uksort($headers, array($this, '_sortHeaders')); - } - foreach ($headers as $collection) { - foreach ($collection as $header) { - if ($this->_isDisplayed($header) || $header->getFieldBody() != '') { - $string .= $header->toString(); - } - } - } - - return $string; - } - - /** - * Returns a string representation of this object. - * - * @return string - * - * @see toString() - */ - public function __toString() - { - return $this->toString(); - } - - /** Save a Header to the internal collection */ - private function _storeHeader($name, Swift_Mime_Header $header, $offset = null) - { - if (!isset($this->_headers[strtolower($name)])) { - $this->_headers[strtolower($name)] = array(); - } - if (!isset($offset)) { - $this->_headers[strtolower($name)][] = $header; - } else { - $this->_headers[strtolower($name)][$offset] = $header; - } - } - - /** Test if the headers can be sorted */ - private function _canSort() - { - return count($this->_order) > 0; - } - - /** uksort() algorithm for Header ordering */ - private function _sortHeaders($a, $b) - { - $lowerA = strtolower($a); - $lowerB = strtolower($b); - $aPos = array_key_exists($lowerA, $this->_order) ? $this->_order[$lowerA] : -1; - $bPos = array_key_exists($lowerB, $this->_order) ? $this->_order[$lowerB] : -1; - - if (-1 === $aPos && -1 === $bPos) { - // just be sure to be determinist here - return $a > $b ? -1 : 1; - } - - if ($aPos == -1) { - return 1; - } elseif ($bPos == -1) { - return -1; - } - - return $aPos < $bPos ? -1 : 1; - } - - /** Test if the given Header is always displayed */ - private function _isDisplayed(Swift_Mime_Header $header) - { - return array_key_exists(strtolower($header->getFieldName()), $this->_required); - } - - /** Notify all Headers of the new charset */ - private function _notifyHeadersOfCharset($charset) - { - foreach ($this->_headers as $headerGroup) { - foreach ($headerGroup as $header) { - $header->setCharset($charset); - } - } - } - - /** - * Make a deep copy of object. - */ - public function __clone() - { - $this->_factory = clone $this->_factory; - foreach ($this->_headers as $groupKey => $headerGroup) { - foreach ($headerGroup as $key => $header) { - $this->_headers[$groupKey][$key] = clone $header; - } - } - } -} diff --git a/tools/swift/classes/Swift/Mime/SimpleMessage.php b/tools/swift/classes/Swift/Mime/SimpleMessage.php deleted file mode 100644 index 72d40cee0..000000000 --- a/tools/swift/classes/Swift/Mime/SimpleMessage.php +++ /dev/null @@ -1,655 +0,0 @@ -getHeaders()->defineOrdering(array( - 'Return-Path', - 'Received', - 'DKIM-Signature', - 'DomainKey-Signature', - 'Sender', - 'Message-ID', - 'Date', - 'Subject', - 'From', - 'Reply-To', - 'To', - 'Cc', - 'Bcc', - 'MIME-Version', - 'Content-Type', - 'Content-Transfer-Encoding', - )); - $this->getHeaders()->setAlwaysDisplayed(array('Date', 'Message-ID', 'From')); - $this->getHeaders()->addTextHeader('MIME-Version', '1.0'); - $this->setDate(time()); - $this->setId($this->getId()); - $this->getHeaders()->addMailboxHeader('From'); - } - - /** - * Always returns {@link LEVEL_TOP} for a message instance. - * - * @return int - */ - public function getNestingLevel() - { - return self::LEVEL_TOP; - } - - /** - * Set the subject of this message. - * - * @param string $subject - * - * @return $this - */ - public function setSubject($subject) - { - if (!$this->_setHeaderFieldModel('Subject', $subject)) { - $this->getHeaders()->addTextHeader('Subject', $subject); - } - - return $this; - } - - /** - * Get the subject of this message. - * - * @return string - */ - public function getSubject() - { - return $this->_getHeaderFieldModel('Subject'); - } - - /** - * Set the date at which this message was created. - * - * @param int $date - * - * @return $this - */ - public function setDate($date) - { - if (!$this->_setHeaderFieldModel('Date', $date)) { - $this->getHeaders()->addDateHeader('Date', $date); - } - - return $this; - } - - /** - * Get the date at which this message was created. - * - * @return int - */ - public function getDate() - { - return $this->_getHeaderFieldModel('Date'); - } - - /** - * Set the return-path (the bounce address) of this message. - * - * @param string $address - * - * @return $this - */ - public function setReturnPath($address) - { - if (!$this->_setHeaderFieldModel('Return-Path', $address)) { - $this->getHeaders()->addPathHeader('Return-Path', $address); - } - - return $this; - } - - /** - * Get the return-path (bounce address) of this message. - * - * @return string - */ - public function getReturnPath() - { - return $this->_getHeaderFieldModel('Return-Path'); - } - - /** - * Set the sender of this message. - * - * This does not override the From field, but it has a higher significance. - * - * @param string $address - * @param string $name optional - * - * @return $this - */ - public function setSender($address, $name = null) - { - if (!is_array($address) && isset($name)) { - $address = array($address => $name); - } - - if (!$this->_setHeaderFieldModel('Sender', (array) $address)) { - $this->getHeaders()->addMailboxHeader('Sender', (array) $address); - } - - return $this; - } - - /** - * Get the sender of this message. - * - * @return string - */ - public function getSender() - { - return $this->_getHeaderFieldModel('Sender'); - } - - /** - * Add a From: address to this message. - * - * If $name is passed this name will be associated with the address. - * - * @param string $address - * @param string $name optional - * - * @return $this - */ - public function addFrom($address, $name = null) - { - $current = $this->getFrom(); - $current[$address] = $name; - - return $this->setFrom($current); - } - - /** - * Set the from address of this message. - * - * You may pass an array of addresses if this message is from multiple people. - * - * If $name is passed and the first parameter is a string, this name will be - * associated with the address. - * - * @param string|array $addresses - * @param string $name optional - * - * @return $this - */ - public function setFrom($addresses, $name = null) - { - if (!is_array($addresses) && isset($name)) { - $addresses = array($addresses => $name); - } - - if (!$this->_setHeaderFieldModel('From', (array) $addresses)) { - $this->getHeaders()->addMailboxHeader('From', (array) $addresses); - } - - return $this; - } - - /** - * Get the from address of this message. - * - * @return mixed - */ - public function getFrom() - { - return $this->_getHeaderFieldModel('From'); - } - - /** - * Add a Reply-To: address to this message. - * - * If $name is passed this name will be associated with the address. - * - * @param string $address - * @param string $name optional - * - * @return $this - */ - public function addReplyTo($address, $name = null) - { - $current = $this->getReplyTo(); - $current[$address] = $name; - - return $this->setReplyTo($current); - } - - /** - * Set the reply-to address of this message. - * - * You may pass an array of addresses if replies will go to multiple people. - * - * If $name is passed and the first parameter is a string, this name will be - * associated with the address. - * - * @param mixed $addresses - * @param string $name optional - * - * @return $this - */ - public function setReplyTo($addresses, $name = null) - { - if (!is_array($addresses) && isset($name)) { - $addresses = array($addresses => $name); - } - - if (!$this->_setHeaderFieldModel('Reply-To', (array) $addresses)) { - $this->getHeaders()->addMailboxHeader('Reply-To', (array) $addresses); - } - - return $this; - } - - /** - * Get the reply-to address of this message. - * - * @return string - */ - public function getReplyTo() - { - return $this->_getHeaderFieldModel('Reply-To'); - } - - /** - * Add a To: address to this message. - * - * If $name is passed this name will be associated with the address. - * - * @param string $address - * @param string $name optional - * - * @return $this - */ - public function addTo($address, $name = null) - { - $current = $this->getTo(); - $current[$address] = $name; - - return $this->setTo($current); - } - - /** - * Set the to addresses of this message. - * - * If multiple recipients will receive the message an array should be used. - * Example: array('receiver@domain.org', 'other@domain.org' => 'A name') - * - * If $name is passed and the first parameter is a string, this name will be - * associated with the address. - * - * @param mixed $addresses - * @param string $name optional - * - * @return $this - */ - public function setTo($addresses, $name = null) - { - if (!is_array($addresses) && isset($name)) { - $addresses = array($addresses => $name); - } - - if (!$this->_setHeaderFieldModel('To', (array) $addresses)) { - $this->getHeaders()->addMailboxHeader('To', (array) $addresses); - } - - return $this; - } - - /** - * Get the To addresses of this message. - * - * @return array - */ - public function getTo() - { - return $this->_getHeaderFieldModel('To'); - } - - /** - * Add a Cc: address to this message. - * - * If $name is passed this name will be associated with the address. - * - * @param string $address - * @param string $name optional - * - * @return $this - */ - public function addCc($address, $name = null) - { - $current = $this->getCc(); - $current[$address] = $name; - - return $this->setCc($current); - } - - /** - * Set the Cc addresses of this message. - * - * If $name is passed and the first parameter is a string, this name will be - * associated with the address. - * - * @param mixed $addresses - * @param string $name optional - * - * @return $this - */ - public function setCc($addresses, $name = null) - { - if (!is_array($addresses) && isset($name)) { - $addresses = array($addresses => $name); - } - - if (!$this->_setHeaderFieldModel('Cc', (array) $addresses)) { - $this->getHeaders()->addMailboxHeader('Cc', (array) $addresses); - } - - return $this; - } - - /** - * Get the Cc address of this message. - * - * @return array - */ - public function getCc() - { - return $this->_getHeaderFieldModel('Cc'); - } - - /** - * Add a Bcc: address to this message. - * - * If $name is passed this name will be associated with the address. - * - * @param string $address - * @param string $name optional - * - * @return $this - */ - public function addBcc($address, $name = null) - { - $current = $this->getBcc(); - $current[$address] = $name; - - return $this->setBcc($current); - } - - /** - * Set the Bcc addresses of this message. - * - * If $name is passed and the first parameter is a string, this name will be - * associated with the address. - * - * @param mixed $addresses - * @param string $name optional - * - * @return $this - */ - public function setBcc($addresses, $name = null) - { - if (!is_array($addresses) && isset($name)) { - $addresses = array($addresses => $name); - } - - if (!$this->_setHeaderFieldModel('Bcc', (array) $addresses)) { - $this->getHeaders()->addMailboxHeader('Bcc', (array) $addresses); - } - - return $this; - } - - /** - * Get the Bcc addresses of this message. - * - * @return array - */ - public function getBcc() - { - return $this->_getHeaderFieldModel('Bcc'); - } - - /** - * Set the priority of this message. - * - * The value is an integer where 1 is the highest priority and 5 is the lowest. - * - * @param int $priority - * - * @return $this - */ - public function setPriority($priority) - { - $priorityMap = array( - self::PRIORITY_HIGHEST => 'Highest', - self::PRIORITY_HIGH => 'High', - self::PRIORITY_NORMAL => 'Normal', - self::PRIORITY_LOW => 'Low', - self::PRIORITY_LOWEST => 'Lowest', - ); - $pMapKeys = array_keys($priorityMap); - if ($priority > max($pMapKeys)) { - $priority = max($pMapKeys); - } elseif ($priority < min($pMapKeys)) { - $priority = min($pMapKeys); - } - if (!$this->_setHeaderFieldModel('X-Priority', - sprintf('%d (%s)', $priority, $priorityMap[$priority]))) { - $this->getHeaders()->addTextHeader('X-Priority', - sprintf('%d (%s)', $priority, $priorityMap[$priority])); - } - - return $this; - } - - /** - * Get the priority of this message. - * - * The returned value is an integer where 1 is the highest priority and 5 - * is the lowest. - * - * @return int - */ - public function getPriority() - { - list($priority) = sscanf($this->_getHeaderFieldModel('X-Priority'), - '%[1-5]' - ); - - return isset($priority) ? $priority : 3; - } - - /** - * Ask for a delivery receipt from the recipient to be sent to $addresses. - * - * @param array $addresses - * - * @return $this - */ - public function setReadReceiptTo($addresses) - { - if (!$this->_setHeaderFieldModel('Disposition-Notification-To', $addresses)) { - $this->getHeaders() - ->addMailboxHeader('Disposition-Notification-To', $addresses); - } - - return $this; - } - - /** - * Get the addresses to which a read-receipt will be sent. - * - * @return string - */ - public function getReadReceiptTo() - { - return $this->_getHeaderFieldModel('Disposition-Notification-To'); - } - - /** - * Attach a {@link Swift_Mime_MimeEntity} such as an Attachment or MimePart. - * - * @param Swift_Mime_MimeEntity $entity - * - * @return $this - */ - public function attach(Swift_Mime_MimeEntity $entity) - { - $this->setChildren(array_merge($this->getChildren(), array($entity))); - - return $this; - } - - /** - * Remove an already attached entity. - * - * @param Swift_Mime_MimeEntity $entity - * - * @return $this - */ - public function detach(Swift_Mime_MimeEntity $entity) - { - $newChildren = array(); - foreach ($this->getChildren() as $child) { - if ($entity !== $child) { - $newChildren[] = $child; - } - } - $this->setChildren($newChildren); - - return $this; - } - - /** - * Attach a {@link Swift_Mime_MimeEntity} and return it's CID source. - * This method should be used when embedding images or other data in a message. - * - * @param Swift_Mime_MimeEntity $entity - * - * @return string - */ - public function embed(Swift_Mime_MimeEntity $entity) - { - $this->attach($entity); - - return 'cid:'.$entity->getId(); - } - - /** - * Get this message as a complete string. - * - * @return string - */ - public function toString() - { - if (count($children = $this->getChildren()) > 0 && $this->getBody() != '') { - $this->setChildren(array_merge(array($this->_becomeMimePart()), $children)); - $string = parent::toString(); - $this->setChildren($children); - } else { - $string = parent::toString(); - } - - return $string; - } - - /** - * Returns a string representation of this object. - * - * @see toString() - * - * @return string - */ - public function __toString() - { - return $this->toString(); - } - - /** - * Write this message to a {@link Swift_InputByteStream}. - * - * @param Swift_InputByteStream $is - */ - public function toByteStream(Swift_InputByteStream $is) - { - if (count($children = $this->getChildren()) > 0 && $this->getBody() != '') { - $this->setChildren(array_merge(array($this->_becomeMimePart()), $children)); - parent::toByteStream($is); - $this->setChildren($children); - } else { - parent::toByteStream($is); - } - } - - /** @see Swift_Mime_SimpleMimeEntity::_getIdField() */ - protected function _getIdField() - { - return 'Message-ID'; - } - - /** Turn the body of this message into a child of itself if needed */ - protected function _becomeMimePart() - { - $part = new parent($this->getHeaders()->newInstance(), $this->getEncoder(), - $this->_getCache(), $this->_getGrammar(), $this->_userCharset - ); - $part->setContentType($this->_userContentType); - $part->setBody($this->getBody()); - $part->setFormat($this->_userFormat); - $part->setDelSp($this->_userDelSp); - $part->_setNestingLevel($this->_getTopNestingLevel()); - - return $part; - } - - /** Get the highest nesting level nested inside this message */ - private function _getTopNestingLevel() - { - $highestLevel = $this->getNestingLevel(); - foreach ($this->getChildren() as $child) { - $childLevel = $child->getNestingLevel(); - if ($highestLevel < $childLevel) { - $highestLevel = $childLevel; - } - } - - return $highestLevel; - } -} diff --git a/tools/swift/classes/Swift/Mime/SimpleMimeEntity.php b/tools/swift/classes/Swift/Mime/SimpleMimeEntity.php deleted file mode 100644 index a13f1b23d..000000000 --- a/tools/swift/classes/Swift/Mime/SimpleMimeEntity.php +++ /dev/null @@ -1,846 +0,0 @@ - array(self::LEVEL_TOP, self::LEVEL_MIXED), - 'multipart/alternative' => array(self::LEVEL_MIXED, self::LEVEL_ALTERNATIVE), - 'multipart/related' => array(self::LEVEL_ALTERNATIVE, self::LEVEL_RELATED), - ); - - /** A set of filter rules to define what level an entity should be nested at */ - private $_compoundLevelFilters = array(); - - /** The nesting level of this entity */ - private $_nestingLevel = self::LEVEL_ALTERNATIVE; - - /** A KeyCache instance used during encoding and streaming */ - private $_cache; - - /** Direct descendants of this entity */ - private $_immediateChildren = array(); - - /** All descendants of this entity */ - private $_children = array(); - - /** The maximum line length of the body of this entity */ - private $_maxLineLength = 78; - - /** The order in which alternative mime types should appear */ - private $_alternativePartOrder = array( - 'text/plain' => 1, - 'text/html' => 2, - 'multipart/related' => 3, - ); - - /** The CID of this entity */ - private $_id; - - /** The key used for accessing the cache */ - private $_cacheKey; - - protected $_userContentType; - - /** - * Create a new SimpleMimeEntity with $headers, $encoder and $cache. - * - * @param Swift_Mime_HeaderSet $headers - * @param Swift_Mime_ContentEncoder $encoder - * @param Swift_KeyCache $cache - * @param Swift_Mime_Grammar $grammar - */ - public function __construct(Swift_Mime_HeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_Mime_Grammar $grammar) - { - $this->_cacheKey = md5(uniqid(getmypid().mt_rand(), true)); - $this->_cache = $cache; - $this->_headers = $headers; - $this->_grammar = $grammar; - $this->setEncoder($encoder); - $this->_headers->defineOrdering(array('Content-Type', 'Content-Transfer-Encoding')); - - // This array specifies that, when the entire MIME document contains - // $compoundLevel, then for each child within $level, if its Content-Type - // is $contentType then it should be treated as if it's level is - // $neededLevel instead. I tried to write that unambiguously! :-\ - // Data Structure: - // array ( - // $compoundLevel => array( - // $level => array( - // $contentType => $neededLevel - // ) - // ) - // ) - - $this->_compoundLevelFilters = array( - (self::LEVEL_ALTERNATIVE + self::LEVEL_RELATED) => array( - self::LEVEL_ALTERNATIVE => array( - 'text/plain' => self::LEVEL_ALTERNATIVE, - 'text/html' => self::LEVEL_RELATED, - ), - ), - ); - - $this->_id = $this->getRandomId(); - } - - /** - * Generate a new Content-ID or Message-ID for this MIME entity. - * - * @return string - */ - public function generateId() - { - $this->setId($this->getRandomId()); - - return $this->_id; - } - - /** - * Get the {@link Swift_Mime_HeaderSet} for this entity. - * - * @return Swift_Mime_HeaderSet - */ - public function getHeaders() - { - return $this->_headers; - } - - /** - * Get the nesting level of this entity. - * - * @see LEVEL_TOP, LEVEL_MIXED, LEVEL_RELATED, LEVEL_ALTERNATIVE - * - * @return int - */ - public function getNestingLevel() - { - return $this->_nestingLevel; - } - - /** - * Get the Content-type of this entity. - * - * @return string - */ - public function getContentType() - { - return $this->_getHeaderFieldModel('Content-Type'); - } - - /** - * Set the Content-type of this entity. - * - * @param string $type - * - * @return $this - */ - public function setContentType($type) - { - $this->_setContentTypeInHeaders($type); - // Keep track of the value so that if the content-type changes automatically - // due to added child entities, it can be restored if they are later removed - $this->_userContentType = $type; - - return $this; - } - - /** - * Get the CID of this entity. - * - * The CID will only be present in headers if a Content-ID header is present. - * - * @return string - */ - public function getId() - { - $tmp = (array) $this->_getHeaderFieldModel($this->_getIdField()); - - return $this->_headers->has($this->_getIdField()) ? current($tmp) : $this->_id; - } - - /** - * Set the CID of this entity. - * - * @param string $id - * - * @return $this - */ - public function setId($id) - { - if (!$this->_setHeaderFieldModel($this->_getIdField(), $id)) { - $this->_headers->addIdHeader($this->_getIdField(), $id); - } - $this->_id = $id; - - return $this; - } - - /** - * Get the description of this entity. - * - * This value comes from the Content-Description header if set. - * - * @return string - */ - public function getDescription() - { - return $this->_getHeaderFieldModel('Content-Description'); - } - - /** - * Set the description of this entity. - * - * This method sets a value in the Content-ID header. - * - * @param string $description - * - * @return $this - */ - public function setDescription($description) - { - if (!$this->_setHeaderFieldModel('Content-Description', $description)) { - $this->_headers->addTextHeader('Content-Description', $description); - } - - return $this; - } - - /** - * Get the maximum line length of the body of this entity. - * - * @return int - */ - public function getMaxLineLength() - { - return $this->_maxLineLength; - } - - /** - * Set the maximum line length of lines in this body. - * - * Though not enforced by the library, lines should not exceed 1000 chars. - * - * @param int $length - * - * @return $this - */ - public function setMaxLineLength($length) - { - $this->_maxLineLength = $length; - - return $this; - } - - /** - * Get all children added to this entity. - * - * @return Swift_Mime_MimeEntity[] - */ - public function getChildren() - { - return $this->_children; - } - - /** - * Set all children of this entity. - * - * @param Swift_Mime_MimeEntity[] $children - * @param int $compoundLevel For internal use only - * - * @return $this - */ - public function setChildren(array $children, $compoundLevel = null) - { - // TODO: Try to refactor this logic - - $compoundLevel = isset($compoundLevel) ? $compoundLevel : $this->_getCompoundLevel($children); - $immediateChildren = array(); - $grandchildren = array(); - $newContentType = $this->_userContentType; - - foreach ($children as $child) { - $level = $this->_getNeededChildLevel($child, $compoundLevel); - if (empty($immediateChildren)) { - //first iteration - $immediateChildren = array($child); - } else { - $nextLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel); - if ($nextLevel == $level) { - $immediateChildren[] = $child; - } elseif ($level < $nextLevel) { - // Re-assign immediateChildren to grandchildren - $grandchildren = array_merge($grandchildren, $immediateChildren); - // Set new children - $immediateChildren = array($child); - } else { - $grandchildren[] = $child; - } - } - } - - if ($immediateChildren) { - $lowestLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel); - - // Determine which composite media type is needed to accommodate the - // immediate children - foreach ($this->_compositeRanges as $mediaType => $range) { - if ($lowestLevel > $range[0] && $lowestLevel <= $range[1]) { - $newContentType = $mediaType; - - break; - } - } - - // Put any grandchildren in a subpart - if (!empty($grandchildren)) { - $subentity = $this->_createChild(); - $subentity->_setNestingLevel($lowestLevel); - $subentity->setChildren($grandchildren, $compoundLevel); - array_unshift($immediateChildren, $subentity); - } - } - - $this->_immediateChildren = $immediateChildren; - $this->_children = $children; - $this->_setContentTypeInHeaders($newContentType); - $this->_fixHeaders(); - $this->_sortChildren(); - - return $this; - } - - /** - * Get the body of this entity as a string. - * - * @return string - */ - public function getBody() - { - return $this->_body instanceof Swift_OutputByteStream ? $this->_readStream($this->_body) : $this->_body; - } - - /** - * Set the body of this entity, either as a string, or as an instance of - * {@link Swift_OutputByteStream}. - * - * @param mixed $body - * @param string $contentType optional - * - * @return $this - */ - public function setBody($body, $contentType = null) - { - if ($body !== $this->_body) { - $this->_clearCache(); - } - - $this->_body = $body; - if (isset($contentType)) { - $this->setContentType($contentType); - } - - return $this; - } - - /** - * Get the encoder used for the body of this entity. - * - * @return Swift_Mime_ContentEncoder - */ - public function getEncoder() - { - return $this->_encoder; - } - - /** - * Set the encoder used for the body of this entity. - * - * @param Swift_Mime_ContentEncoder $encoder - * - * @return $this - */ - public function setEncoder(Swift_Mime_ContentEncoder $encoder) - { - if ($encoder !== $this->_encoder) { - $this->_clearCache(); - } - - $this->_encoder = $encoder; - $this->_setEncoding($encoder->getName()); - $this->_notifyEncoderChanged($encoder); - - return $this; - } - - /** - * Get the boundary used to separate children in this entity. - * - * @return string - */ - public function getBoundary() - { - if (!isset($this->_boundary)) { - $this->_boundary = '_=_swift_v4_'.time().'_'.md5(getmypid().mt_rand().uniqid('', true)).'_=_'; - } - - return $this->_boundary; - } - - /** - * Set the boundary used to separate children in this entity. - * - * @param string $boundary - * - * @throws Swift_RfcComplianceException - * - * @return $this - */ - public function setBoundary($boundary) - { - $this->_assertValidBoundary($boundary); - $this->_boundary = $boundary; - - return $this; - } - - /** - * Receive notification that the charset of this entity, or a parent entity - * has changed. - * - * @param string $charset - */ - public function charsetChanged($charset) - { - $this->_notifyCharsetChanged($charset); - } - - /** - * Receive notification that the encoder of this entity or a parent entity - * has changed. - * - * @param Swift_Mime_ContentEncoder $encoder - */ - public function encoderChanged(Swift_Mime_ContentEncoder $encoder) - { - $this->_notifyEncoderChanged($encoder); - } - - /** - * Get this entire entity as a string. - * - * @return string - */ - public function toString() - { - $string = $this->_headers->toString(); - $string .= $this->_bodyToString(); - - return $string; - } - - /** - * Get this entire entity as a string. - * - * @return string - */ - protected function _bodyToString() - { - $string = ''; - - if (isset($this->_body) && empty($this->_immediateChildren)) { - if ($this->_cache->hasKey($this->_cacheKey, 'body')) { - $body = $this->_cache->getString($this->_cacheKey, 'body'); - } else { - $body = "\r\n".$this->_encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength()); - $this->_cache->setString($this->_cacheKey, 'body', $body, Swift_KeyCache::MODE_WRITE); - } - $string .= $body; - } - - if (!empty($this->_immediateChildren)) { - foreach ($this->_immediateChildren as $child) { - $string .= "\r\n\r\n--".$this->getBoundary()."\r\n"; - $string .= $child->toString(); - } - $string .= "\r\n\r\n--".$this->getBoundary()."--\r\n"; - } - - return $string; - } - - /** - * Returns a string representation of this object. - * - * @see toString() - * - * @return string - */ - public function __toString() - { - return $this->toString(); - } - - /** - * Write this entire entity to a {@see Swift_InputByteStream}. - * - * @param Swift_InputByteStream - */ - public function toByteStream(Swift_InputByteStream $is) - { - $is->write($this->_headers->toString()); - $is->commit(); - - $this->_bodyToByteStream($is); - } - - /** - * Write this entire entity to a {@link Swift_InputByteStream}. - * - * @param Swift_InputByteStream - */ - protected function _bodyToByteStream(Swift_InputByteStream $is) - { - if (empty($this->_immediateChildren)) { - if (isset($this->_body)) { - if ($this->_cache->hasKey($this->_cacheKey, 'body')) { - $this->_cache->exportToByteStream($this->_cacheKey, 'body', $is); - } else { - $cacheIs = $this->_cache->getInputByteStream($this->_cacheKey, 'body'); - if ($cacheIs) { - $is->bind($cacheIs); - } - - $is->write("\r\n"); - - if ($this->_body instanceof Swift_OutputByteStream) { - $this->_body->setReadPointer(0); - - $this->_encoder->encodeByteStream($this->_body, $is, 0, $this->getMaxLineLength()); - } else { - $is->write($this->_encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength())); - } - - if ($cacheIs) { - $is->unbind($cacheIs); - } - } - } - } - - if (!empty($this->_immediateChildren)) { - foreach ($this->_immediateChildren as $child) { - $is->write("\r\n\r\n--".$this->getBoundary()."\r\n"); - $child->toByteStream($is); - } - $is->write("\r\n\r\n--".$this->getBoundary()."--\r\n"); - } - } - - /** - * Get the name of the header that provides the ID of this entity. - */ - protected function _getIdField() - { - return 'Content-ID'; - } - - /** - * Get the model data (usually an array or a string) for $field. - */ - protected function _getHeaderFieldModel($field) - { - if ($this->_headers->has($field)) { - return $this->_headers->get($field)->getFieldBodyModel(); - } - } - - /** - * Set the model data for $field. - */ - protected function _setHeaderFieldModel($field, $model) - { - if ($this->_headers->has($field)) { - $this->_headers->get($field)->setFieldBodyModel($model); - - return true; - } - - return false; - } - - /** - * Get the parameter value of $parameter on $field header. - */ - protected function _getHeaderParameter($field, $parameter) - { - if ($this->_headers->has($field)) { - return $this->_headers->get($field)->getParameter($parameter); - } - } - - /** - * Set the parameter value of $parameter on $field header. - */ - protected function _setHeaderParameter($field, $parameter, $value) - { - if ($this->_headers->has($field)) { - $this->_headers->get($field)->setParameter($parameter, $value); - - return true; - } - - return false; - } - - /** - * Re-evaluate what content type and encoding should be used on this entity. - */ - protected function _fixHeaders() - { - if (count($this->_immediateChildren)) { - $this->_setHeaderParameter('Content-Type', 'boundary', - $this->getBoundary() - ); - $this->_headers->remove('Content-Transfer-Encoding'); - } else { - $this->_setHeaderParameter('Content-Type', 'boundary', null); - $this->_setEncoding($this->_encoder->getName()); - } - } - - /** - * Get the KeyCache used in this entity. - * - * @return Swift_KeyCache - */ - protected function _getCache() - { - return $this->_cache; - } - - /** - * Get the grammar used for validation. - * - * @return Swift_Mime_Grammar - */ - protected function _getGrammar() - { - return $this->_grammar; - } - - /** - * Empty the KeyCache for this entity. - */ - protected function _clearCache() - { - $this->_cache->clearKey($this->_cacheKey, 'body'); - } - - /** - * Returns a random Content-ID or Message-ID. - * - * @return string - */ - protected function getRandomId() - { - $idLeft = md5(getmypid().'.'.time().'.'.uniqid(mt_rand(), true)); - $idRight = !empty($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'swift.generated'; - $id = $idLeft.'@'.$idRight; - - try { - $this->_assertValidId($id); - } catch (Swift_RfcComplianceException $e) { - $id = $idLeft.'@swift.generated'; - } - - return $id; - } - - private function _readStream(Swift_OutputByteStream $os) - { - $string = ''; - while (false !== $bytes = $os->read(8192)) { - $string .= $bytes; - } - - $os->setReadPointer(0); - - return $string; - } - - private function _setEncoding($encoding) - { - if (!$this->_setHeaderFieldModel('Content-Transfer-Encoding', $encoding)) { - $this->_headers->addTextHeader('Content-Transfer-Encoding', $encoding); - } - } - - private function _assertValidBoundary($boundary) - { - if (!preg_match('/^[a-z0-9\'\(\)\+_\-,\.\/:=\?\ ]{0,69}[a-z0-9\'\(\)\+_\-,\.\/:=\?]$/Di', $boundary)) { - throw new Swift_RfcComplianceException('Mime boundary set is not RFC 2046 compliant.'); - } - } - - private function _setContentTypeInHeaders($type) - { - if (!$this->_setHeaderFieldModel('Content-Type', $type)) { - $this->_headers->addParameterizedHeader('Content-Type', $type); - } - } - - private function _setNestingLevel($level) - { - $this->_nestingLevel = $level; - } - - private function _getCompoundLevel($children) - { - $level = 0; - foreach ($children as $child) { - $level |= $child->getNestingLevel(); - } - - return $level; - } - - private function _getNeededChildLevel($child, $compoundLevel) - { - $filter = array(); - foreach ($this->_compoundLevelFilters as $bitmask => $rules) { - if (($compoundLevel & $bitmask) === $bitmask) { - $filter = $rules + $filter; - } - } - - $realLevel = $child->getNestingLevel(); - $lowercaseType = strtolower($child->getContentType()); - - if (isset($filter[$realLevel]) && isset($filter[$realLevel][$lowercaseType])) { - return $filter[$realLevel][$lowercaseType]; - } - - return $realLevel; - } - - private function _createChild() - { - return new self($this->_headers->newInstance(), $this->_encoder, $this->_cache, $this->_grammar); - } - - private function _notifyEncoderChanged(Swift_Mime_ContentEncoder $encoder) - { - foreach ($this->_immediateChildren as $child) { - $child->encoderChanged($encoder); - } - } - - private function _notifyCharsetChanged($charset) - { - $this->_encoder->charsetChanged($charset); - $this->_headers->charsetChanged($charset); - foreach ($this->_immediateChildren as $child) { - $child->charsetChanged($charset); - } - } - - private function _sortChildren() - { - $shouldSort = false; - foreach ($this->_immediateChildren as $child) { - // NOTE: This include alternative parts moved into a related part - if ($child->getNestingLevel() == self::LEVEL_ALTERNATIVE) { - $shouldSort = true; - break; - } - } - - // Sort in order of preference, if there is one - if ($shouldSort) { - // Group the messages by order of preference - $sorted = array(); - foreach ($this->_immediateChildren as $child) { - $type = $child->getContentType(); - $level = array_key_exists($type, $this->_alternativePartOrder) ? $this->_alternativePartOrder[$type] : max($this->_alternativePartOrder) + 1; - - if (empty($sorted[$level])) { - $sorted[$level] = array(); - } - - $sorted[$level][] = $child; - } - - ksort($sorted); - - $this->_immediateChildren = array_reduce($sorted, 'array_merge', array()); - } - } - - /** - * Empties it's own contents from the cache. - */ - public function __destruct() - { - if ($this->_cache instanceof Swift_KeyCache) { - $this->_cache->clearAll($this->_cacheKey); - } - } - - /** - * Throws an Exception if the id passed does not comply with RFC 2822. - * - * @param string $id - * - * @throws Swift_RfcComplianceException - */ - private function _assertValidId($id) - { - if (!preg_match('/^'.$this->_grammar->getDefinition('id-left').'@'.$this->_grammar->getDefinition('id-right').'$/D', $id)) { - throw new Swift_RfcComplianceException('Invalid ID given <'.$id.'>'); - } - } - - /** - * Make a deep copy of object. - */ - public function __clone() - { - $this->_headers = clone $this->_headers; - $this->_encoder = clone $this->_encoder; - $this->_cacheKey = md5(uniqid(getmypid().mt_rand(), true)); - $children = array(); - foreach ($this->_children as $pos => $child) { - $children[$pos] = clone $child; - } - $this->setChildren($children); - } -} diff --git a/tools/swift/classes/Swift/MimePart.php b/tools/swift/classes/Swift/MimePart.php deleted file mode 100644 index 525b7ec8e..000000000 --- a/tools/swift/classes/Swift/MimePart.php +++ /dev/null @@ -1,59 +0,0 @@ -createDependenciesFor('mime.part') - ); - - if (!isset($charset)) { - $charset = Swift_DependencyContainer::getInstance() - ->lookup('properties.charset'); - } - $this->setBody($body); - $this->setCharset($charset); - if ($contentType) { - $this->setContentType($contentType); - } - } - - /** - * Create a new MimePart. - * - * @param string $body - * @param string $contentType - * @param string $charset - * - * @return self - */ - public static function newInstance($body = null, $contentType = null, $charset = null) - { - return new self($body, $contentType, $charset); - } -} diff --git a/tools/swift/classes/Swift/NullTransport.php b/tools/swift/classes/Swift/NullTransport.php deleted file mode 100644 index ddde335c5..000000000 --- a/tools/swift/classes/Swift/NullTransport.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Pretends messages have been sent, but just ignores them. - * - * @author Fabien Potencier - */ -class Swift_NullTransport extends Swift_Transport_NullTransport -{ - public function __construct() - { - call_user_func_array( - array($this, 'Swift_Transport_NullTransport::__construct'), - Swift_DependencyContainer::getInstance() - ->createDependenciesFor('transport.null') - ); - } - - /** - * Create a new NullTransport instance. - * - * @return self - */ - public static function newInstance() - { - return new self(); - } -} diff --git a/tools/swift/classes/Swift/OutputByteStream.php b/tools/swift/classes/Swift/OutputByteStream.php deleted file mode 100644 index 1f26f9be5..000000000 --- a/tools/swift/classes/Swift/OutputByteStream.php +++ /dev/null @@ -1,46 +0,0 @@ -setThreshold($threshold); - $this->setSleepTime($sleep); - $this->_sleeper = $sleeper; - } - - /** - * Set the number of emails to send before restarting. - * - * @param int $threshold - */ - public function setThreshold($threshold) - { - $this->_threshold = $threshold; - } - - /** - * Get the number of emails to send before restarting. - * - * @return int - */ - public function getThreshold() - { - return $this->_threshold; - } - - /** - * Set the number of seconds to sleep for during a restart. - * - * @param int $sleep time - */ - public function setSleepTime($sleep) - { - $this->_sleep = $sleep; - } - - /** - * Get the number of seconds to sleep for during a restart. - * - * @return int - */ - public function getSleepTime() - { - return $this->_sleep; - } - - /** - * Invoked immediately before the Message is sent. - * - * @param Swift_Events_SendEvent $evt - */ - public function beforeSendPerformed(Swift_Events_SendEvent $evt) - { - } - - /** - * Invoked immediately after the Message is sent. - * - * @param Swift_Events_SendEvent $evt - */ - public function sendPerformed(Swift_Events_SendEvent $evt) - { - ++$this->_counter; - if ($this->_counter >= $this->_threshold) { - $transport = $evt->getTransport(); - $transport->stop(); - if ($this->_sleep) { - $this->sleep($this->_sleep); - } - $transport->start(); - $this->_counter = 0; - } - } - - /** - * Sleep for $seconds. - * - * @param int $seconds - */ - public function sleep($seconds) - { - if (isset($this->_sleeper)) { - $this->_sleeper->sleep($seconds); - } else { - sleep($seconds); - } - } -} diff --git a/tools/swift/classes/Swift/Plugins/BandwidthMonitorPlugin.php b/tools/swift/classes/Swift/Plugins/BandwidthMonitorPlugin.php deleted file mode 100644 index f7e18d0eb..000000000 --- a/tools/swift/classes/Swift/Plugins/BandwidthMonitorPlugin.php +++ /dev/null @@ -1,164 +0,0 @@ -getMessage(); - $message->toByteStream($this); - } - - /** - * Invoked immediately following a command being sent. - * - * @param Swift_Events_CommandEvent $evt - */ - public function commandSent(Swift_Events_CommandEvent $evt) - { - $command = $evt->getCommand(); - $this->_out += strlen($command); - } - - /** - * Invoked immediately following a response coming back. - * - * @param Swift_Events_ResponseEvent $evt - */ - public function responseReceived(Swift_Events_ResponseEvent $evt) - { - $response = $evt->getResponse(); - $this->_in += strlen($response); - } - - /** - * Called when a message is sent so that the outgoing counter can be increased. - * - * @param string $bytes - */ - public function write($bytes) - { - $this->_out += strlen($bytes); - foreach ($this->_mirrors as $stream) { - $stream->write($bytes); - } - } - - /** - * Not used. - */ - public function commit() - { - } - - /** - * Attach $is to this stream. - * - * The stream acts as an observer, receiving all data that is written. - * All {@link write()} and {@link flushBuffers()} operations will be mirrored. - * - * @param Swift_InputByteStream $is - */ - public function bind(Swift_InputByteStream $is) - { - $this->_mirrors[] = $is; - } - - /** - * Remove an already bound stream. - * - * If $is is not bound, no errors will be raised. - * If the stream currently has any buffered data it will be written to $is - * before unbinding occurs. - * - * @param Swift_InputByteStream $is - */ - public function unbind(Swift_InputByteStream $is) - { - foreach ($this->_mirrors as $k => $stream) { - if ($is === $stream) { - unset($this->_mirrors[$k]); - } - } - } - - /** - * Not used. - */ - public function flushBuffers() - { - foreach ($this->_mirrors as $stream) { - $stream->flushBuffers(); - } - } - - /** - * Get the total number of bytes sent to the server. - * - * @return int - */ - public function getBytesOut() - { - return $this->_out; - } - - /** - * Get the total number of bytes received from the server. - * - * @return int - */ - public function getBytesIn() - { - return $this->_in; - } - - /** - * Reset the internal counters to zero. - */ - public function reset() - { - $this->_out = 0; - $this->_in = 0; - } -} diff --git a/tools/swift/classes/Swift/Plugins/Decorator/Replacements.php b/tools/swift/classes/Swift/Plugins/Decorator/Replacements.php deleted file mode 100644 index 9f9f08b56..000000000 --- a/tools/swift/classes/Swift/Plugins/Decorator/Replacements.php +++ /dev/null @@ -1,31 +0,0 @@ - - * $replacements = array( - * "address1@domain.tld" => array("{a}" => "b", "{c}" => "d"), - * "address2@domain.tld" => array("{a}" => "x", "{c}" => "y") - * ) - * - * - * When using an instance of {@link Swift_Plugins_Decorator_Replacements}, - * the object should return just the array of replacements for the address - * given to {@link Swift_Plugins_Decorator_Replacements::getReplacementsFor()}. - * - * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements - */ - public function __construct($replacements) - { - $this->setReplacements($replacements); - } - - /** - * Sets replacements. - * - * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements - * - * @see __construct() - */ - public function setReplacements($replacements) - { - if (!($replacements instanceof Swift_Plugins_Decorator_Replacements)) { - $this->_replacements = (array) $replacements; - } else { - $this->_replacements = $replacements; - } - } - - /** - * Invoked immediately before the Message is sent. - * - * @param Swift_Events_SendEvent $evt - */ - public function beforeSendPerformed(Swift_Events_SendEvent $evt) - { - $message = $evt->getMessage(); - $this->_restoreMessage($message); - $to = array_keys($message->getTo()); - $address = array_shift($to); - if ($replacements = $this->getReplacementsFor($address)) { - $body = $message->getBody(); - $search = array_keys($replacements); - $replace = array_values($replacements); - $bodyReplaced = str_replace( - $search, $replace, $body - ); - if ($body != $bodyReplaced) { - $this->_originalBody = $body; - $message->setBody($bodyReplaced); - } - - foreach ($message->getHeaders()->getAll() as $header) { - $body = $header->getFieldBodyModel(); - $count = 0; - if (is_array($body)) { - $bodyReplaced = array(); - foreach ($body as $key => $value) { - $count1 = 0; - $count2 = 0; - $key = is_string($key) ? str_replace($search, $replace, $key, $count1) : $key; - $value = is_string($value) ? str_replace($search, $replace, $value, $count2) : $value; - $bodyReplaced[$key] = $value; - - if (!$count && ($count1 || $count2)) { - $count = 1; - } - } - } else { - $bodyReplaced = str_replace($search, $replace, $body, $count); - } - - if ($count) { - $this->_originalHeaders[$header->getFieldName()] = $body; - $header->setFieldBodyModel($bodyReplaced); - } - } - - $children = (array) $message->getChildren(); - foreach ($children as $child) { - list($type) = sscanf($child->getContentType(), '%[^/]/%s'); - if ('text' == $type) { - $body = $child->getBody(); - $bodyReplaced = str_replace( - $search, $replace, $body - ); - if ($body != $bodyReplaced) { - $child->setBody($bodyReplaced); - $this->_originalChildBodies[$child->getId()] = $body; - } - } - } - $this->_lastMessage = $message; - } - } - - /** - * Find a map of replacements for the address. - * - * If this plugin was provided with a delegate instance of - * {@link Swift_Plugins_Decorator_Replacements} then the call will be - * delegated to it. Otherwise, it will attempt to find the replacements - * from the array provided in the constructor. - * - * If no replacements can be found, an empty value (NULL) is returned. - * - * @param string $address - * - * @return array - */ - public function getReplacementsFor($address) - { - if ($this->_replacements instanceof Swift_Plugins_Decorator_Replacements) { - return $this->_replacements->getReplacementsFor($address); - } - - return isset($this->_replacements[$address]) ? $this->_replacements[$address] : null; - } - - /** - * Invoked immediately after the Message is sent. - * - * @param Swift_Events_SendEvent $evt - */ - public function sendPerformed(Swift_Events_SendEvent $evt) - { - $this->_restoreMessage($evt->getMessage()); - } - - /** Restore a changed message back to its original state */ - private function _restoreMessage(Swift_Mime_Message $message) - { - if ($this->_lastMessage === $message) { - if (isset($this->_originalBody)) { - $message->setBody($this->_originalBody); - $this->_originalBody = null; - } - if (!empty($this->_originalHeaders)) { - foreach ($message->getHeaders()->getAll() as $header) { - if (array_key_exists($header->getFieldName(), $this->_originalHeaders)) { - $header->setFieldBodyModel($this->_originalHeaders[$header->getFieldName()]); - } - } - $this->_originalHeaders = array(); - } - if (!empty($this->_originalChildBodies)) { - $children = (array) $message->getChildren(); - foreach ($children as $child) { - $id = $child->getId(); - if (array_key_exists($id, $this->_originalChildBodies)) { - $child->setBody($this->_originalChildBodies[$id]); - } - } - $this->_originalChildBodies = array(); - } - $this->_lastMessage = null; - } - } -} diff --git a/tools/swift/classes/Swift/Plugins/ImpersonatePlugin.php b/tools/swift/classes/Swift/Plugins/ImpersonatePlugin.php deleted file mode 100644 index 583444053..000000000 --- a/tools/swift/classes/Swift/Plugins/ImpersonatePlugin.php +++ /dev/null @@ -1,69 +0,0 @@ -_sender = $sender; - } - - /** - * Invoked immediately before the Message is sent. - * - * @param Swift_Events_SendEvent $evt - */ - public function beforeSendPerformed(Swift_Events_SendEvent $evt) - { - $message = $evt->getMessage(); - $headers = $message->getHeaders(); - - // save current recipients - $headers->addPathHeader('X-Swift-Return-Path', $message->getReturnPath()); - - // replace them with the one to send to - $message->setReturnPath($this->_sender); - } - - /** - * Invoked immediately after the Message is sent. - * - * @param Swift_Events_SendEvent $evt - */ - public function sendPerformed(Swift_Events_SendEvent $evt) - { - $message = $evt->getMessage(); - - // restore original headers - $headers = $message->getHeaders(); - - if ($headers->has('X-Swift-Return-Path')) { - $message->setReturnPath($headers->get('X-Swift-Return-Path')->getAddress()); - $headers->removeAll('X-Swift-Return-Path'); - } - } -} diff --git a/tools/swift/classes/Swift/Plugins/Logger.php b/tools/swift/classes/Swift/Plugins/Logger.php deleted file mode 100644 index d9bce8935..000000000 --- a/tools/swift/classes/Swift/Plugins/Logger.php +++ /dev/null @@ -1,36 +0,0 @@ -_logger = $logger; - } - - /** - * Add a log entry. - * - * @param string $entry - */ - public function add($entry) - { - $this->_logger->add($entry); - } - - /** - * Clear the log contents. - */ - public function clear() - { - $this->_logger->clear(); - } - - /** - * Get this log as a string. - * - * @return string - */ - public function dump() - { - return $this->_logger->dump(); - } - - /** - * Invoked immediately following a command being sent. - * - * @param Swift_Events_CommandEvent $evt - */ - public function commandSent(Swift_Events_CommandEvent $evt) - { - $command = $evt->getCommand(); - $this->_logger->add(sprintf('>> %s', $command)); - } - - /** - * Invoked immediately following a response coming back. - * - * @param Swift_Events_ResponseEvent $evt - */ - public function responseReceived(Swift_Events_ResponseEvent $evt) - { - $response = $evt->getResponse(); - $this->_logger->add(sprintf('<< %s', $response)); - } - - /** - * Invoked just before a Transport is started. - * - * @param Swift_Events_TransportChangeEvent $evt - */ - public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt) - { - $transportName = get_class($evt->getSource()); - $this->_logger->add(sprintf('++ Starting %s', $transportName)); - } - - /** - * Invoked immediately after the Transport is started. - * - * @param Swift_Events_TransportChangeEvent $evt - */ - public function transportStarted(Swift_Events_TransportChangeEvent $evt) - { - $transportName = get_class($evt->getSource()); - $this->_logger->add(sprintf('++ %s started', $transportName)); - } - - /** - * Invoked just before a Transport is stopped. - * - * @param Swift_Events_TransportChangeEvent $evt - */ - public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt) - { - $transportName = get_class($evt->getSource()); - $this->_logger->add(sprintf('++ Stopping %s', $transportName)); - } - - /** - * Invoked immediately after the Transport is stopped. - * - * @param Swift_Events_TransportChangeEvent $evt - */ - public function transportStopped(Swift_Events_TransportChangeEvent $evt) - { - $transportName = get_class($evt->getSource()); - $this->_logger->add(sprintf('++ %s stopped', $transportName)); - } - - /** - * Invoked as a TransportException is thrown in the Transport system. - * - * @param Swift_Events_TransportExceptionEvent $evt - */ - public function exceptionThrown(Swift_Events_TransportExceptionEvent $evt) - { - $e = $evt->getException(); - $message = $e->getMessage(); - $code = $e->getCode(); - $this->_logger->add(sprintf('!! %s (code: %s)', $message, $code)); - $message .= PHP_EOL; - $message .= 'Log data:'.PHP_EOL; - $message .= $this->_logger->dump(); - $evt->cancelBubble(); - throw new Swift_TransportException($message, $code, $e->getPrevious()); - } -} diff --git a/tools/swift/classes/Swift/Plugins/Loggers/ArrayLogger.php b/tools/swift/classes/Swift/Plugins/Loggers/ArrayLogger.php deleted file mode 100644 index 865bb0aa3..000000000 --- a/tools/swift/classes/Swift/Plugins/Loggers/ArrayLogger.php +++ /dev/null @@ -1,72 +0,0 @@ -_size = $size; - } - - /** - * Add a log entry. - * - * @param string $entry - */ - public function add($entry) - { - $this->_log[] = $entry; - while (count($this->_log) > $this->_size) { - array_shift($this->_log); - } - } - - /** - * Clear the log contents. - */ - public function clear() - { - $this->_log = array(); - } - - /** - * Get this log as a string. - * - * @return string - */ - public function dump() - { - return implode(PHP_EOL, $this->_log); - } -} diff --git a/tools/swift/classes/Swift/Plugins/Loggers/EchoLogger.php b/tools/swift/classes/Swift/Plugins/Loggers/EchoLogger.php deleted file mode 100644 index 3583297ab..000000000 --- a/tools/swift/classes/Swift/Plugins/Loggers/EchoLogger.php +++ /dev/null @@ -1,58 +0,0 @@ -_isHtml = $isHtml; - } - - /** - * Add a log entry. - * - * @param string $entry - */ - public function add($entry) - { - if ($this->_isHtml) { - printf('%s%s%s', htmlspecialchars($entry, ENT_QUOTES), '
', PHP_EOL); - } else { - printf('%s%s', $entry, PHP_EOL); - } - } - - /** - * Not implemented. - */ - public function clear() - { - } - - /** - * Not implemented. - */ - public function dump() - { - } -} diff --git a/tools/swift/classes/Swift/Plugins/MessageLogger.php b/tools/swift/classes/Swift/Plugins/MessageLogger.php deleted file mode 100644 index 5ff1d9321..000000000 --- a/tools/swift/classes/Swift/Plugins/MessageLogger.php +++ /dev/null @@ -1,74 +0,0 @@ -messages = array(); - } - - /** - * Get the message list. - * - * @return Swift_Mime_Message[] - */ - public function getMessages() - { - return $this->messages; - } - - /** - * Get the message count. - * - * @return int count - */ - public function countMessages() - { - return count($this->messages); - } - - /** - * Empty the message list. - */ - public function clear() - { - $this->messages = array(); - } - - /** - * Invoked immediately before the Message is sent. - * - * @param Swift_Events_SendEvent $evt - */ - public function beforeSendPerformed(Swift_Events_SendEvent $evt) - { - $this->messages[] = clone $evt->getMessage(); - } - - /** - * Invoked immediately after the Message is sent. - * - * @param Swift_Events_SendEvent $evt - */ - public function sendPerformed(Swift_Events_SendEvent $evt) - { - } -} diff --git a/tools/swift/classes/Swift/Plugins/Pop/Pop3Connection.php b/tools/swift/classes/Swift/Plugins/Pop/Pop3Connection.php deleted file mode 100644 index fb99e4c94..000000000 --- a/tools/swift/classes/Swift/Plugins/Pop/Pop3Connection.php +++ /dev/null @@ -1,31 +0,0 @@ -_host = $host; - $this->_port = $port; - $this->_crypto = $crypto; - } - - /** - * Create a new PopBeforeSmtpPlugin for $host and $port. - * - * @param string $host - * @param int $port - * @param string $crypto as "tls" or "ssl" - * - * @return self - */ - public static function newInstance($host, $port = 110, $crypto = null) - { - return new self($host, $port, $crypto); - } - - /** - * Set a Pop3Connection to delegate to instead of connecting directly. - * - * @param Swift_Plugins_Pop_Pop3Connection $connection - * - * @return $this - */ - public function setConnection(Swift_Plugins_Pop_Pop3Connection $connection) - { - $this->_connection = $connection; - - return $this; - } - - /** - * Bind this plugin to a specific SMTP transport instance. - * - * @param Swift_Transport - */ - public function bindSmtp(Swift_Transport $smtp) - { - $this->_transport = $smtp; - } - - /** - * Set the connection timeout in seconds (default 10). - * - * @param int $timeout - * - * @return $this - */ - public function setTimeout($timeout) - { - $this->_timeout = (int) $timeout; - - return $this; - } - - /** - * Set the username to use when connecting (if needed). - * - * @param string $username - * - * @return $this - */ - public function setUsername($username) - { - $this->_username = $username; - - return $this; - } - - /** - * Set the password to use when connecting (if needed). - * - * @param string $password - * - * @return $this - */ - public function setPassword($password) - { - $this->_password = $password; - - return $this; - } - - /** - * Connect to the POP3 host and authenticate. - * - * @throws Swift_Plugins_Pop_Pop3Exception if connection fails - */ - public function connect() - { - if (isset($this->_connection)) { - $this->_connection->connect(); - } else { - if (!isset($this->_socket)) { - if (!$socket = fsockopen( - $this->_getHostString(), $this->_port, $errno, $errstr, $this->_timeout)) { - throw new Swift_Plugins_Pop_Pop3Exception( - sprintf('Failed to connect to POP3 host [%s]: %s', $this->_host, $errstr) - ); - } - $this->_socket = $socket; - - if (false === $greeting = fgets($this->_socket)) { - throw new Swift_Plugins_Pop_Pop3Exception( - sprintf('Failed to connect to POP3 host [%s]', trim($greeting)) - ); - } - - $this->_assertOk($greeting); - - if ($this->_username) { - $this->_command(sprintf("USER %s\r\n", $this->_username)); - $this->_command(sprintf("PASS %s\r\n", $this->_password)); - } - } - } - } - - /** - * Disconnect from the POP3 host. - */ - public function disconnect() - { - if (isset($this->_connection)) { - $this->_connection->disconnect(); - } else { - $this->_command("QUIT\r\n"); - if (!fclose($this->_socket)) { - throw new Swift_Plugins_Pop_Pop3Exception( - sprintf('POP3 host [%s] connection could not be stopped', $this->_host) - ); - } - $this->_socket = null; - } - } - - /** - * Invoked just before a Transport is started. - * - * @param Swift_Events_TransportChangeEvent $evt - */ - public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt) - { - if (isset($this->_transport)) { - if ($this->_transport !== $evt->getTransport()) { - return; - } - } - - $this->connect(); - $this->disconnect(); - } - - /** - * Not used. - */ - public function transportStarted(Swift_Events_TransportChangeEvent $evt) - { - } - - /** - * Not used. - */ - public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt) - { - } - - /** - * Not used. - */ - public function transportStopped(Swift_Events_TransportChangeEvent $evt) - { - } - - private function _command($command) - { - if (!fwrite($this->_socket, $command)) { - throw new Swift_Plugins_Pop_Pop3Exception( - sprintf('Failed to write command [%s] to POP3 host', trim($command)) - ); - } - - if (false === $response = fgets($this->_socket)) { - throw new Swift_Plugins_Pop_Pop3Exception( - sprintf('Failed to read from POP3 host after command [%s]', trim($command)) - ); - } - - $this->_assertOk($response); - - return $response; - } - - private function _assertOk($response) - { - if (substr($response, 0, 3) != '+OK') { - throw new Swift_Plugins_Pop_Pop3Exception( - sprintf('POP3 command failed [%s]', trim($response)) - ); - } - } - - private function _getHostString() - { - $host = $this->_host; - switch (strtolower($this->_crypto)) { - case 'ssl': - $host = 'ssl://'.$host; - break; - - case 'tls': - $host = 'tls://'.$host; - break; - } - - return $host; - } -} diff --git a/tools/swift/classes/Swift/Plugins/RedirectingPlugin.php b/tools/swift/classes/Swift/Plugins/RedirectingPlugin.php deleted file mode 100644 index c3a1f8685..000000000 --- a/tools/swift/classes/Swift/Plugins/RedirectingPlugin.php +++ /dev/null @@ -1,213 +0,0 @@ -_recipient = $recipient; - $this->_whitelist = $whitelist; - } - - /** - * Set the recipient of all messages. - * - * @param mixed $recipient - */ - public function setRecipient($recipient) - { - $this->_recipient = $recipient; - } - - /** - * Get the recipient of all messages. - * - * @return mixed - */ - public function getRecipient() - { - return $this->_recipient; - } - - /** - * Set a list of regular expressions to whitelist certain recipients. - * - * @param array $whitelist - */ - public function setWhitelist(array $whitelist) - { - $this->_whitelist = $whitelist; - } - - /** - * Get the whitelist. - * - * @return array - */ - public function getWhitelist() - { - return $this->_whitelist; - } - - /** - * Invoked immediately before the Message is sent. - * - * @param Swift_Events_SendEvent $evt - */ - public function beforeSendPerformed(Swift_Events_SendEvent $evt) - { - $message = $evt->getMessage(); - $headers = $message->getHeaders(); - - // conditionally save current recipients - - if ($headers->has('to')) { - $headers->addMailboxHeader('X-Swift-To', $message->getTo()); - } - - if ($headers->has('cc')) { - $headers->addMailboxHeader('X-Swift-Cc', $message->getCc()); - } - - if ($headers->has('bcc')) { - $headers->addMailboxHeader('X-Swift-Bcc', $message->getBcc()); - } - - // Filter remaining headers against whitelist - $this->_filterHeaderSet($headers, 'To'); - $this->_filterHeaderSet($headers, 'Cc'); - $this->_filterHeaderSet($headers, 'Bcc'); - - // Add each hard coded recipient - $to = $message->getTo(); - if (null === $to) { - $to = array(); - } - - foreach ((array) $this->_recipient as $recipient) { - if (!array_key_exists($recipient, $to)) { - $message->addTo($recipient); - } - } - } - - /** - * Filter header set against a whitelist of regular expressions. - * - * @param Swift_Mime_HeaderSet $headerSet - * @param string $type - */ - private function _filterHeaderSet(Swift_Mime_HeaderSet $headerSet, $type) - { - foreach ($headerSet->getAll($type) as $headers) { - $headers->setNameAddresses($this->_filterNameAddresses($headers->getNameAddresses())); - } - } - - /** - * Filtered list of addresses => name pairs. - * - * @param array $recipients - * - * @return array - */ - private function _filterNameAddresses(array $recipients) - { - $filtered = array(); - - foreach ($recipients as $address => $name) { - if ($this->_isWhitelisted($address)) { - $filtered[$address] = $name; - } - } - - return $filtered; - } - - /** - * Matches address against whitelist of regular expressions. - * - * @param $recipient - * - * @return bool - */ - protected function _isWhitelisted($recipient) - { - if (in_array($recipient, (array) $this->_recipient)) { - return true; - } - - foreach ($this->_whitelist as $pattern) { - if (preg_match($pattern, $recipient)) { - return true; - } - } - - return false; - } - - /** - * Invoked immediately after the Message is sent. - * - * @param Swift_Events_SendEvent $evt - */ - public function sendPerformed(Swift_Events_SendEvent $evt) - { - $this->_restoreMessage($evt->getMessage()); - } - - private function _restoreMessage(Swift_Mime_Message $message) - { - // restore original headers - $headers = $message->getHeaders(); - - if ($headers->has('X-Swift-To')) { - $message->setTo($headers->get('X-Swift-To')->getNameAddresses()); - $headers->removeAll('X-Swift-To'); - } else { - $message->setTo(null); - } - - if ($headers->has('X-Swift-Cc')) { - $message->setCc($headers->get('X-Swift-Cc')->getNameAddresses()); - $headers->removeAll('X-Swift-Cc'); - } - - if ($headers->has('X-Swift-Bcc')) { - $message->setBcc($headers->get('X-Swift-Bcc')->getNameAddresses()); - $headers->removeAll('X-Swift-Bcc'); - } - } -} diff --git a/tools/swift/classes/Swift/Plugins/Reporter.php b/tools/swift/classes/Swift/Plugins/Reporter.php deleted file mode 100644 index 0f21b7d60..000000000 --- a/tools/swift/classes/Swift/Plugins/Reporter.php +++ /dev/null @@ -1,32 +0,0 @@ -_reporter = $reporter; - } - - /** - * Not used. - */ - public function beforeSendPerformed(Swift_Events_SendEvent $evt) - { - } - - /** - * Invoked immediately after the Message is sent. - * - * @param Swift_Events_SendEvent $evt - */ - public function sendPerformed(Swift_Events_SendEvent $evt) - { - $message = $evt->getMessage(); - $failures = array_flip($evt->getFailedRecipients()); - foreach ((array) $message->getTo() as $address => $null) { - $this->_reporter->notify($message, $address, array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS); - } - foreach ((array) $message->getCc() as $address => $null) { - $this->_reporter->notify($message, $address, array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS); - } - foreach ((array) $message->getBcc() as $address => $null) { - $this->_reporter->notify($message, $address, array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS); - } - } -} diff --git a/tools/swift/classes/Swift/Plugins/Reporters/HitReporter.php b/tools/swift/classes/Swift/Plugins/Reporters/HitReporter.php deleted file mode 100644 index cad9d168e..000000000 --- a/tools/swift/classes/Swift/Plugins/Reporters/HitReporter.php +++ /dev/null @@ -1,59 +0,0 @@ -_failures_cache[$address])) { - $this->_failures[] = $address; - $this->_failures_cache[$address] = true; - } - } - - /** - * Get an array of addresses for which delivery failed. - * - * @return array - */ - public function getFailedRecipients() - { - return $this->_failures; - } - - /** - * Clear the buffer (empty the list). - */ - public function clear() - { - $this->_failures = $this->_failures_cache = array(); - } -} diff --git a/tools/swift/classes/Swift/Plugins/Reporters/HtmlReporter.php b/tools/swift/classes/Swift/Plugins/Reporters/HtmlReporter.php deleted file mode 100644 index c62593557..000000000 --- a/tools/swift/classes/Swift/Plugins/Reporters/HtmlReporter.php +++ /dev/null @@ -1,39 +0,0 @@ -'.PHP_EOL; - echo 'PASS '.$address.PHP_EOL; - echo ''.PHP_EOL; - flush(); - } else { - echo '
'.PHP_EOL; - echo 'FAIL '.$address.PHP_EOL; - echo '
'.PHP_EOL; - flush(); - } - } -} diff --git a/tools/swift/classes/Swift/Plugins/Sleeper.php b/tools/swift/classes/Swift/Plugins/Sleeper.php deleted file mode 100644 index 595c0f603..000000000 --- a/tools/swift/classes/Swift/Plugins/Sleeper.php +++ /dev/null @@ -1,24 +0,0 @@ -_rate = $rate; - $this->_mode = $mode; - $this->_sleeper = $sleeper; - $this->_timer = $timer; - } - - /** - * Invoked immediately before the Message is sent. - * - * @param Swift_Events_SendEvent $evt - */ - public function beforeSendPerformed(Swift_Events_SendEvent $evt) - { - $time = $this->getTimestamp(); - if (!isset($this->_start)) { - $this->_start = $time; - } - $duration = $time - $this->_start; - - switch ($this->_mode) { - case self::BYTES_PER_MINUTE: - $sleep = $this->_throttleBytesPerMinute($duration); - break; - case self::MESSAGES_PER_SECOND: - $sleep = $this->_throttleMessagesPerSecond($duration); - break; - case self::MESSAGES_PER_MINUTE: - $sleep = $this->_throttleMessagesPerMinute($duration); - break; - default: - $sleep = 0; - break; - } - - if ($sleep > 0) { - $this->sleep($sleep); - } - } - - /** - * Invoked when a Message is sent. - * - * @param Swift_Events_SendEvent $evt - */ - public function sendPerformed(Swift_Events_SendEvent $evt) - { - parent::sendPerformed($evt); - ++$this->_messages; - } - - /** - * Sleep for $seconds. - * - * @param int $seconds - */ - public function sleep($seconds) - { - if (isset($this->_sleeper)) { - $this->_sleeper->sleep($seconds); - } else { - sleep($seconds); - } - } - - /** - * Get the current UNIX timestamp. - * - * @return int - */ - public function getTimestamp() - { - if (isset($this->_timer)) { - return $this->_timer->getTimestamp(); - } - - return time(); - } - - /** - * Get a number of seconds to sleep for. - * - * @param int $timePassed - * - * @return int - */ - private function _throttleBytesPerMinute($timePassed) - { - $expectedDuration = $this->getBytesOut() / ($this->_rate / 60); - - return (int) ceil($expectedDuration - $timePassed); - } - - /** - * Get a number of seconds to sleep for. - * - * @param int $timePassed - * - * @return int - */ - private function _throttleMessagesPerSecond($timePassed) - { - $expectedDuration = $this->_messages / ($this->_rate); - - return (int) ceil($expectedDuration - $timePassed); - } - - /** - * Get a number of seconds to sleep for. - * - * @param int $timePassed - * - * @return int - */ - private function _throttleMessagesPerMinute($timePassed) - { - $expectedDuration = $this->_messages / ($this->_rate / 60); - - return (int) ceil($expectedDuration - $timePassed); - } -} diff --git a/tools/swift/classes/Swift/Plugins/Timer.php b/tools/swift/classes/Swift/Plugins/Timer.php deleted file mode 100644 index 9c8deb38a..000000000 --- a/tools/swift/classes/Swift/Plugins/Timer.php +++ /dev/null @@ -1,24 +0,0 @@ -register('properties.charset')->asValue($charset); - - return $this; - } - - /** - * Set the directory where temporary files can be saved. - * - * @param string $dir - * - * @return $this - */ - public function setTempDir($dir) - { - Swift_DependencyContainer::getInstance()->register('tempdir')->asValue($dir); - - return $this; - } - - /** - * Set the type of cache to use (i.e. "disk" or "array"). - * - * @param string $type - * - * @return $this - */ - public function setCacheType($type) - { - Swift_DependencyContainer::getInstance()->register('cache')->asAliasOf(sprintf('cache.%s', $type)); - - return $this; - } - - /** - * Set the QuotedPrintable dot escaper preference. - * - * @param bool $dotEscape - * - * @return $this - */ - public function setQPDotEscape($dotEscape) - { - $dotEscape = !empty($dotEscape); - Swift_DependencyContainer::getInstance() - ->register('mime.qpcontentencoder') - ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder') - ->withDependencies(array('mime.charstream', 'mime.bytecanonicalizer')) - ->addConstructorValue($dotEscape); - - return $this; - } -} diff --git a/tools/swift/classes/Swift/ReplacementFilterFactory.php b/tools/swift/classes/Swift/ReplacementFilterFactory.php deleted file mode 100644 index 2897474e7..000000000 --- a/tools/swift/classes/Swift/ReplacementFilterFactory.php +++ /dev/null @@ -1,27 +0,0 @@ -createDependenciesFor('transport.sendmail') - ); - - $this->setCommand($command); - } - - /** - * Create a new SendmailTransport instance. - * - * @param string $command - * - * @return self - */ - public static function newInstance($command = '/usr/sbin/sendmail -bs') - { - return new self($command); - } -} diff --git a/tools/swift/classes/Swift/SignedMessage.php b/tools/swift/classes/Swift/SignedMessage.php deleted file mode 100644 index 2e7a8726d..000000000 --- a/tools/swift/classes/Swift/SignedMessage.php +++ /dev/null @@ -1,23 +0,0 @@ - - * - * @deprecated - */ -class Swift_SignedMessage extends Swift_Message -{ -} diff --git a/tools/swift/classes/Swift/Signer.php b/tools/swift/classes/Swift/Signer.php deleted file mode 100644 index 2d8176d90..000000000 --- a/tools/swift/classes/Swift/Signer.php +++ /dev/null @@ -1,20 +0,0 @@ - - */ -interface Swift_Signer -{ - public function reset(); -} diff --git a/tools/swift/classes/Swift/Signers/BodySigner.php b/tools/swift/classes/Swift/Signers/BodySigner.php deleted file mode 100644 index 8e66e18f4..000000000 --- a/tools/swift/classes/Swift/Signers/BodySigner.php +++ /dev/null @@ -1,33 +0,0 @@ - - */ -interface Swift_Signers_BodySigner extends Swift_Signer -{ - /** - * Change the Swift_Signed_Message to apply the singing. - * - * @param Swift_Message $message - * - * @return self - */ - public function signMessage(Swift_Message $message); - - /** - * Return the list of header a signer might tamper. - * - * @return array - */ - public function getAlteredHeaders(); -} diff --git a/tools/swift/classes/Swift/Signers/DKIMSigner.php b/tools/swift/classes/Swift/Signers/DKIMSigner.php deleted file mode 100644 index 454e84b47..000000000 --- a/tools/swift/classes/Swift/Signers/DKIMSigner.php +++ /dev/null @@ -1,712 +0,0 @@ - - */ -class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner -{ - /** - * PrivateKey. - * - * @var string - */ - protected $_privateKey; - - /** - * DomainName. - * - * @var string - */ - protected $_domainName; - - /** - * Selector. - * - * @var string - */ - protected $_selector; - - /** - * Hash algorithm used. - * - * @see RFC6376 3.3: Signers MUST implement and SHOULD sign using rsa-sha256. - * - * @var string - */ - protected $_hashAlgorithm = 'rsa-sha256'; - - /** - * Body canon method. - * - * @var string - */ - protected $_bodyCanon = 'simple'; - - /** - * Header canon method. - * - * @var string - */ - protected $_headerCanon = 'simple'; - - /** - * Headers not being signed. - * - * @var array - */ - protected $_ignoredHeaders = array('return-path' => true); - - /** - * Signer identity. - * - * @var string - */ - protected $_signerIdentity; - - /** - * BodyLength. - * - * @var int - */ - protected $_bodyLen = 0; - - /** - * Maximum signedLen. - * - * @var int - */ - protected $_maxLen = PHP_INT_MAX; - - /** - * Embbed bodyLen in signature. - * - * @var bool - */ - protected $_showLen = false; - - /** - * When the signature has been applied (true means time()), false means not embedded. - * - * @var mixed - */ - protected $_signatureTimestamp = true; - - /** - * When will the signature expires false means not embedded, if sigTimestamp is auto - * Expiration is relative, otherwise it's absolute. - * - * @var int - */ - protected $_signatureExpiration = false; - - /** - * Must we embed signed headers? - * - * @var bool - */ - protected $_debugHeaders = false; - - // work variables - /** - * Headers used to generate hash. - * - * @var array - */ - protected $_signedHeaders = array(); - - /** - * If debugHeaders is set store debugData here. - * - * @var string - */ - private $_debugHeadersData = ''; - - /** - * Stores the bodyHash. - * - * @var string - */ - private $_bodyHash = ''; - - /** - * Stores the signature header. - * - * @var Swift_Mime_Headers_ParameterizedHeader - */ - protected $_dkimHeader; - - private $_bodyHashHandler; - - private $_headerHash; - - private $_headerCanonData = ''; - - private $_bodyCanonEmptyCounter = 0; - - private $_bodyCanonIgnoreStart = 2; - - private $_bodyCanonSpace = false; - - private $_bodyCanonLastChar = null; - - private $_bodyCanonLine = ''; - - private $_bound = array(); - - /** - * Constructor. - * - * @param string $privateKey - * @param string $domainName - * @param string $selector - */ - public function __construct($privateKey, $domainName, $selector) - { - $this->_privateKey = $privateKey; - $this->_domainName = $domainName; - $this->_signerIdentity = '@'.$domainName; - $this->_selector = $selector; - - // keep fallback hash algorithm sha1 if php version is lower than 5.4.8 - if (PHP_VERSION_ID < 50408) { - $this->_hashAlgorithm = 'rsa-sha1'; - } - } - - /** - * Instanciate DKIMSigner. - * - * @param string $privateKey - * @param string $domainName - * @param string $selector - * - * @return self - */ - public static function newInstance($privateKey, $domainName, $selector) - { - return new static($privateKey, $domainName, $selector); - } - - /** - * Reset the Signer. - * - * @see Swift_Signer::reset() - */ - public function reset() - { - $this->_headerHash = null; - $this->_signedHeaders = array(); - $this->_bodyHash = null; - $this->_bodyHashHandler = null; - $this->_bodyCanonIgnoreStart = 2; - $this->_bodyCanonEmptyCounter = 0; - $this->_bodyCanonLastChar = null; - $this->_bodyCanonSpace = false; - } - - /** - * Writes $bytes to the end of the stream. - * - * Writing may not happen immediately if the stream chooses to buffer. If - * you want to write these bytes with immediate effect, call {@link commit()} - * after calling write(). - * - * This method returns the sequence ID of the write (i.e. 1 for first, 2 for - * second, etc etc). - * - * @param string $bytes - * - * @throws Swift_IoException - * - * @return int - */ - // TODO fix return - public function write($bytes) - { - $this->_canonicalizeBody($bytes); - foreach ($this->_bound as $is) { - $is->write($bytes); - } - } - - /** - * For any bytes that are currently buffered inside the stream, force them - * off the buffer. - */ - public function commit() - { - // Nothing to do - return; - } - - /** - * Attach $is to this stream. - * The stream acts as an observer, receiving all data that is written. - * All {@link write()} and {@link flushBuffers()} operations will be mirrored. - * - * @param Swift_InputByteStream $is - */ - public function bind(Swift_InputByteStream $is) - { - // Don't have to mirror anything - $this->_bound[] = $is; - - return; - } - - /** - * Remove an already bound stream. - * If $is is not bound, no errors will be raised. - * If the stream currently has any buffered data it will be written to $is - * before unbinding occurs. - * - * @param Swift_InputByteStream $is - */ - public function unbind(Swift_InputByteStream $is) - { - // Don't have to mirror anything - foreach ($this->_bound as $k => $stream) { - if ($stream === $is) { - unset($this->_bound[$k]); - - return; - } - } - } - - /** - * Flush the contents of the stream (empty it) and set the internal pointer - * to the beginning. - * - * @throws Swift_IoException - */ - public function flushBuffers() - { - $this->reset(); - } - - /** - * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1. - * - * @param string $hash 'rsa-sha1' or 'rsa-sha256' - * - * @throws Swift_SwiftException - * - * @return $this - */ - public function setHashAlgorithm($hash) - { - switch ($hash) { - case 'rsa-sha1': - $this->_hashAlgorithm = 'rsa-sha1'; - break; - case 'rsa-sha256': - $this->_hashAlgorithm = 'rsa-sha256'; - if (!defined('OPENSSL_ALGO_SHA256')) { - throw new Swift_SwiftException('Unable to set sha256 as it is not supported by OpenSSL.'); - } - break; - default: - throw new Swift_SwiftException('Unable to set the hash algorithm, must be one of rsa-sha1 or rsa-sha256 (%s given).', $hash); - } - - return $this; - } - - /** - * Set the body canonicalization algorithm. - * - * @param string $canon - * - * @return $this - */ - public function setBodyCanon($canon) - { - if ($canon == 'relaxed') { - $this->_bodyCanon = 'relaxed'; - } else { - $this->_bodyCanon = 'simple'; - } - - return $this; - } - - /** - * Set the header canonicalization algorithm. - * - * @param string $canon - * - * @return $this - */ - public function setHeaderCanon($canon) - { - if ($canon == 'relaxed') { - $this->_headerCanon = 'relaxed'; - } else { - $this->_headerCanon = 'simple'; - } - - return $this; - } - - /** - * Set the signer identity. - * - * @param string $identity - * - * @return $this - */ - public function setSignerIdentity($identity) - { - $this->_signerIdentity = $identity; - - return $this; - } - - /** - * Set the length of the body to sign. - * - * @param mixed $len (bool or int) - * - * @return $this - */ - public function setBodySignedLen($len) - { - if ($len === true) { - $this->_showLen = true; - $this->_maxLen = PHP_INT_MAX; - } elseif ($len === false) { - $this->_showLen = false; - $this->_maxLen = PHP_INT_MAX; - } else { - $this->_showLen = true; - $this->_maxLen = (int) $len; - } - - return $this; - } - - /** - * Set the signature timestamp. - * - * @param int $time A timestamp - * - * @return $this - */ - public function setSignatureTimestamp($time) - { - $this->_signatureTimestamp = $time; - - return $this; - } - - /** - * Set the signature expiration timestamp. - * - * @param int $time A timestamp - * - * @return $this - */ - public function setSignatureExpiration($time) - { - $this->_signatureExpiration = $time; - - return $this; - } - - /** - * Enable / disable the DebugHeaders. - * - * @param bool $debug - * - * @return Swift_Signers_DKIMSigner - */ - public function setDebugHeaders($debug) - { - $this->_debugHeaders = (bool) $debug; - - return $this; - } - - /** - * Start Body. - */ - public function startBody() - { - // Init - switch ($this->_hashAlgorithm) { - case 'rsa-sha256': - $this->_bodyHashHandler = hash_init('sha256'); - break; - case 'rsa-sha1': - $this->_bodyHashHandler = hash_init('sha1'); - break; - } - $this->_bodyCanonLine = ''; - } - - /** - * End Body. - */ - public function endBody() - { - $this->_endOfBody(); - } - - /** - * Returns the list of Headers Tampered by this plugin. - * - * @return array - */ - public function getAlteredHeaders() - { - if ($this->_debugHeaders) { - return array('DKIM-Signature', 'X-DebugHash'); - } else { - return array('DKIM-Signature'); - } - } - - /** - * Adds an ignored Header. - * - * @param string $header_name - * - * @return Swift_Signers_DKIMSigner - */ - public function ignoreHeader($header_name) - { - $this->_ignoredHeaders[strtolower($header_name)] = true; - - return $this; - } - - /** - * Set the headers to sign. - * - * @param Swift_Mime_HeaderSet $headers - * - * @return Swift_Signers_DKIMSigner - */ - public function setHeaders(Swift_Mime_HeaderSet $headers) - { - $this->_headerCanonData = ''; - // Loop through Headers - $listHeaders = $headers->listAll(); - foreach ($listHeaders as $hName) { - // Check if we need to ignore Header - if (!isset($this->_ignoredHeaders[strtolower($hName)])) { - if ($headers->has($hName)) { - $tmp = $headers->getAll($hName); - foreach ($tmp as $header) { - if ($header->getFieldBody() != '') { - $this->_addHeader($header->toString()); - $this->_signedHeaders[] = $header->getFieldName(); - } - } - } - } - } - - return $this; - } - - /** - * Add the signature to the given Headers. - * - * @param Swift_Mime_HeaderSet $headers - * - * @return Swift_Signers_DKIMSigner - */ - public function addSignature(Swift_Mime_HeaderSet $headers) - { - // Prepare the DKIM-Signature - $params = array('v' => '1', 'a' => $this->_hashAlgorithm, 'bh' => base64_encode($this->_bodyHash), 'd' => $this->_domainName, 'h' => implode(': ', $this->_signedHeaders), 'i' => $this->_signerIdentity, 's' => $this->_selector); - if ($this->_bodyCanon != 'simple') { - $params['c'] = $this->_headerCanon.'/'.$this->_bodyCanon; - } elseif ($this->_headerCanon != 'simple') { - $params['c'] = $this->_headerCanon; - } - if ($this->_showLen) { - $params['l'] = $this->_bodyLen; - } - if ($this->_signatureTimestamp === true) { - $params['t'] = time(); - if ($this->_signatureExpiration !== false) { - $params['x'] = $params['t'] + $this->_signatureExpiration; - } - } else { - if ($this->_signatureTimestamp !== false) { - $params['t'] = $this->_signatureTimestamp; - } - if ($this->_signatureExpiration !== false) { - $params['x'] = $this->_signatureExpiration; - } - } - if ($this->_debugHeaders) { - $params['z'] = implode('|', $this->_debugHeadersData); - } - $string = ''; - foreach ($params as $k => $v) { - $string .= $k.'='.$v.'; '; - } - $string = trim($string); - $headers->addTextHeader('DKIM-Signature', $string); - // Add the last DKIM-Signature - $tmp = $headers->getAll('DKIM-Signature'); - $this->_dkimHeader = end($tmp); - $this->_addHeader(trim($this->_dkimHeader->toString())."\r\n b=", true); - $this->_endOfHeaders(); - if ($this->_debugHeaders) { - $headers->addTextHeader('X-DebugHash', base64_encode($this->_headerHash)); - } - $this->_dkimHeader->setValue($string.' b='.trim(chunk_split(base64_encode($this->_getEncryptedHash()), 73, ' '))); - - return $this; - } - - /* Private helpers */ - - protected function _addHeader($header, $is_sig = false) - { - switch ($this->_headerCanon) { - case 'relaxed': - // Prepare Header and cascade - $exploded = explode(':', $header, 2); - $name = strtolower(trim($exploded[0])); - $value = str_replace("\r\n", '', $exploded[1]); - $value = preg_replace("/[ \t][ \t]+/", ' ', $value); - $header = $name.':'.trim($value).($is_sig ? '' : "\r\n"); - case 'simple': - // Nothing to do - } - $this->_addToHeaderHash($header); - } - - /** - * @deprecated This method is currently useless in this class but it must be - * kept for BC reasons due to its "protected" scope. This method - * might be overridden by custom client code. - */ - protected function _endOfHeaders() - { - } - - protected function _canonicalizeBody($string) - { - $len = strlen($string); - $canon = ''; - $method = ($this->_bodyCanon == 'relaxed'); - for ($i = 0; $i < $len; ++$i) { - if ($this->_bodyCanonIgnoreStart > 0) { - --$this->_bodyCanonIgnoreStart; - continue; - } - switch ($string[$i]) { - case "\r": - $this->_bodyCanonLastChar = "\r"; - break; - case "\n": - if ($this->_bodyCanonLastChar == "\r") { - if ($method) { - $this->_bodyCanonSpace = false; - } - if ($this->_bodyCanonLine == '') { - ++$this->_bodyCanonEmptyCounter; - } else { - $this->_bodyCanonLine = ''; - $canon .= "\r\n"; - } - } else { - // Wooops Error - // todo handle it but should never happen - } - break; - case ' ': - case "\t": - if ($method) { - $this->_bodyCanonSpace = true; - break; - } - default: - if ($this->_bodyCanonEmptyCounter > 0) { - $canon .= str_repeat("\r\n", $this->_bodyCanonEmptyCounter); - $this->_bodyCanonEmptyCounter = 0; - } - if ($this->_bodyCanonSpace) { - $this->_bodyCanonLine .= ' '; - $canon .= ' '; - $this->_bodyCanonSpace = false; - } - $this->_bodyCanonLine .= $string[$i]; - $canon .= $string[$i]; - } - } - $this->_addToBodyHash($canon); - } - - protected function _endOfBody() - { - // Add trailing Line return if last line is non empty - if (strlen($this->_bodyCanonLine) > 0) { - $this->_addToBodyHash("\r\n"); - } - $this->_bodyHash = hash_final($this->_bodyHashHandler, true); - } - - private function _addToBodyHash($string) - { - $len = strlen($string); - if ($len > ($new_len = ($this->_maxLen - $this->_bodyLen))) { - $string = substr($string, 0, $new_len); - $len = $new_len; - } - hash_update($this->_bodyHashHandler, $string); - $this->_bodyLen += $len; - } - - private function _addToHeaderHash($header) - { - if ($this->_debugHeaders) { - $this->_debugHeadersData[] = trim($header); - } - $this->_headerCanonData .= $header; - } - - /** - * @throws Swift_SwiftException - * - * @return string - */ - private function _getEncryptedHash() - { - $signature = ''; - - switch ($this->_hashAlgorithm) { - case 'rsa-sha1': - $algorithm = OPENSSL_ALGO_SHA1; - break; - case 'rsa-sha256': - $algorithm = OPENSSL_ALGO_SHA256; - break; - } - $pkeyId = openssl_get_privatekey($this->_privateKey); - if (!$pkeyId) { - throw new Swift_SwiftException('Unable to load DKIM Private Key ['.openssl_error_string().']'); - } - if (openssl_sign($this->_headerCanonData, $signature, $pkeyId, $algorithm)) { - return $signature; - } - throw new Swift_SwiftException('Unable to sign DKIM Hash ['.openssl_error_string().']'); - } -} diff --git a/tools/swift/classes/Swift/Signers/DomainKeySigner.php b/tools/swift/classes/Swift/Signers/DomainKeySigner.php deleted file mode 100644 index 0365363c8..000000000 --- a/tools/swift/classes/Swift/Signers/DomainKeySigner.php +++ /dev/null @@ -1,524 +0,0 @@ - - */ -class Swift_Signers_DomainKeySigner implements Swift_Signers_HeaderSigner -{ - /** - * PrivateKey. - * - * @var string - */ - protected $_privateKey; - - /** - * DomainName. - * - * @var string - */ - protected $_domainName; - - /** - * Selector. - * - * @var string - */ - protected $_selector; - - /** - * Hash algorithm used. - * - * @var string - */ - protected $_hashAlgorithm = 'rsa-sha1'; - - /** - * Canonisation method. - * - * @var string - */ - protected $_canon = 'simple'; - - /** - * Headers not being signed. - * - * @var array - */ - protected $_ignoredHeaders = array(); - - /** - * Signer identity. - * - * @var string - */ - protected $_signerIdentity; - - /** - * Must we embed signed headers? - * - * @var bool - */ - protected $_debugHeaders = false; - - // work variables - /** - * Headers used to generate hash. - * - * @var array - */ - private $_signedHeaders = array(); - - /** - * Stores the signature header. - * - * @var Swift_Mime_Headers_ParameterizedHeader - */ - protected $_domainKeyHeader; - - /** - * Hash Handler. - * - * @var resource|null - */ - private $_hashHandler; - - private $_hash; - - private $_canonData = ''; - - private $_bodyCanonEmptyCounter = 0; - - private $_bodyCanonIgnoreStart = 2; - - private $_bodyCanonSpace = false; - - private $_bodyCanonLastChar = null; - - private $_bodyCanonLine = ''; - - private $_bound = array(); - - /** - * Constructor. - * - * @param string $privateKey - * @param string $domainName - * @param string $selector - */ - public function __construct($privateKey, $domainName, $selector) - { - $this->_privateKey = $privateKey; - $this->_domainName = $domainName; - $this->_signerIdentity = '@'.$domainName; - $this->_selector = $selector; - } - - /** - * Instanciate DomainKeySigner. - * - * @param string $privateKey - * @param string $domainName - * @param string $selector - * - * @return self - */ - public static function newInstance($privateKey, $domainName, $selector) - { - return new static($privateKey, $domainName, $selector); - } - - /** - * Resets internal states. - * - * @return $this - */ - public function reset() - { - $this->_hash = null; - $this->_hashHandler = null; - $this->_bodyCanonIgnoreStart = 2; - $this->_bodyCanonEmptyCounter = 0; - $this->_bodyCanonLastChar = null; - $this->_bodyCanonSpace = false; - - return $this; - } - - /** - * Writes $bytes to the end of the stream. - * - * Writing may not happen immediately if the stream chooses to buffer. If - * you want to write these bytes with immediate effect, call {@link commit()} - * after calling write(). - * - * This method returns the sequence ID of the write (i.e. 1 for first, 2 for - * second, etc etc). - * - * @param string $bytes - * - * @throws Swift_IoException - * - * @return $this - */ - public function write($bytes) - { - $this->_canonicalizeBody($bytes); - foreach ($this->_bound as $is) { - $is->write($bytes); - } - - return $this; - } - - /** - * For any bytes that are currently buffered inside the stream, force them - * off the buffer. - * - * @throws Swift_IoException - * - * @return $this - */ - public function commit() - { - // Nothing to do - return $this; - } - - /** - * Attach $is to this stream. - * The stream acts as an observer, receiving all data that is written. - * All {@link write()} and {@link flushBuffers()} operations will be mirrored. - * - * @param Swift_InputByteStream $is - * - * @return $this - */ - public function bind(Swift_InputByteStream $is) - { - // Don't have to mirror anything - $this->_bound[] = $is; - - return $this; - } - - /** - * Remove an already bound stream. - * If $is is not bound, no errors will be raised. - * If the stream currently has any buffered data it will be written to $is - * before unbinding occurs. - * - * @param Swift_InputByteStream $is - * - * @return $this - */ - public function unbind(Swift_InputByteStream $is) - { - // Don't have to mirror anything - foreach ($this->_bound as $k => $stream) { - if ($stream === $is) { - unset($this->_bound[$k]); - - break; - } - } - - return $this; - } - - /** - * Flush the contents of the stream (empty it) and set the internal pointer - * to the beginning. - * - * @throws Swift_IoException - * - * @return $this - */ - public function flushBuffers() - { - $this->reset(); - - return $this; - } - - /** - * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1 defaults to rsa-sha256. - * - * @param string $hash - * - * @return $this - */ - public function setHashAlgorithm($hash) - { - $this->_hashAlgorithm = 'rsa-sha1'; - - return $this; - } - - /** - * Set the canonicalization algorithm. - * - * @param string $canon simple | nofws defaults to simple - * - * @return $this - */ - public function setCanon($canon) - { - if ($canon == 'nofws') { - $this->_canon = 'nofws'; - } else { - $this->_canon = 'simple'; - } - - return $this; - } - - /** - * Set the signer identity. - * - * @param string $identity - * - * @return $this - */ - public function setSignerIdentity($identity) - { - $this->_signerIdentity = $identity; - - return $this; - } - - /** - * Enable / disable the DebugHeaders. - * - * @param bool $debug - * - * @return $this - */ - public function setDebugHeaders($debug) - { - $this->_debugHeaders = (bool) $debug; - - return $this; - } - - /** - * Start Body. - */ - public function startBody() - { - } - - /** - * End Body. - */ - public function endBody() - { - $this->_endOfBody(); - } - - /** - * Returns the list of Headers Tampered by this plugin. - * - * @return array - */ - public function getAlteredHeaders() - { - if ($this->_debugHeaders) { - return array('DomainKey-Signature', 'X-DebugHash'); - } - - return array('DomainKey-Signature'); - } - - /** - * Adds an ignored Header. - * - * @param string $header_name - * - * @return $this - */ - public function ignoreHeader($header_name) - { - $this->_ignoredHeaders[strtolower($header_name)] = true; - - return $this; - } - - /** - * Set the headers to sign. - * - * @param Swift_Mime_HeaderSet $headers - * - * @return $this - */ - public function setHeaders(Swift_Mime_HeaderSet $headers) - { - $this->_startHash(); - $this->_canonData = ''; - // Loop through Headers - $listHeaders = $headers->listAll(); - foreach ($listHeaders as $hName) { - // Check if we need to ignore Header - if (!isset($this->_ignoredHeaders[strtolower($hName)])) { - if ($headers->has($hName)) { - $tmp = $headers->getAll($hName); - foreach ($tmp as $header) { - if ($header->getFieldBody() != '') { - $this->_addHeader($header->toString()); - $this->_signedHeaders[] = $header->getFieldName(); - } - } - } - } - } - $this->_endOfHeaders(); - - return $this; - } - - /** - * Add the signature to the given Headers. - * - * @param Swift_Mime_HeaderSet $headers - * - * @return $this - */ - public function addSignature(Swift_Mime_HeaderSet $headers) - { - // Prepare the DomainKey-Signature Header - $params = array('a' => $this->_hashAlgorithm, 'b' => chunk_split(base64_encode($this->_getEncryptedHash()), 73, ' '), 'c' => $this->_canon, 'd' => $this->_domainName, 'h' => implode(': ', $this->_signedHeaders), 'q' => 'dns', 's' => $this->_selector); - $string = ''; - foreach ($params as $k => $v) { - $string .= $k.'='.$v.'; '; - } - $string = trim($string); - $headers->addTextHeader('DomainKey-Signature', $string); - - return $this; - } - - /* Private helpers */ - - protected function _addHeader($header) - { - switch ($this->_canon) { - case 'nofws': - // Prepare Header and cascade - $exploded = explode(':', $header, 2); - $name = strtolower(trim($exploded[0])); - $value = str_replace("\r\n", '', $exploded[1]); - $value = preg_replace("/[ \t][ \t]+/", ' ', $value); - $header = $name.':'.trim($value)."\r\n"; - case 'simple': - // Nothing to do - } - $this->_addToHash($header); - } - - protected function _endOfHeaders() - { - $this->_bodyCanonEmptyCounter = 1; - } - - protected function _canonicalizeBody($string) - { - $len = strlen($string); - $canon = ''; - $nofws = ($this->_canon == 'nofws'); - for ($i = 0; $i < $len; ++$i) { - if ($this->_bodyCanonIgnoreStart > 0) { - --$this->_bodyCanonIgnoreStart; - continue; - } - switch ($string[$i]) { - case "\r": - $this->_bodyCanonLastChar = "\r"; - break; - case "\n": - if ($this->_bodyCanonLastChar == "\r") { - if ($nofws) { - $this->_bodyCanonSpace = false; - } - if ($this->_bodyCanonLine == '') { - ++$this->_bodyCanonEmptyCounter; - } else { - $this->_bodyCanonLine = ''; - $canon .= "\r\n"; - } - } else { - // Wooops Error - throw new Swift_SwiftException('Invalid new line sequence in mail found \n without preceding \r'); - } - break; - case ' ': - case "\t": - case "\x09": //HTAB - if ($nofws) { - $this->_bodyCanonSpace = true; - break; - } - default: - if ($this->_bodyCanonEmptyCounter > 0) { - $canon .= str_repeat("\r\n", $this->_bodyCanonEmptyCounter); - $this->_bodyCanonEmptyCounter = 0; - } - $this->_bodyCanonLine .= $string[$i]; - $canon .= $string[$i]; - } - } - $this->_addToHash($canon); - } - - protected function _endOfBody() - { - if (strlen($this->_bodyCanonLine) > 0) { - $this->_addToHash("\r\n"); - } - $this->_hash = hash_final($this->_hashHandler, true); - } - - private function _addToHash($string) - { - $this->_canonData .= $string; - hash_update($this->_hashHandler, $string); - } - - private function _startHash() - { - // Init - switch ($this->_hashAlgorithm) { - case 'rsa-sha1': - $this->_hashHandler = hash_init('sha1'); - break; - } - $this->_bodyCanonLine = ''; - } - - /** - * @throws Swift_SwiftException - * - * @return string - */ - private function _getEncryptedHash() - { - $signature = ''; - $pkeyId = openssl_get_privatekey($this->_privateKey); - if (!$pkeyId) { - throw new Swift_SwiftException('Unable to load DomainKey Private Key ['.openssl_error_string().']'); - } - if (openssl_sign($this->_canonData, $signature, $pkeyId, OPENSSL_ALGO_SHA1)) { - return $signature; - } - throw new Swift_SwiftException('Unable to sign DomainKey Hash ['.openssl_error_string().']'); - } -} diff --git a/tools/swift/classes/Swift/Signers/HeaderSigner.php b/tools/swift/classes/Swift/Signers/HeaderSigner.php deleted file mode 100644 index ef8832fdf..000000000 --- a/tools/swift/classes/Swift/Signers/HeaderSigner.php +++ /dev/null @@ -1,65 +0,0 @@ - - */ -interface Swift_Signers_HeaderSigner extends Swift_Signer, Swift_InputByteStream -{ - /** - * Exclude an header from the signed headers. - * - * @param string $header_name - * - * @return self - */ - public function ignoreHeader($header_name); - - /** - * Prepare the Signer to get a new Body. - * - * @return self - */ - public function startBody(); - - /** - * Give the signal that the body has finished streaming. - * - * @return self - */ - public function endBody(); - - /** - * Give the headers already given. - * - * @param Swift_Mime_SimpleHeaderSet $headers - * - * @return self - */ - public function setHeaders(Swift_Mime_HeaderSet $headers); - - /** - * Add the header(s) to the headerSet. - * - * @param Swift_Mime_HeaderSet $headers - * - * @return self - */ - public function addSignature(Swift_Mime_HeaderSet $headers); - - /** - * Return the list of header a signer might tamper. - * - * @return array - */ - public function getAlteredHeaders(); -} diff --git a/tools/swift/classes/Swift/Signers/OpenDKIMSigner.php b/tools/swift/classes/Swift/Signers/OpenDKIMSigner.php deleted file mode 100644 index 8fdbaa43b..000000000 --- a/tools/swift/classes/Swift/Signers/OpenDKIMSigner.php +++ /dev/null @@ -1,190 +0,0 @@ - - */ -class Swift_Signers_OpenDKIMSigner extends Swift_Signers_DKIMSigner -{ - private $_peclLoaded = false; - - private $_dkimHandler = null; - - private $dropFirstLF = true; - - const CANON_RELAXED = 1; - const CANON_SIMPLE = 2; - const SIG_RSA_SHA1 = 3; - const SIG_RSA_SHA256 = 4; - - public function __construct($privateKey, $domainName, $selector) - { - if (!extension_loaded('opendkim')) { - throw new Swift_SwiftException('php-opendkim extension not found'); - } - - $this->_peclLoaded = true; - - parent::__construct($privateKey, $domainName, $selector); - } - - public static function newInstance($privateKey, $domainName, $selector) - { - return new static($privateKey, $domainName, $selector); - } - - public function addSignature(Swift_Mime_HeaderSet $headers) - { - $header = new Swift_Mime_Headers_OpenDKIMHeader('DKIM-Signature'); - $headerVal = $this->_dkimHandler->getSignatureHeader(); - if (!$headerVal) { - throw new Swift_SwiftException('OpenDKIM Error: '.$this->_dkimHandler->getError()); - } - $header->setValue($headerVal); - $headers->set($header); - - return $this; - } - - public function setHeaders(Swift_Mime_HeaderSet $headers) - { - $bodyLen = $this->_bodyLen; - if (is_bool($bodyLen)) { - $bodyLen = -1; - } - $hash = $this->_hashAlgorithm == 'rsa-sha1' ? OpenDKIMSign::ALG_RSASHA1 : OpenDKIMSign::ALG_RSASHA256; - $bodyCanon = $this->_bodyCanon == 'simple' ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED; - $headerCanon = $this->_headerCanon == 'simple' ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED; - $this->_dkimHandler = new OpenDKIMSign($this->_privateKey, $this->_selector, $this->_domainName, $headerCanon, $bodyCanon, $hash, $bodyLen); - // Hardcode signature Margin for now - $this->_dkimHandler->setMargin(78); - - if (!is_numeric($this->_signatureTimestamp)) { - OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, time()); - } else { - if (!OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, $this->_signatureTimestamp)) { - throw new Swift_SwiftException('Unable to force signature timestamp ['.openssl_error_string().']'); - } - } - if (isset($this->_signerIdentity)) { - $this->_dkimHandler->setSigner($this->_signerIdentity); - } - $listHeaders = $headers->listAll(); - foreach ($listHeaders as $hName) { - // Check if we need to ignore Header - if (!isset($this->_ignoredHeaders[strtolower($hName)])) { - $tmp = $headers->getAll($hName); - if ($headers->has($hName)) { - foreach ($tmp as $header) { - if ($header->getFieldBody() != '') { - $htosign = $header->toString(); - $this->_dkimHandler->header($htosign); - $this->_signedHeaders[] = $header->getFieldName(); - } - } - } - } - } - - return $this; - } - - public function startBody() - { - if (!$this->_peclLoaded) { - return parent::startBody(); - } - $this->dropFirstLF = true; - $this->_dkimHandler->eoh(); - - return $this; - } - - public function endBody() - { - if (!$this->_peclLoaded) { - return parent::endBody(); - } - $this->_dkimHandler->eom(); - - return $this; - } - - public function reset() - { - $this->_dkimHandler = null; - parent::reset(); - - return $this; - } - - /** - * Set the signature timestamp. - * - * @param int $time - * - * @return $this - */ - public function setSignatureTimestamp($time) - { - $this->_signatureTimestamp = $time; - - return $this; - } - - /** - * Set the signature expiration timestamp. - * - * @param int $time - * - * @return $this - */ - public function setSignatureExpiration($time) - { - $this->_signatureExpiration = $time; - - return $this; - } - - /** - * Enable / disable the DebugHeaders. - * - * @param bool $debug - * - * @return $this - */ - public function setDebugHeaders($debug) - { - $this->_debugHeaders = (bool) $debug; - - return $this; - } - - // Protected - - protected function _canonicalizeBody($string) - { - if (!$this->_peclLoaded) { - return parent::_canonicalizeBody($string); - } - if (false && $this->dropFirstLF === true) { - if ($string[0] == "\r" && $string[1] == "\n") { - $string = substr($string, 2); - } - } - $this->dropFirstLF = false; - if (strlen($string)) { - $this->_dkimHandler->body($string); - } - } -} diff --git a/tools/swift/classes/Swift/Signers/SMimeSigner.php b/tools/swift/classes/Swift/Signers/SMimeSigner.php deleted file mode 100644 index d13c02e4c..000000000 --- a/tools/swift/classes/Swift/Signers/SMimeSigner.php +++ /dev/null @@ -1,436 +0,0 @@ - - */ -class Swift_Signers_SMimeSigner implements Swift_Signers_BodySigner -{ - protected $signCertificate; - protected $signPrivateKey; - protected $encryptCert; - protected $signThenEncrypt = true; - protected $signLevel; - protected $encryptLevel; - protected $signOptions; - protected $encryptOptions; - protected $encryptCipher; - protected $extraCerts = null; - - /** - * @var Swift_StreamFilters_StringReplacementFilterFactory - */ - protected $replacementFactory; - - /** - * @var Swift_Mime_HeaderFactory - */ - protected $headerFactory; - - /** - * Constructor. - * - * @param string|null $signCertificate - * @param string|null $signPrivateKey - * @param string|null $encryptCertificate - */ - public function __construct($signCertificate = null, $signPrivateKey = null, $encryptCertificate = null) - { - if (null !== $signPrivateKey) { - $this->setSignCertificate($signCertificate, $signPrivateKey); - } - - if (null !== $encryptCertificate) { - $this->setEncryptCertificate($encryptCertificate); - } - - $this->replacementFactory = Swift_DependencyContainer::getInstance() - ->lookup('transport.replacementfactory'); - - $this->signOptions = PKCS7_DETACHED; - - // Supported since php5.4 - if (defined('OPENSSL_CIPHER_AES_128_CBC')) { - $this->encryptCipher = OPENSSL_CIPHER_AES_128_CBC; - } else { - $this->encryptCipher = OPENSSL_CIPHER_RC2_128; - } - } - - /** - * Returns an new Swift_Signers_SMimeSigner instance. - * - * @param string $certificate - * @param string $privateKey - * - * @return self - */ - public static function newInstance($certificate = null, $privateKey = null) - { - return new self($certificate, $privateKey); - } - - /** - * Set the certificate location to use for signing. - * - * @see http://www.php.net/manual/en/openssl.pkcs7.flags.php - * - * @param string $certificate - * @param string|array $privateKey If the key needs an passphrase use array('file-location', 'passphrase') instead - * @param int $signOptions Bitwise operator options for openssl_pkcs7_sign() - * @param string $extraCerts A file containing intermediate certificates needed by the signing certificate - * - * @return $this - */ - public function setSignCertificate($certificate, $privateKey = null, $signOptions = PKCS7_DETACHED, $extraCerts = null) - { - $this->signCertificate = 'file://'.str_replace('\\', '/', realpath($certificate)); - - if (null !== $privateKey) { - if (is_array($privateKey)) { - $this->signPrivateKey = $privateKey; - $this->signPrivateKey[0] = 'file://'.str_replace('\\', '/', realpath($privateKey[0])); - } else { - $this->signPrivateKey = 'file://'.str_replace('\\', '/', realpath($privateKey)); - } - } - - $this->signOptions = $signOptions; - if (null !== $extraCerts) { - $this->extraCerts = str_replace('\\', '/', realpath($extraCerts)); - } - - return $this; - } - - /** - * Set the certificate location to use for encryption. - * - * @see http://www.php.net/manual/en/openssl.pkcs7.flags.php - * @see http://nl3.php.net/manual/en/openssl.ciphers.php - * - * @param string|array $recipientCerts Either an single X.509 certificate, or an assoc array of X.509 certificates. - * @param int $cipher - * - * @return $this - */ - public function setEncryptCertificate($recipientCerts, $cipher = null) - { - if (is_array($recipientCerts)) { - $this->encryptCert = array(); - - foreach ($recipientCerts as $cert) { - $this->encryptCert[] = 'file://'.str_replace('\\', '/', realpath($cert)); - } - } else { - $this->encryptCert = 'file://'.str_replace('\\', '/', realpath($recipientCerts)); - } - - if (null !== $cipher) { - $this->encryptCipher = $cipher; - } - - return $this; - } - - /** - * @return string - */ - public function getSignCertificate() - { - return $this->signCertificate; - } - - /** - * @return string - */ - public function getSignPrivateKey() - { - return $this->signPrivateKey; - } - - /** - * Set perform signing before encryption. - * - * The default is to first sign the message and then encrypt. - * But some older mail clients, namely Microsoft Outlook 2000 will work when the message first encrypted. - * As this goes against the official specs, its recommended to only use 'encryption -> signing' when specifically targeting these 'broken' clients. - * - * @param bool $signThenEncrypt - * - * @return $this - */ - public function setSignThenEncrypt($signThenEncrypt = true) - { - $this->signThenEncrypt = $signThenEncrypt; - - return $this; - } - - /** - * @return bool - */ - public function isSignThenEncrypt() - { - return $this->signThenEncrypt; - } - - /** - * Resets internal states. - * - * @return $this - */ - public function reset() - { - return $this; - } - - /** - * Change the Swift_Message to apply the signing. - * - * @param Swift_Message $message - * - * @return $this - */ - public function signMessage(Swift_Message $message) - { - if (null === $this->signCertificate && null === $this->encryptCert) { - return $this; - } - - // Store the message using ByteStream to a file{1} - // Remove all Children - // Sign file{1}, parse the new MIME headers and set them on the primary MimeEntity - // Set the singed-body as the new body (without boundary) - - $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); - $this->toSMimeByteStream($messageStream, $message); - $message->setEncoder(Swift_DependencyContainer::getInstance()->lookup('mime.rawcontentencoder')); - - $message->setChildren(array()); - $this->streamToMime($messageStream, $message); - } - - /** - * Return the list of header a signer might tamper. - * - * @return array - */ - public function getAlteredHeaders() - { - return array('Content-Type', 'Content-Transfer-Encoding', 'Content-Disposition'); - } - - /** - * @param Swift_InputByteStream $inputStream - * @param Swift_Message $mimeEntity - */ - protected function toSMimeByteStream(Swift_InputByteStream $inputStream, Swift_Message $message) - { - $mimeEntity = $this->createMessage($message); - $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); - - $mimeEntity->toByteStream($messageStream); - $messageStream->commit(); - - if (null !== $this->signCertificate && null !== $this->encryptCert) { - $temporaryStream = new Swift_ByteStream_TemporaryFileByteStream(); - - if ($this->signThenEncrypt) { - $this->messageStreamToSignedByteStream($messageStream, $temporaryStream); - $this->messageStreamToEncryptedByteStream($temporaryStream, $inputStream); - } else { - $this->messageStreamToEncryptedByteStream($messageStream, $temporaryStream); - $this->messageStreamToSignedByteStream($temporaryStream, $inputStream); - } - } elseif ($this->signCertificate !== null) { - $this->messageStreamToSignedByteStream($messageStream, $inputStream); - } else { - $this->messageStreamToEncryptedByteStream($messageStream, $inputStream); - } - } - - /** - * @param Swift_Message $message - * - * @return Swift_Message - */ - protected function createMessage(Swift_Message $message) - { - $mimeEntity = new Swift_Message('', $message->getBody(), $message->getContentType(), $message->getCharset()); - $mimeEntity->setChildren($message->getChildren()); - - $messageHeaders = $mimeEntity->getHeaders(); - $messageHeaders->remove('Message-ID'); - $messageHeaders->remove('Date'); - $messageHeaders->remove('Subject'); - $messageHeaders->remove('MIME-Version'); - $messageHeaders->remove('To'); - $messageHeaders->remove('From'); - - return $mimeEntity; - } - - /** - * @param Swift_FileStream $outputStream - * @param Swift_InputByteStream $inputStream - * - * @throws Swift_IoException - */ - protected function messageStreamToSignedByteStream(Swift_FileStream $outputStream, Swift_InputByteStream $inputStream) - { - $signedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); - - $args = array($outputStream->getPath(), $signedMessageStream->getPath(), $this->signCertificate, $this->signPrivateKey, array(), $this->signOptions); - if (null !== $this->extraCerts) { - $args[] = $this->extraCerts; - } - - if (!call_user_func_array('openssl_pkcs7_sign', $args)) { - throw new Swift_IoException(sprintf('Failed to sign S/Mime message. Error: "%s".', openssl_error_string())); - } - - $this->copyFromOpenSSLOutput($signedMessageStream, $inputStream); - } - - /** - * @param Swift_FileStream $outputStream - * @param Swift_InputByteStream $is - * - * @throws Swift_IoException - */ - protected function messageStreamToEncryptedByteStream(Swift_FileStream $outputStream, Swift_InputByteStream $is) - { - $encryptedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); - - if (!openssl_pkcs7_encrypt($outputStream->getPath(), $encryptedMessageStream->getPath(), $this->encryptCert, array(), 0, $this->encryptCipher)) { - throw new Swift_IoException(sprintf('Failed to encrypt S/Mime message. Error: "%s".', openssl_error_string())); - } - - $this->copyFromOpenSSLOutput($encryptedMessageStream, $is); - } - - /** - * @param Swift_OutputByteStream $fromStream - * @param Swift_InputByteStream $toStream - */ - protected function copyFromOpenSSLOutput(Swift_OutputByteStream $fromStream, Swift_InputByteStream $toStream) - { - $bufferLength = 4096; - $filteredStream = new Swift_ByteStream_TemporaryFileByteStream(); - $filteredStream->addFilter($this->replacementFactory->createFilter("\r\n", "\n"), 'CRLF to LF'); - $filteredStream->addFilter($this->replacementFactory->createFilter("\n", "\r\n"), 'LF to CRLF'); - - while (false !== ($buffer = $fromStream->read($bufferLength))) { - $filteredStream->write($buffer); - } - - $filteredStream->flushBuffers(); - - while (false !== ($buffer = $filteredStream->read($bufferLength))) { - $toStream->write($buffer); - } - - $toStream->commit(); - } - - /** - * Merges an OutputByteStream to Swift_Message. - * - * @param Swift_OutputByteStream $fromStream - * @param Swift_Message $message - */ - protected function streamToMime(Swift_OutputByteStream $fromStream, Swift_Message $message) - { - $bufferLength = 78; - $headerData = ''; - - $fromStream->setReadPointer(0); - - while (($buffer = $fromStream->read($bufferLength)) !== false) { - $headerData .= $buffer; - - if (false !== strpos($buffer, "\r\n\r\n")) { - break; - } - } - - $headersPosEnd = strpos($headerData, "\r\n\r\n"); - $headerData = trim($headerData); - $headerData = substr($headerData, 0, $headersPosEnd); - $headerLines = explode("\r\n", $headerData); - unset($headerData); - - $headers = array(); - $currentHeaderName = ''; - - foreach ($headerLines as $headerLine) { - // Line separated - if (ctype_space($headerLines[0]) || false === strpos($headerLine, ':')) { - $headers[$currentHeaderName] .= ' '.trim($headerLine); - continue; - } - - $header = explode(':', $headerLine, 2); - $currentHeaderName = strtolower($header[0]); - $headers[$currentHeaderName] = trim($header[1]); - } - - $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); - $messageStream->addFilter($this->replacementFactory->createFilter("\r\n", "\n"), 'CRLF to LF'); - $messageStream->addFilter($this->replacementFactory->createFilter("\n", "\r\n"), 'LF to CRLF'); - - $messageHeaders = $message->getHeaders(); - - // No need to check for 'application/pkcs7-mime', as this is always base64 - if ('multipart/signed;' === substr($headers['content-type'], 0, 17)) { - if (!preg_match('/boundary=("[^"]+"|(?:[^\s]+|$))/is', $headers['content-type'], $contentTypeData)) { - throw new Swift_SwiftException('Failed to find Boundary parameter'); - } - - $boundary = trim($contentTypeData['1'], '"'); - - // Skip the header and CRLF CRLF - $fromStream->setReadPointer($headersPosEnd + 4); - - while (false !== ($buffer = $fromStream->read($bufferLength))) { - $messageStream->write($buffer); - } - - $messageStream->commit(); - - $messageHeaders->remove('Content-Transfer-Encoding'); - $message->setContentType($headers['content-type']); - $message->setBoundary($boundary); - $message->setBody($messageStream); - } else { - $fromStream->setReadPointer($headersPosEnd + 4); - - if (null === $this->headerFactory) { - $this->headerFactory = Swift_DependencyContainer::getInstance()->lookup('mime.headerfactory'); - } - - $message->setContentType($headers['content-type']); - $messageHeaders->set($this->headerFactory->createTextHeader('Content-Transfer-Encoding', $headers['content-transfer-encoding'])); - $messageHeaders->set($this->headerFactory->createTextHeader('Content-Disposition', $headers['content-disposition'])); - - while (false !== ($buffer = $fromStream->read($bufferLength))) { - $messageStream->write($buffer); - } - - $messageStream->commit(); - $message->setBody($messageStream); - } - } -} diff --git a/tools/swift/classes/Swift/SmtpTransport.php b/tools/swift/classes/Swift/SmtpTransport.php deleted file mode 100644 index b97f01e7c..000000000 --- a/tools/swift/classes/Swift/SmtpTransport.php +++ /dev/null @@ -1,58 +0,0 @@ -createDependenciesFor('transport.smtp') - ); - - $this->setHost($host); - $this->setPort($port); - $this->setEncryption($security); - } - - /** - * Create a new SmtpTransport instance. - * - * @param string $host - * @param int $port - * @param string $security - * - * @return self - */ - public static function newInstance($host = 'localhost', $port = 25, $security = null) - { - return new self($host, $port, $security); - } -} diff --git a/tools/swift/classes/Swift/Spool.php b/tools/swift/classes/Swift/Spool.php deleted file mode 100644 index c16ab4b38..000000000 --- a/tools/swift/classes/Swift/Spool.php +++ /dev/null @@ -1,53 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Interface for spools. - * - * @author Fabien Potencier - */ -interface Swift_Spool -{ - /** - * Starts this Spool mechanism. - */ - public function start(); - - /** - * Stops this Spool mechanism. - */ - public function stop(); - - /** - * Tests if this Spool mechanism has started. - * - * @return bool - */ - public function isStarted(); - - /** - * Queues a message. - * - * @param Swift_Mime_Message $message The message to store - * - * @return bool Whether the operation has succeeded - */ - public function queueMessage(Swift_Mime_Message $message); - - /** - * Sends messages using the given transport instance. - * - * @param Swift_Transport $transport A transport instance - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int The number of sent emails - */ - public function flushQueue(Swift_Transport $transport, &$failedRecipients = null); -} diff --git a/tools/swift/classes/Swift/SpoolTransport.php b/tools/swift/classes/Swift/SpoolTransport.php deleted file mode 100644 index 79c9b1f03..000000000 --- a/tools/swift/classes/Swift/SpoolTransport.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Stores Messages in a queue. - * - * @author Fabien Potencier - */ -class Swift_SpoolTransport extends Swift_Transport_SpoolTransport -{ - /** - * Create a new SpoolTransport. - * - * @param Swift_Spool $spool - */ - public function __construct(Swift_Spool $spool) - { - $arguments = Swift_DependencyContainer::getInstance() - ->createDependenciesFor('transport.spool'); - - $arguments[] = $spool; - - call_user_func_array( - array($this, 'Swift_Transport_SpoolTransport::__construct'), - $arguments - ); - } - - /** - * Create a new SpoolTransport instance. - * - * @param Swift_Spool $spool - * - * @return self - */ - public static function newInstance(Swift_Spool $spool) - { - return new self($spool); - } -} diff --git a/tools/swift/classes/Swift/StreamFilter.php b/tools/swift/classes/Swift/StreamFilter.php deleted file mode 100644 index 362be2e8d..000000000 --- a/tools/swift/classes/Swift/StreamFilter.php +++ /dev/null @@ -1,35 +0,0 @@ -_search = $search; - $this->_index = array(); - $this->_tree = array(); - $this->_replace = array(); - $this->_repSize = array(); - - $tree = null; - $i = null; - $last_size = $size = 0; - foreach ($search as $i => $search_element) { - if ($tree !== null) { - $tree[-1] = min(count($replace) - 1, $i - 1); - $tree[-2] = $last_size; - } - $tree = &$this->_tree; - if (is_array($search_element)) { - foreach ($search_element as $k => $char) { - $this->_index[$char] = true; - if (!isset($tree[$char])) { - $tree[$char] = array(); - } - $tree = &$tree[$char]; - } - $last_size = $k + 1; - $size = max($size, $last_size); - } else { - $last_size = 1; - if (!isset($tree[$search_element])) { - $tree[$search_element] = array(); - } - $tree = &$tree[$search_element]; - $size = max($last_size, $size); - $this->_index[$search_element] = true; - } - } - if ($i !== null) { - $tree[-1] = min(count($replace) - 1, $i); - $tree[-2] = $last_size; - $this->_treeMaxLen = $size; - } - foreach ($replace as $rep) { - if (!is_array($rep)) { - $rep = array($rep); - } - $this->_replace[] = $rep; - } - for ($i = count($this->_replace) - 1; $i >= 0; --$i) { - $this->_replace[$i] = $rep = $this->filter($this->_replace[$i], $i); - $this->_repSize[$i] = count($rep); - } - } - - /** - * Returns true if based on the buffer passed more bytes should be buffered. - * - * @param array $buffer - * - * @return bool - */ - public function shouldBuffer($buffer) - { - $endOfBuffer = end($buffer); - - return isset($this->_index[$endOfBuffer]); - } - - /** - * Perform the actual replacements on $buffer and return the result. - * - * @param array $buffer - * @param int $_minReplaces - * - * @return array - */ - public function filter($buffer, $_minReplaces = -1) - { - if ($this->_treeMaxLen == 0) { - return $buffer; - } - - $newBuffer = array(); - $buf_size = count($buffer); - $last_size = 0; - for ($i = 0; $i < $buf_size; ++$i) { - $search_pos = $this->_tree; - $last_found = PHP_INT_MAX; - // We try to find if the next byte is part of a search pattern - for ($j = 0; $j <= $this->_treeMaxLen; ++$j) { - // We have a new byte for a search pattern - if (isset($buffer[$p = $i + $j]) && isset($search_pos[$buffer[$p]])) { - $search_pos = $search_pos[$buffer[$p]]; - // We have a complete pattern, save, in case we don't find a better match later - if (isset($search_pos[-1]) && $search_pos[-1] < $last_found - && $search_pos[-1] > $_minReplaces) { - $last_found = $search_pos[-1]; - $last_size = $search_pos[-2]; - } - } - // We got a complete pattern - elseif ($last_found !== PHP_INT_MAX) { - // Adding replacement datas to output buffer - $rep_size = $this->_repSize[$last_found]; - for ($j = 0; $j < $rep_size; ++$j) { - $newBuffer[] = $this->_replace[$last_found][$j]; - } - // We Move cursor forward - $i += $last_size - 1; - // Edge Case, last position in buffer - if ($i >= $buf_size) { - $newBuffer[] = $buffer[$i]; - } - - // We start the next loop - continue 2; - } else { - // this byte is not in a pattern and we haven't found another pattern - break; - } - } - // Normal byte, move it to output buffer - $newBuffer[] = $buffer[$i]; - } - - return $newBuffer; - } -} diff --git a/tools/swift/classes/Swift/StreamFilters/StringReplacementFilter.php b/tools/swift/classes/Swift/StreamFilters/StringReplacementFilter.php deleted file mode 100644 index f64144af2..000000000 --- a/tools/swift/classes/Swift/StreamFilters/StringReplacementFilter.php +++ /dev/null @@ -1,70 +0,0 @@ -_search = $search; - $this->_replace = $replace; - } - - /** - * Returns true if based on the buffer passed more bytes should be buffered. - * - * @param string $buffer - * - * @return bool - */ - public function shouldBuffer($buffer) - { - if ('' === $buffer) { - return false; - } - - $endOfBuffer = substr($buffer, -1); - foreach ((array) $this->_search as $needle) { - if (false !== strpos($needle, $endOfBuffer)) { - return true; - } - } - - return false; - } - - /** - * Perform the actual replacements on $buffer and return the result. - * - * @param string $buffer - * - * @return string - */ - public function filter($buffer) - { - return str_replace($this->_search, $this->_replace, $buffer); - } -} diff --git a/tools/swift/classes/Swift/StreamFilters/StringReplacementFilterFactory.php b/tools/swift/classes/Swift/StreamFilters/StringReplacementFilterFactory.php deleted file mode 100644 index e98240b5b..000000000 --- a/tools/swift/classes/Swift/StreamFilters/StringReplacementFilterFactory.php +++ /dev/null @@ -1,45 +0,0 @@ -_filters[$search][$replace])) { - if (!isset($this->_filters[$search])) { - $this->_filters[$search] = array(); - } - - if (!isset($this->_filters[$search][$replace])) { - $this->_filters[$search][$replace] = array(); - } - - $this->_filters[$search][$replace] = new Swift_StreamFilters_StringReplacementFilter($search, $replace); - } - - return $this->_filters[$search][$replace]; - } -} diff --git a/tools/swift/classes/Swift/SwiftException.php b/tools/swift/classes/Swift/SwiftException.php deleted file mode 100644 index db3d31093..000000000 --- a/tools/swift/classes/Swift/SwiftException.php +++ /dev/null @@ -1,29 +0,0 @@ -_eventDispatcher = $dispatcher; - $this->_buffer = $buf; - $this->_lookupHostname(); - } - - /** - * Set the name of the local domain which Swift will identify itself as. - * - * This should be a fully-qualified domain name and should be truly the domain - * you're using. - * - * If your server doesn't have a domain name, use the IP in square - * brackets (i.e. [127.0.0.1]). - * - * @param string $domain - * - * @return $this - */ - public function setLocalDomain($domain) - { - $this->_domain = $domain; - - return $this; - } - - /** - * Get the name of the domain Swift will identify as. - * - * @return string - */ - public function getLocalDomain() - { - return $this->_domain; - } - - /** - * Sets the source IP. - * - * @param string $source - */ - public function setSourceIp($source) - { - $this->_sourceIp = $source; - } - - /** - * Returns the IP used to connect to the destination. - * - * @return string - */ - public function getSourceIp() - { - return $this->_sourceIp; - } - - /** - * Start the SMTP connection. - */ - public function start() - { - if (!$this->_started) { - if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) { - $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStarted'); - if ($evt->bubbleCancelled()) { - return; - } - } - - try { - $this->_buffer->initialize($this->_getBufferParams()); - } catch (Swift_TransportException $e) { - $this->_throwException($e); - } - $this->_readGreeting(); - $this->_doHeloCommand(); - - if ($evt) { - $this->_eventDispatcher->dispatchEvent($evt, 'transportStarted'); - } - - $this->_started = true; - } - } - - /** - * Test if an SMTP connection has been established. - * - * @return bool - */ - public function isStarted() - { - return $this->_started; - } - - /** - * Send the given Message. - * - * Recipient/sender data will be retrieved from the Message API. - * The return value is the number of recipients who were accepted for delivery. - * - * @param Swift_Mime_Message $message - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int - */ - public function send(Swift_Mime_Message $message, &$failedRecipients = null) - { - $sent = 0; - $failedRecipients = (array) $failedRecipients; - - if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { - $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); - if ($evt->bubbleCancelled()) { - return 0; - } - } - - if (!$reversePath = $this->_getReversePath($message)) { - $this->_throwException(new Swift_TransportException( - 'Cannot send message without a sender address' - ) - ); - } - - $to = (array) $message->getTo(); - $cc = (array) $message->getCc(); - $tos = array_merge($to, $cc); - $bcc = (array) $message->getBcc(); - - $message->setBcc(array()); - - try { - $sent += $this->_sendTo($message, $reversePath, $tos, $failedRecipients); - $sent += $this->_sendBcc($message, $reversePath, $bcc, $failedRecipients); - } catch (Exception $e) { - $message->setBcc($bcc); - throw $e; - } - - $message->setBcc($bcc); - - if ($evt) { - if ($sent == count($to) + count($cc) + count($bcc)) { - $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); - } elseif ($sent > 0) { - $evt->setResult(Swift_Events_SendEvent::RESULT_TENTATIVE); - } else { - $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED); - } - $evt->setFailedRecipients($failedRecipients); - $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); - } - - $message->generateId(); //Make sure a new Message ID is used - - return $sent; - } - - /** - * Stop the SMTP connection. - */ - public function stop() - { - if ($this->_started) { - if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) { - $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStopped'); - if ($evt->bubbleCancelled()) { - return; - } - } - - try { - $this->executeCommand("QUIT\r\n", array(221)); - } catch (Swift_TransportException $e) { - } - - try { - $this->_buffer->terminate(); - - if ($evt) { - $this->_eventDispatcher->dispatchEvent($evt, 'transportStopped'); - } - } catch (Swift_TransportException $e) { - $this->_throwException($e); - } - } - $this->_started = false; - } - - /** - * Register a plugin. - * - * @param Swift_Events_EventListener $plugin - */ - public function registerPlugin(Swift_Events_EventListener $plugin) - { - $this->_eventDispatcher->bindEventListener($plugin); - } - - /** - * Reset the current mail transaction. - */ - public function reset() - { - $this->executeCommand("RSET\r\n", array(250)); - } - - /** - * Get the IoBuffer where read/writes are occurring. - * - * @return Swift_Transport_IoBuffer - */ - public function getBuffer() - { - return $this->_buffer; - } - - /** - * Run a command against the buffer, expecting the given response codes. - * - * If no response codes are given, the response will not be validated. - * If codes are given, an exception will be thrown on an invalid response. - * - * @param string $command - * @param int[] $codes - * @param string[] $failures An array of failures by-reference - * - * @return string - */ - public function executeCommand($command, $codes = array(), &$failures = null) - { - $failures = (array) $failures; - $seq = $this->_buffer->write($command); - $response = $this->_getFullResponse($seq); - if ($evt = $this->_eventDispatcher->createCommandEvent($this, $command, $codes)) { - $this->_eventDispatcher->dispatchEvent($evt, 'commandSent'); - } - $this->_assertResponseCode($response, $codes); - - return $response; - } - - /** Read the opening SMTP greeting */ - protected function _readGreeting() - { - $this->_assertResponseCode($this->_getFullResponse(0), array(220)); - } - - /** Send the HELO welcome */ - protected function _doHeloCommand() - { - $this->executeCommand( - sprintf("HELO %s\r\n", $this->_domain), array(250) - ); - } - - /** Send the MAIL FROM command */ - protected function _doMailFromCommand($address) - { - $this->executeCommand( - sprintf("MAIL FROM:<%s>\r\n", $address), array(250) - ); - } - - /** Send the RCPT TO command */ - protected function _doRcptToCommand($address) - { - $this->executeCommand( - sprintf("RCPT TO:<%s>\r\n", $address), array(250, 251, 252) - ); - } - - /** Send the DATA command */ - protected function _doDataCommand() - { - $this->executeCommand("DATA\r\n", array(354)); - } - - /** Stream the contents of the message over the buffer */ - protected function _streamMessage(Swift_Mime_Message $message) - { - $this->_buffer->setWriteTranslations(array("\r\n." => "\r\n..")); - try { - $message->toByteStream($this->_buffer); - $this->_buffer->flushBuffers(); - } catch (Swift_TransportException $e) { - $this->_throwException($e); - } - $this->_buffer->setWriteTranslations(array()); - $this->executeCommand("\r\n.\r\n", array(250)); - } - - /** Determine the best-use reverse path for this message */ - protected function _getReversePath(Swift_Mime_Message $message) - { - $return = $message->getReturnPath(); - $sender = $message->getSender(); - $from = $message->getFrom(); - $path = null; - if (!empty($return)) { - $path = $return; - } elseif (!empty($sender)) { - // Don't use array_keys - reset($sender); // Reset Pointer to first pos - $path = key($sender); // Get key - } elseif (!empty($from)) { - reset($from); // Reset Pointer to first pos - $path = key($from); // Get key - } - - return $path; - } - - /** Throw a TransportException, first sending it to any listeners */ - protected function _throwException(Swift_TransportException $e) - { - if ($evt = $this->_eventDispatcher->createTransportExceptionEvent($this, $e)) { - $this->_eventDispatcher->dispatchEvent($evt, 'exceptionThrown'); - if (!$evt->bubbleCancelled()) { - throw $e; - } - } else { - throw $e; - } - } - - /** Throws an Exception if a response code is incorrect */ - protected function _assertResponseCode($response, $wanted) - { - list($code) = sscanf($response, '%3d'); - $valid = (empty($wanted) || in_array($code, $wanted)); - - if ($evt = $this->_eventDispatcher->createResponseEvent($this, $response, - $valid)) { - $this->_eventDispatcher->dispatchEvent($evt, 'responseReceived'); - } - - if (!$valid) { - $this->_throwException( - new Swift_TransportException( - 'Expected response code '.implode('/', $wanted).' but got code '. - '"'.$code.'", with message "'.$response.'"', - $code) - ); - } - } - - /** Get an entire multi-line response using its sequence number */ - protected function _getFullResponse($seq) - { - $response = ''; - try { - do { - $line = $this->_buffer->readLine($seq); - $response .= $line; - } while (null !== $line && false !== $line && ' ' != $line[3]); - } catch (Swift_TransportException $e) { - $this->_throwException($e); - } catch (Swift_IoException $e) { - $this->_throwException( - new Swift_TransportException( - $e->getMessage()) - ); - } - - return $response; - } - - /** Send an email to the given recipients from the given reverse path */ - private function _doMailTransaction($message, $reversePath, array $recipients, array &$failedRecipients) - { - $sent = 0; - $this->_doMailFromCommand($reversePath); - foreach ($recipients as $forwardPath) { - try { - $this->_doRcptToCommand($forwardPath); - ++$sent; - } catch (Swift_TransportException $e) { - $failedRecipients[] = $forwardPath; - } - } - - if ($sent != 0) { - $this->_doDataCommand(); - $this->_streamMessage($message); - } else { - $this->reset(); - } - - return $sent; - } - - /** Send a message to the given To: recipients */ - private function _sendTo(Swift_Mime_Message $message, $reversePath, array $to, array &$failedRecipients) - { - if (empty($to)) { - return 0; - } - - return $this->_doMailTransaction($message, $reversePath, array_keys($to), - $failedRecipients); - } - - /** Send a message to all Bcc: recipients */ - private function _sendBcc(Swift_Mime_Message $message, $reversePath, array $bcc, array &$failedRecipients) - { - $sent = 0; - foreach ($bcc as $forwardPath => $name) { - $message->setBcc(array($forwardPath => $name)); - $sent += $this->_doMailTransaction( - $message, $reversePath, array($forwardPath), $failedRecipients - ); - } - - return $sent; - } - - /** Try to determine the hostname of the server this is run on */ - private function _lookupHostname() - { - if (!empty($_SERVER['SERVER_NAME']) && $this->_isFqdn($_SERVER['SERVER_NAME'])) { - $this->_domain = $_SERVER['SERVER_NAME']; - } elseif (!empty($_SERVER['SERVER_ADDR'])) { - // Set the address literal tag (See RFC 5321, section: 4.1.3) - if (false === strpos($_SERVER['SERVER_ADDR'], ':')) { - $prefix = ''; // IPv4 addresses are not tagged. - } else { - $prefix = 'IPv6:'; // Adding prefix in case of IPv6. - } - - $this->_domain = sprintf('[%s%s]', $prefix, $_SERVER['SERVER_ADDR']); - } - } - - /** Determine is the $hostname is a fully-qualified name */ - private function _isFqdn($hostname) - { - // We could do a really thorough check, but there's really no point - if (false !== $dotPos = strpos($hostname, '.')) { - return ($dotPos > 0) && ($dotPos != strlen($hostname) - 1); - } - - return false; - } - - /** - * Destructor. - */ - public function __destruct() - { - try { - $this->stop(); - } catch (Exception $e) { - } - } -} diff --git a/tools/swift/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php b/tools/swift/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php deleted file mode 100644 index 53f721d03..000000000 --- a/tools/swift/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php +++ /dev/null @@ -1,81 +0,0 @@ -executeCommand("AUTH CRAM-MD5\r\n", array(334)); - $challenge = base64_decode(substr($challenge, 4)); - $message = base64_encode( - $username.' '.$this->_getResponse($password, $challenge) - ); - $agent->executeCommand(sprintf("%s\r\n", $message), array(235)); - - return true; - } catch (Swift_TransportException $e) { - $agent->executeCommand("RSET\r\n", array(250)); - - return false; - } - } - - /** - * Generate a CRAM-MD5 response from a server challenge. - * - * @param string $secret - * @param string $challenge - * - * @return string - */ - private function _getResponse($secret, $challenge) - { - if (strlen($secret) > 64) { - $secret = pack('H32', md5($secret)); - } - - if (strlen($secret) < 64) { - $secret = str_pad($secret, 64, chr(0)); - } - - $k_ipad = substr($secret, 0, 64) ^ str_repeat(chr(0x36), 64); - $k_opad = substr($secret, 0, 64) ^ str_repeat(chr(0x5C), 64); - - $inner = pack('H32', md5($k_ipad.$challenge)); - $digest = md5($k_opad.$inner); - - return $digest; - } -} diff --git a/tools/swift/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php b/tools/swift/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php deleted file mode 100644 index 6ab6e3337..000000000 --- a/tools/swift/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php +++ /dev/null @@ -1,51 +0,0 @@ -executeCommand("AUTH LOGIN\r\n", array(334)); - $agent->executeCommand(sprintf("%s\r\n", base64_encode($username)), array(334)); - $agent->executeCommand(sprintf("%s\r\n", base64_encode($password)), array(235)); - - return true; - } catch (Swift_TransportException $e) { - $agent->executeCommand("RSET\r\n", array(250)); - - return false; - } - } -} diff --git a/tools/swift/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php b/tools/swift/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php deleted file mode 100644 index 839265857..000000000 --- a/tools/swift/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php +++ /dev/null @@ -1,725 +0,0 @@ - - */ -class Swift_Transport_Esmtp_Auth_NTLMAuthenticator implements Swift_Transport_Esmtp_Authenticator -{ - const NTLMSIG = "NTLMSSP\x00"; - const DESCONST = 'KGS!@#$%'; - - /** - * Get the name of the AUTH mechanism this Authenticator handles. - * - * @return string - */ - public function getAuthKeyword() - { - return 'NTLM'; - } - - /** - * Try to authenticate the user with $username and $password. - * - * @param Swift_Transport_SmtpAgent $agent - * @param string $username - * @param string $password - * - * @return bool - */ - public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password) - { - if (!function_exists('openssl_random_pseudo_bytes') || !function_exists('openssl_encrypt')) { - throw new LogicException('The OpenSSL extension must be enabled to use the NTLM authenticator.'); - } - - if (!function_exists('bcmul')) { - throw new LogicException('The BCMath functions must be enabled to use the NTLM authenticator.'); - } - - try { - // execute AUTH command and filter out the code at the beginning - // AUTH NTLM xxxx - $response = base64_decode(substr(trim($this->sendMessage1($agent)), 4)); - - // extra parameters for our unit cases - $timestamp = func_num_args() > 3 ? func_get_arg(3) : $this->getCorrectTimestamp(bcmul(microtime(true), '1000')); - $client = func_num_args() > 4 ? func_get_arg(4) : $this->getRandomBytes(8); - - // Message 3 response - $this->sendMessage3($response, $username, $password, $timestamp, $client, $agent); - - return true; - } catch (Swift_TransportException $e) { - $agent->executeCommand("RSET\r\n", array(250)); - - return false; - } - } - - protected function si2bin($si, $bits = 32) - { - $bin = null; - if ($si >= -pow(2, $bits - 1) && ($si <= pow(2, $bits - 1))) { - // positive or zero - if ($si >= 0) { - $bin = base_convert($si, 10, 2); - // pad to $bits bit - $bin_length = strlen($bin); - if ($bin_length < $bits) { - $bin = str_repeat('0', $bits - $bin_length).$bin; - } - } else { - // negative - $si = -$si - pow(2, $bits); - $bin = base_convert($si, 10, 2); - $bin_length = strlen($bin); - if ($bin_length > $bits) { - $bin = str_repeat('1', $bits - $bin_length).$bin; - } - } - } - - return $bin; - } - - /** - * Send our auth message and returns the response. - * - * @param Swift_Transport_SmtpAgent $agent - * - * @return string SMTP Response - */ - protected function sendMessage1(Swift_Transport_SmtpAgent $agent) - { - $message = $this->createMessage1(); - - return $agent->executeCommand(sprintf("AUTH %s %s\r\n", $this->getAuthKeyword(), base64_encode($message)), array(334)); - } - - /** - * Fetch all details of our response (message 2). - * - * @param string $response - * - * @return array our response parsed - */ - protected function parseMessage2($response) - { - $responseHex = bin2hex($response); - $length = floor(hexdec(substr($responseHex, 28, 4)) / 256) * 2; - $offset = floor(hexdec(substr($responseHex, 32, 4)) / 256) * 2; - $challenge = $this->hex2bin(substr($responseHex, 48, 16)); - $context = $this->hex2bin(substr($responseHex, 64, 16)); - $targetInfoH = $this->hex2bin(substr($responseHex, 80, 16)); - $targetName = $this->hex2bin(substr($responseHex, $offset, $length)); - $offset = floor(hexdec(substr($responseHex, 88, 4)) / 256) * 2; - $targetInfoBlock = substr($responseHex, $offset); - list($domainName, $serverName, $DNSDomainName, $DNSServerName, $terminatorByte) = $this->readSubBlock($targetInfoBlock); - - return array( - $challenge, - $context, - $targetInfoH, - $targetName, - $domainName, - $serverName, - $DNSDomainName, - $DNSServerName, - $this->hex2bin($targetInfoBlock), - $terminatorByte, - ); - } - - /** - * Read the blob information in from message2. - * - * @param $block - * - * @return array - */ - protected function readSubBlock($block) - { - // remove terminatorByte cause it's always the same - $block = substr($block, 0, -8); - - $length = strlen($block); - $offset = 0; - $data = array(); - while ($offset < $length) { - $blockLength = hexdec(substr(substr($block, $offset, 8), -4)) / 256; - $offset += 8; - $data[] = $this->hex2bin(substr($block, $offset, $blockLength * 2)); - $offset += $blockLength * 2; - } - - if (count($data) == 3) { - $data[] = $data[2]; - $data[2] = ''; - } - - $data[] = $this->createByte('00'); - - return $data; - } - - /** - * Send our final message with all our data. - * - * @param string $response Message 1 response (message 2) - * @param string $username - * @param string $password - * @param string $timestamp - * @param string $client - * @param Swift_Transport_SmtpAgent $agent - * @param bool $v2 Use version2 of the protocol - * - * @return string - */ - protected function sendMessage3($response, $username, $password, $timestamp, $client, Swift_Transport_SmtpAgent $agent, $v2 = true) - { - list($domain, $username) = $this->getDomainAndUsername($username); - //$challenge, $context, $targetInfoH, $targetName, $domainName, $workstation, $DNSDomainName, $DNSServerName, $blob, $ter - list($challenge, , , , , $workstation, , , $blob) = $this->parseMessage2($response); - - if (!$v2) { - // LMv1 - $lmResponse = $this->createLMPassword($password, $challenge); - // NTLMv1 - $ntlmResponse = $this->createNTLMPassword($password, $challenge); - } else { - // LMv2 - $lmResponse = $this->createLMv2Password($password, $username, $domain, $challenge, $client); - // NTLMv2 - $ntlmResponse = $this->createNTLMv2Hash($password, $username, $domain, $challenge, $blob, $timestamp, $client); - } - - $message = $this->createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse); - - return $agent->executeCommand(sprintf("%s\r\n", base64_encode($message)), array(235)); - } - - /** - * Create our message 1. - * - * @return string - */ - protected function createMessage1() - { - return self::NTLMSIG - .$this->createByte('01') // Message 1 -.$this->createByte('0702'); // Flags - } - - /** - * Create our message 3. - * - * @param string $domain - * @param string $username - * @param string $workstation - * @param string $lmResponse - * @param string $ntlmResponse - * - * @return string - */ - protected function createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse) - { - // Create security buffers - $domainSec = $this->createSecurityBuffer($domain, 64); - $domainInfo = $this->readSecurityBuffer(bin2hex($domainSec)); - $userSec = $this->createSecurityBuffer($username, ($domainInfo[0] + $domainInfo[1]) / 2); - $userInfo = $this->readSecurityBuffer(bin2hex($userSec)); - $workSec = $this->createSecurityBuffer($workstation, ($userInfo[0] + $userInfo[1]) / 2); - $workInfo = $this->readSecurityBuffer(bin2hex($workSec)); - $lmSec = $this->createSecurityBuffer($lmResponse, ($workInfo[0] + $workInfo[1]) / 2, true); - $lmInfo = $this->readSecurityBuffer(bin2hex($lmSec)); - $ntlmSec = $this->createSecurityBuffer($ntlmResponse, ($lmInfo[0] + $lmInfo[1]) / 2, true); - - return self::NTLMSIG - .$this->createByte('03') // TYPE 3 message -.$lmSec // LM response header -.$ntlmSec // NTLM response header -.$domainSec // Domain header -.$userSec // User header -.$workSec // Workstation header -.$this->createByte('000000009a', 8) // session key header (empty) -.$this->createByte('01020000') // FLAGS -.$this->convertTo16bit($domain) // domain name -.$this->convertTo16bit($username) // username -.$this->convertTo16bit($workstation) // workstation -.$lmResponse - .$ntlmResponse; - } - - /** - * @param string $timestamp Epoch timestamp in microseconds - * @param string $client Random bytes - * @param string $targetInfo - * - * @return string - */ - protected function createBlob($timestamp, $client, $targetInfo) - { - return $this->createByte('0101') - .$this->createByte('00') - .$timestamp - .$client - .$this->createByte('00') - .$targetInfo - .$this->createByte('00'); - } - - /** - * Get domain and username from our username. - * - * @example DOMAIN\username - * - * @param string $name - * - * @return array - */ - protected function getDomainAndUsername($name) - { - if (strpos($name, '\\') !== false) { - return explode('\\', $name); - } - - if (false !== strpos($name, '@')) { - list($user, $domain) = explode('@', $name); - - return array($domain, $user); - } - - // no domain passed - return array('', $name); - } - - /** - * Create LMv1 response. - * - * @param string $password - * @param string $challenge - * - * @return string - */ - protected function createLMPassword($password, $challenge) - { - // FIRST PART - $password = $this->createByte(strtoupper($password), 14, false); - list($key1, $key2) = str_split($password, 7); - - $desKey1 = $this->createDesKey($key1); - $desKey2 = $this->createDesKey($key2); - - $constantDecrypt = $this->createByte($this->desEncrypt(self::DESCONST, $desKey1).$this->desEncrypt(self::DESCONST, $desKey2), 21, false); - - // SECOND PART - list($key1, $key2, $key3) = str_split($constantDecrypt, 7); - - $desKey1 = $this->createDesKey($key1); - $desKey2 = $this->createDesKey($key2); - $desKey3 = $this->createDesKey($key3); - - return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3); - } - - /** - * Create NTLMv1 response. - * - * @param string $password - * @param string $challenge - * - * @return string - */ - protected function createNTLMPassword($password, $challenge) - { - // FIRST PART - $ntlmHash = $this->createByte($this->md4Encrypt($password), 21, false); - list($key1, $key2, $key3) = str_split($ntlmHash, 7); - - $desKey1 = $this->createDesKey($key1); - $desKey2 = $this->createDesKey($key2); - $desKey3 = $this->createDesKey($key3); - - return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3); - } - - /** - * Convert a normal timestamp to a tenth of a microtime epoch time. - * - * @param string $time - * - * @return string - */ - protected function getCorrectTimestamp($time) - { - // Get our timestamp (tricky!) - $time = number_format($time, 0, '.', ''); // save microtime to string - $time = bcadd($time, '11644473600000', 0); // add epoch time - $time = bcmul($time, 10000, 0); // tenths of a microsecond. - - $binary = $this->si2bin($time, 64); // create 64 bit binary string - $timestamp = ''; - for ($i = 0; $i < 8; ++$i) { - $timestamp .= chr(bindec(substr($binary, -(($i + 1) * 8), 8))); - } - - return $timestamp; - } - - /** - * Create LMv2 response. - * - * @param string $password - * @param string $username - * @param string $domain - * @param string $challenge NTLM Challenge - * @param string $client Random string - * - * @return string - */ - protected function createLMv2Password($password, $username, $domain, $challenge, $client) - { - $lmPass = '00'; // by default 00 - // if $password > 15 than we can't use this method - if (strlen($password) <= 15) { - $ntlmHash = $this->md4Encrypt($password); - $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain)); - - $lmPass = bin2hex($this->md5Encrypt($ntml2Hash, $challenge.$client).$client); - } - - return $this->createByte($lmPass, 24); - } - - /** - * Create NTLMv2 response. - * - * @param string $password - * @param string $username - * @param string $domain - * @param string $challenge Hex values - * @param string $targetInfo Hex values - * @param string $timestamp - * @param string $client Random bytes - * - * @return string - * - * @see http://davenport.sourceforge.net/ntlm.html#theNtlmResponse - */ - protected function createNTLMv2Hash($password, $username, $domain, $challenge, $targetInfo, $timestamp, $client) - { - $ntlmHash = $this->md4Encrypt($password); - $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain)); - - // create blob - $blob = $this->createBlob($timestamp, $client, $targetInfo); - - $ntlmv2Response = $this->md5Encrypt($ntml2Hash, $challenge.$blob); - - return $ntlmv2Response.$blob; - } - - protected function createDesKey($key) - { - $material = array(bin2hex($key[0])); - $len = strlen($key); - for ($i = 1; $i < $len; ++$i) { - list($high, $low) = str_split(bin2hex($key[$i])); - $v = $this->castToByte(ord($key[$i - 1]) << (7 + 1 - $i) | $this->uRShift(hexdec(dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xf)), $i)); - $material[] = str_pad(substr(dechex($v), -2), 2, '0', STR_PAD_LEFT); // cast to byte - } - $material[] = str_pad(substr(dechex($this->castToByte(ord($key[6]) << 1)), -2), 2, '0'); - - // odd parity - foreach ($material as $k => $v) { - $b = $this->castToByte(hexdec($v)); - $needsParity = (($this->uRShift($b, 7) ^ $this->uRShift($b, 6) ^ $this->uRShift($b, 5) - ^ $this->uRShift($b, 4) ^ $this->uRShift($b, 3) ^ $this->uRShift($b, 2) - ^ $this->uRShift($b, 1)) & 0x01) == 0; - - list($high, $low) = str_split($v); - if ($needsParity) { - $material[$k] = dechex(hexdec($high) | 0x0).dechex(hexdec($low) | 0x1); - } else { - $material[$k] = dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xe); - } - } - - return $this->hex2bin(implode('', $material)); - } - - /** HELPER FUNCTIONS */ - - /** - * Create our security buffer depending on length and offset. - * - * @param string $value Value we want to put in - * @param int $offset start of value - * @param bool $is16 Do we 16bit string or not? - * - * @return string - */ - protected function createSecurityBuffer($value, $offset, $is16 = false) - { - $length = strlen(bin2hex($value)); - $length = $is16 ? $length / 2 : $length; - $length = $this->createByte(str_pad(dechex($length), 2, '0', STR_PAD_LEFT), 2); - - return $length.$length.$this->createByte(dechex($offset), 4); - } - - /** - * Read our security buffer to fetch length and offset of our value. - * - * @param string $value Securitybuffer in hex - * - * @return array array with length and offset - */ - protected function readSecurityBuffer($value) - { - $length = floor(hexdec(substr($value, 0, 4)) / 256) * 2; - $offset = floor(hexdec(substr($value, 8, 4)) / 256) * 2; - - return array($length, $offset); - } - - /** - * Cast to byte java equivalent to (byte). - * - * @param int $v - * - * @return int - */ - protected function castToByte($v) - { - return (($v + 128) % 256) - 128; - } - - /** - * Java unsigned right bitwise - * $a >>> $b. - * - * @param int $a - * @param int $b - * - * @return int - */ - protected function uRShift($a, $b) - { - if ($b == 0) { - return $a; - } - - return ($a >> $b) & ~(1 << (8 * PHP_INT_SIZE - 1) >> ($b - 1)); - } - - /** - * Right padding with 0 to certain length. - * - * @param string $input - * @param int $bytes Length of bytes - * @param bool $isHex Did we provided hex value - * - * @return string - */ - protected function createByte($input, $bytes = 4, $isHex = true) - { - if ($isHex) { - $byte = $this->hex2bin(str_pad($input, $bytes * 2, '00')); - } else { - $byte = str_pad($input, $bytes, "\x00"); - } - - return $byte; - } - - /** - * Create random bytes. - * - * @param $length - * - * @return string - */ - protected function getRandomBytes($length) - { - $bytes = openssl_random_pseudo_bytes($length, $strong); - - if (false !== $bytes && true === $strong) { - return $bytes; - } - - throw new RuntimeException('OpenSSL did not produce a secure random number.'); - } - - /** ENCRYPTION ALGORITHMS */ - - /** - * DES Encryption. - * - * @param string $value An 8-byte string - * @param string $key - * - * @return string - */ - protected function desEncrypt($value, $key) - { - // 1 == OPENSSL_RAW_DATA - but constant is only available as of PHP 5.4. - return substr(openssl_encrypt($value, 'DES-ECB', $key, 1), 0, 8); - } - - /** - * MD5 Encryption. - * - * @param string $key Encryption key - * @param string $msg Message to encrypt - * - * @return string - */ - protected function md5Encrypt($key, $msg) - { - $blocksize = 64; - if (strlen($key) > $blocksize) { - $key = pack('H*', md5($key)); - } - - $key = str_pad($key, $blocksize, "\0"); - $ipadk = $key ^ str_repeat("\x36", $blocksize); - $opadk = $key ^ str_repeat("\x5c", $blocksize); - - return pack('H*', md5($opadk.pack('H*', md5($ipadk.$msg)))); - } - - /** - * MD4 Encryption. - * - * @param string $input - * - * @return string - * - * @see http://php.net/manual/en/ref.hash.php - */ - protected function md4Encrypt($input) - { - $input = $this->convertTo16bit($input); - - return function_exists('hash') ? $this->hex2bin(hash('md4', $input)) : mhash(MHASH_MD4, $input); - } - - /** - * Convert UTF-8 to UTF-16. - * - * @param string $input - * - * @return string - */ - protected function convertTo16bit($input) - { - return iconv('UTF-8', 'UTF-16LE', $input); - } - - /** - * Hex2bin replacement for < PHP 5.4. - * - * @param string $hex - * - * @return string Binary - */ - protected function hex2bin($hex) - { - if (function_exists('hex2bin')) { - return hex2bin($hex); - } else { - return pack('H*', $hex); - } - } - - /** - * @param string $message - */ - protected function debug($message) - { - $message = bin2hex($message); - $messageId = substr($message, 16, 8); - echo substr($message, 0, 16)." NTLMSSP Signature
\n"; - echo $messageId." Type Indicator
\n"; - - if ($messageId == '02000000') { - $map = array( - 'Challenge', - 'Context', - 'Target Information Security Buffer', - 'Target Name Data', - 'NetBIOS Domain Name', - 'NetBIOS Server Name', - 'DNS Domain Name', - 'DNS Server Name', - 'BLOB', - 'Target Information Terminator', - ); - - $data = $this->parseMessage2($this->hex2bin($message)); - - foreach ($map as $key => $value) { - echo bin2hex($data[$key]).' - '.$data[$key].' ||| '.$value."
\n"; - } - } elseif ($messageId == '03000000') { - $i = 0; - $data[$i++] = substr($message, 24, 16); - list($lmLength, $lmOffset) = $this->readSecurityBuffer($data[$i - 1]); - - $data[$i++] = substr($message, 40, 16); - list($ntmlLength, $ntmlOffset) = $this->readSecurityBuffer($data[$i - 1]); - - $data[$i++] = substr($message, 56, 16); - list($targetLength, $targetOffset) = $this->readSecurityBuffer($data[$i - 1]); - - $data[$i++] = substr($message, 72, 16); - list($userLength, $userOffset) = $this->readSecurityBuffer($data[$i - 1]); - - $data[$i++] = substr($message, 88, 16); - list($workLength, $workOffset) = $this->readSecurityBuffer($data[$i - 1]); - - $data[$i++] = substr($message, 104, 16); - $data[$i++] = substr($message, 120, 8); - $data[$i++] = substr($message, $targetOffset, $targetLength); - $data[$i++] = substr($message, $userOffset, $userLength); - $data[$i++] = substr($message, $workOffset, $workLength); - $data[$i++] = substr($message, $lmOffset, $lmLength); - $data[$i] = substr($message, $ntmlOffset, $ntmlLength); - - $map = array( - 'LM Response Security Buffer', - 'NTLM Response Security Buffer', - 'Target Name Security Buffer', - 'User Name Security Buffer', - 'Workstation Name Security Buffer', - 'Session Key Security Buffer', - 'Flags', - 'Target Name Data', - 'User Name Data', - 'Workstation Name Data', - 'LM Response Data', - 'NTLM Response Data', - ); - - foreach ($map as $key => $value) { - echo $data[$key].' - '.$this->hex2bin($data[$key]).' ||| '.$value."
\n"; - } - } - - echo '

'; - } -} diff --git a/tools/swift/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php b/tools/swift/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php deleted file mode 100644 index 43219f934..000000000 --- a/tools/swift/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php +++ /dev/null @@ -1,50 +0,0 @@ -executeCommand(sprintf("AUTH PLAIN %s\r\n", $message), array(235)); - - return true; - } catch (Swift_TransportException $e) { - $agent->executeCommand("RSET\r\n", array(250)); - - return false; - } - } -} diff --git a/tools/swift/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php b/tools/swift/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php deleted file mode 100644 index ca35e7b83..000000000 --- a/tools/swift/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php +++ /dev/null @@ -1,70 +0,0 @@ - - * $transport = Swift_SmtpTransport::newInstance('smtp.gmail.com', 587, 'tls') - * ->setAuthMode('XOAUTH2') - * ->setUsername('YOUR_EMAIL_ADDRESS') - * ->setPassword('YOUR_ACCESS_TOKEN'); - * - * - * @author xu.li - * - * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol - */ -class Swift_Transport_Esmtp_Auth_XOAuth2Authenticator implements Swift_Transport_Esmtp_Authenticator -{ - /** - * Get the name of the AUTH mechanism this Authenticator handles. - * - * @return string - */ - public function getAuthKeyword() - { - return 'XOAUTH2'; - } - - /** - * Try to authenticate the user with $email and $token. - * - * @param Swift_Transport_SmtpAgent $agent - * @param string $email - * @param string $token - * - * @return bool - */ - public function authenticate(Swift_Transport_SmtpAgent $agent, $email, $token) - { - try { - $param = $this->constructXOAuth2Params($email, $token); - $agent->executeCommand('AUTH XOAUTH2 '.$param."\r\n", array(235)); - - return true; - } catch (Swift_TransportException $e) { - $agent->executeCommand("RSET\r\n", array(250)); - - return false; - } - } - - /** - * Construct the auth parameter. - * - * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol#the_sasl_xoauth2_mechanism - */ - protected function constructXOAuth2Params($email, $token) - { - return base64_encode("user=$email\1auth=Bearer $token\1\1"); - } -} diff --git a/tools/swift/classes/Swift/Transport/Esmtp/AuthHandler.php b/tools/swift/classes/Swift/Transport/Esmtp/AuthHandler.php deleted file mode 100644 index cb36133c9..000000000 --- a/tools/swift/classes/Swift/Transport/Esmtp/AuthHandler.php +++ /dev/null @@ -1,263 +0,0 @@ -setAuthenticators($authenticators); - } - - /** - * Set the Authenticators which can process a login request. - * - * @param Swift_Transport_Esmtp_Authenticator[] $authenticators - */ - public function setAuthenticators(array $authenticators) - { - $this->_authenticators = $authenticators; - } - - /** - * Get the Authenticators which can process a login request. - * - * @return Swift_Transport_Esmtp_Authenticator[] - */ - public function getAuthenticators() - { - return $this->_authenticators; - } - - /** - * Set the username to authenticate with. - * - * @param string $username - */ - public function setUsername($username) - { - $this->_username = $username; - } - - /** - * Get the username to authenticate with. - * - * @return string - */ - public function getUsername() - { - return $this->_username; - } - - /** - * Set the password to authenticate with. - * - * @param string $password - */ - public function setPassword($password) - { - $this->_password = $password; - } - - /** - * Get the password to authenticate with. - * - * @return string - */ - public function getPassword() - { - return $this->_password; - } - - /** - * Set the auth mode to use to authenticate. - * - * @param string $mode - */ - public function setAuthMode($mode) - { - $this->_auth_mode = $mode; - } - - /** - * Get the auth mode to use to authenticate. - * - * @return string - */ - public function getAuthMode() - { - return $this->_auth_mode; - } - - /** - * Get the name of the ESMTP extension this handles. - * - * @return bool - */ - public function getHandledKeyword() - { - return 'AUTH'; - } - - /** - * Set the parameters which the EHLO greeting indicated. - * - * @param string[] $parameters - */ - public function setKeywordParams(array $parameters) - { - $this->_esmtpParams = $parameters; - } - - /** - * Runs immediately after a EHLO has been issued. - * - * @param Swift_Transport_SmtpAgent $agent to read/write - */ - public function afterEhlo(Swift_Transport_SmtpAgent $agent) - { - if ($this->_username) { - $count = 0; - foreach ($this->_getAuthenticatorsForAgent() as $authenticator) { - if (in_array(strtolower($authenticator->getAuthKeyword()), - array_map('strtolower', $this->_esmtpParams))) { - ++$count; - if ($authenticator->authenticate($agent, $this->_username, $this->_password)) { - return; - } - } - } - throw new Swift_TransportException( - 'Failed to authenticate on SMTP server with username "'. - $this->_username.'" using '.$count.' possible authenticators' - ); - } - } - - /** - * Not used. - */ - public function getMailParams() - { - return array(); - } - - /** - * Not used. - */ - public function getRcptParams() - { - return array(); - } - - /** - * Not used. - */ - public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = array(), &$failedRecipients = null, &$stop = false) - { - } - - /** - * Returns +1, -1 or 0 according to the rules for usort(). - * - * This method is called to ensure extensions can be execute in an appropriate order. - * - * @param string $esmtpKeyword to compare with - * - * @return int - */ - public function getPriorityOver($esmtpKeyword) - { - return 0; - } - - /** - * Returns an array of method names which are exposed to the Esmtp class. - * - * @return string[] - */ - public function exposeMixinMethods() - { - return array('setUsername', 'getUsername', 'setPassword', 'getPassword', 'setAuthMode', 'getAuthMode'); - } - - /** - * Not used. - */ - public function resetState() - { - } - - /** - * Returns the authenticator list for the given agent. - * - * @param Swift_Transport_SmtpAgent $agent - * - * @return array - */ - protected function _getAuthenticatorsForAgent() - { - if (!$mode = strtolower($this->_auth_mode)) { - return $this->_authenticators; - } - - foreach ($this->_authenticators as $authenticator) { - if (strtolower($authenticator->getAuthKeyword()) == $mode) { - return array($authenticator); - } - } - - throw new Swift_TransportException('Auth mode '.$mode.' is invalid'); - } -} diff --git a/tools/swift/classes/Swift/Transport/Esmtp/Authenticator.php b/tools/swift/classes/Swift/Transport/Esmtp/Authenticator.php deleted file mode 100644 index 12a9abf81..000000000 --- a/tools/swift/classes/Swift/Transport/Esmtp/Authenticator.php +++ /dev/null @@ -1,35 +0,0 @@ -. - * - * @return string[] - */ - public function getMailParams(); - - /** - * Get params which are appended to RCPT TO:<>. - * - * @return string[] - */ - public function getRcptParams(); - - /** - * Runs when a command is due to be sent. - * - * @param Swift_Transport_SmtpAgent $agent to read/write - * @param string $command to send - * @param int[] $codes expected in response - * @param string[] $failedRecipients to collect failures - * @param bool $stop to be set true by-reference if the command is now sent - */ - public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = array(), &$failedRecipients = null, &$stop = false); - - /** - * Returns +1, -1 or 0 according to the rules for usort(). - * - * This method is called to ensure extensions can be execute in an appropriate order. - * - * @param string $esmtpKeyword to compare with - * - * @return int - */ - public function getPriorityOver($esmtpKeyword); - - /** - * Returns an array of method names which are exposed to the Esmtp class. - * - * @return string[] - */ - public function exposeMixinMethods(); - - /** - * Tells this handler to clear any buffers and reset its state. - */ - public function resetState(); -} diff --git a/tools/swift/classes/Swift/Transport/EsmtpTransport.php b/tools/swift/classes/Swift/Transport/EsmtpTransport.php deleted file mode 100644 index 156e2cf5b..000000000 --- a/tools/swift/classes/Swift/Transport/EsmtpTransport.php +++ /dev/null @@ -1,411 +0,0 @@ - 'tcp', - 'host' => 'localhost', - 'port' => 25, - 'timeout' => 30, - 'blocking' => 1, - 'tls' => false, - 'type' => Swift_Transport_IoBuffer::TYPE_SOCKET, - 'stream_context_options' => array(), - ); - - /** - * Creates a new EsmtpTransport using the given I/O buffer. - * - * @param Swift_Transport_IoBuffer $buf - * @param Swift_Transport_EsmtpHandler[] $extensionHandlers - * @param Swift_Events_EventDispatcher $dispatcher - */ - public function __construct(Swift_Transport_IoBuffer $buf, array $extensionHandlers, Swift_Events_EventDispatcher $dispatcher) - { - parent::__construct($buf, $dispatcher); - $this->setExtensionHandlers($extensionHandlers); - } - - /** - * Set the host to connect to. - * - * @param string $host - * - * @return $this - */ - public function setHost($host) - { - $this->_params['host'] = $host; - - return $this; - } - - /** - * Get the host to connect to. - * - * @return string - */ - public function getHost() - { - return $this->_params['host']; - } - - /** - * Set the port to connect to. - * - * @param int $port - * - * @return $this - */ - public function setPort($port) - { - $this->_params['port'] = (int) $port; - - return $this; - } - - /** - * Get the port to connect to. - * - * @return int - */ - public function getPort() - { - return $this->_params['port']; - } - - /** - * Set the connection timeout. - * - * @param int $timeout seconds - * - * @return $this - */ - public function setTimeout($timeout) - { - $this->_params['timeout'] = (int) $timeout; - $this->_buffer->setParam('timeout', (int) $timeout); - - return $this; - } - - /** - * Get the connection timeout. - * - * @return int - */ - public function getTimeout() - { - return $this->_params['timeout']; - } - - /** - * Set the encryption type (tls or ssl). - * - * @param string $encryption - * - * @return $this - */ - public function setEncryption($encryption) - { - $encryption = strtolower($encryption); - if ('tls' == $encryption) { - $this->_params['protocol'] = 'tcp'; - $this->_params['tls'] = true; - } else { - $this->_params['protocol'] = $encryption; - $this->_params['tls'] = false; - } - - return $this; - } - - /** - * Get the encryption type. - * - * @return string - */ - public function getEncryption() - { - return $this->_params['tls'] ? 'tls' : $this->_params['protocol']; - } - - /** - * Sets the stream context options. - * - * @param array $options - * - * @return $this - */ - public function setStreamOptions($options) - { - $this->_params['stream_context_options'] = $options; - - return $this; - } - - /** - * Returns the stream context options. - * - * @return array - */ - public function getStreamOptions() - { - return $this->_params['stream_context_options']; - } - - /** - * Sets the source IP. - * - * @param string $source - * - * @return $this - */ - public function setSourceIp($source) - { - $this->_params['sourceIp'] = $source; - - return $this; - } - - /** - * Returns the IP used to connect to the destination. - * - * @return string - */ - public function getSourceIp() - { - return isset($this->_params['sourceIp']) ? $this->_params['sourceIp'] : null; - } - - /** - * Set ESMTP extension handlers. - * - * @param Swift_Transport_EsmtpHandler[] $handlers - * - * @return $this - */ - public function setExtensionHandlers(array $handlers) - { - $assoc = array(); - foreach ($handlers as $handler) { - $assoc[$handler->getHandledKeyword()] = $handler; - } - - @uasort($assoc, array($this, '_sortHandlers')); - $this->_handlers = $assoc; - $this->_setHandlerParams(); - - return $this; - } - - /** - * Get ESMTP extension handlers. - * - * @return Swift_Transport_EsmtpHandler[] - */ - public function getExtensionHandlers() - { - return array_values($this->_handlers); - } - - /** - * Run a command against the buffer, expecting the given response codes. - * - * If no response codes are given, the response will not be validated. - * If codes are given, an exception will be thrown on an invalid response. - * - * @param string $command - * @param int[] $codes - * @param string[] $failures An array of failures by-reference - * - * @return string - */ - public function executeCommand($command, $codes = array(), &$failures = null) - { - $failures = (array) $failures; - $stopSignal = false; - $response = null; - foreach ($this->_getActiveHandlers() as $handler) { - $response = $handler->onCommand( - $this, $command, $codes, $failures, $stopSignal - ); - if ($stopSignal) { - return $response; - } - } - - return parent::executeCommand($command, $codes, $failures); - } - - /** Mixin handling method for ESMTP handlers */ - public function __call($method, $args) - { - foreach ($this->_handlers as $handler) { - if (in_array(strtolower($method), - array_map('strtolower', (array) $handler->exposeMixinMethods()) - )) { - $return = call_user_func_array(array($handler, $method), $args); - // Allow fluid method calls - if (null === $return && substr($method, 0, 3) == 'set') { - return $this; - } else { - return $return; - } - } - } - trigger_error('Call to undefined method '.$method, E_USER_ERROR); - } - - /** Get the params to initialize the buffer */ - protected function _getBufferParams() - { - return $this->_params; - } - - /** Overridden to perform EHLO instead */ - protected function _doHeloCommand() - { - try { - $response = $this->executeCommand( - sprintf("EHLO %s\r\n", $this->_domain), array(250) - ); - } catch (Swift_TransportException $e) { - return parent::_doHeloCommand(); - } - - if ($this->_params['tls']) { - try { - $this->executeCommand("STARTTLS\r\n", array(220)); - - if (!$this->_buffer->startTLS()) { - throw new Swift_TransportException('Unable to connect with TLS encryption'); - } - - try { - $response = $this->executeCommand( - sprintf("EHLO %s\r\n", $this->_domain), array(250) - ); - } catch (Swift_TransportException $e) { - return parent::_doHeloCommand(); - } - } catch (Swift_TransportException $e) { - $this->_throwException($e); - } - } - - $this->_capabilities = $this->_getCapabilities($response); - $this->_setHandlerParams(); - foreach ($this->_getActiveHandlers() as $handler) { - $handler->afterEhlo($this); - } - } - - /** Overridden to add Extension support */ - protected function _doMailFromCommand($address) - { - $handlers = $this->_getActiveHandlers(); - $params = array(); - foreach ($handlers as $handler) { - $params = array_merge($params, (array) $handler->getMailParams()); - } - $paramStr = !empty($params) ? ' '.implode(' ', $params) : ''; - $this->executeCommand( - sprintf("MAIL FROM:<%s>%s\r\n", $address, $paramStr), array(250) - ); - } - - /** Overridden to add Extension support */ - protected function _doRcptToCommand($address) - { - $handlers = $this->_getActiveHandlers(); - $params = array(); - foreach ($handlers as $handler) { - $params = array_merge($params, (array) $handler->getRcptParams()); - } - $paramStr = !empty($params) ? ' '.implode(' ', $params) : ''; - $this->executeCommand( - sprintf("RCPT TO:<%s>%s\r\n", $address, $paramStr), array(250, 251, 252) - ); - } - - /** Determine ESMTP capabilities by function group */ - private function _getCapabilities($ehloResponse) - { - $capabilities = array(); - $ehloResponse = trim($ehloResponse); - $lines = explode("\r\n", $ehloResponse); - array_shift($lines); - foreach ($lines as $line) { - if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di', $line, $matches)) { - $keyword = strtoupper($matches[1]); - $paramStr = strtoupper(ltrim($matches[2], ' =')); - $params = !empty($paramStr) ? explode(' ', $paramStr) : array(); - $capabilities[$keyword] = $params; - } - } - - return $capabilities; - } - - /** Set parameters which are used by each extension handler */ - private function _setHandlerParams() - { - foreach ($this->_handlers as $keyword => $handler) { - if (array_key_exists($keyword, $this->_capabilities)) { - $handler->setKeywordParams($this->_capabilities[$keyword]); - } - } - } - - /** Get ESMTP handlers which are currently ok to use */ - private function _getActiveHandlers() - { - $handlers = array(); - foreach ($this->_handlers as $keyword => $handler) { - if (array_key_exists($keyword, $this->_capabilities)) { - $handlers[] = $handler; - } - } - - return $handlers; - } - - /** Custom sort for extension handler ordering */ - private function _sortHandlers($a, $b) - { - return $a->getPriorityOver($b->getHandledKeyword()); - } -} diff --git a/tools/swift/classes/Swift/Transport/FailoverTransport.php b/tools/swift/classes/Swift/Transport/FailoverTransport.php deleted file mode 100644 index 311a0f2ad..000000000 --- a/tools/swift/classes/Swift/Transport/FailoverTransport.php +++ /dev/null @@ -1,88 +0,0 @@ -_transports); - $sent = 0; - $this->_lastUsedTransport = null; - - for ($i = 0; $i < $maxTransports - && $transport = $this->_getNextTransport(); ++$i) { - try { - if (!$transport->isStarted()) { - $transport->start(); - } - - if ($sent = $transport->send($message, $failedRecipients)) { - $this->_lastUsedTransport = $transport; - - return $sent; - } - } catch (Swift_TransportException $e) { - $this->_killCurrentTransport(); - } - } - - if (count($this->_transports) == 0) { - throw new Swift_TransportException( - 'All Transports in FailoverTransport failed, or no Transports available' - ); - } - - return $sent; - } - - protected function _getNextTransport() - { - if (!isset($this->_currentTransport)) { - $this->_currentTransport = parent::_getNextTransport(); - } - - return $this->_currentTransport; - } - - protected function _killCurrentTransport() - { - $this->_currentTransport = null; - parent::_killCurrentTransport(); - } -} diff --git a/tools/swift/classes/Swift/Transport/IoBuffer.php b/tools/swift/classes/Swift/Transport/IoBuffer.php deleted file mode 100644 index af97adf1f..000000000 --- a/tools/swift/classes/Swift/Transport/IoBuffer.php +++ /dev/null @@ -1,67 +0,0 @@ -_transports = $transports; - $this->_deadTransports = array(); - } - - /** - * Get $transports to delegate to. - * - * @return Swift_Transport[] - */ - public function getTransports() - { - return array_merge($this->_transports, $this->_deadTransports); - } - - /** - * Get the Transport used in the last successful send operation. - * - * @return Swift_Transport - */ - public function getLastUsedTransport() - { - return $this->_lastUsedTransport; - } - - /** - * Test if this Transport mechanism has started. - * - * @return bool - */ - public function isStarted() - { - return count($this->_transports) > 0; - } - - /** - * Start this Transport mechanism. - */ - public function start() - { - $this->_transports = array_merge($this->_transports, $this->_deadTransports); - } - - /** - * Stop this Transport mechanism. - */ - public function stop() - { - foreach ($this->_transports as $transport) { - $transport->stop(); - } - } - - /** - * Send the given Message. - * - * Recipient/sender data will be retrieved from the Message API. - * The return value is the number of recipients who were accepted for delivery. - * - * @param Swift_Mime_Message $message - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int - */ - public function send(Swift_Mime_Message $message, &$failedRecipients = null) - { - $maxTransports = count($this->_transports); - $sent = 0; - $this->_lastUsedTransport = null; - - for ($i = 0; $i < $maxTransports - && $transport = $this->_getNextTransport(); ++$i) { - try { - if (!$transport->isStarted()) { - $transport->start(); - } - if ($sent = $transport->send($message, $failedRecipients)) { - $this->_lastUsedTransport = $transport; - break; - } - } catch (Swift_TransportException $e) { - $this->_killCurrentTransport(); - } - } - - if (count($this->_transports) == 0) { - throw new Swift_TransportException( - 'All Transports in LoadBalancedTransport failed, or no Transports available' - ); - } - - return $sent; - } - - /** - * Register a plugin. - * - * @param Swift_Events_EventListener $plugin - */ - public function registerPlugin(Swift_Events_EventListener $plugin) - { - foreach ($this->_transports as $transport) { - $transport->registerPlugin($plugin); - } - } - - /** - * Rotates the transport list around and returns the first instance. - * - * @return Swift_Transport - */ - protected function _getNextTransport() - { - if ($next = array_shift($this->_transports)) { - $this->_transports[] = $next; - } - - return $next; - } - - /** - * Tag the currently used (top of stack) transport as dead/useless. - */ - protected function _killCurrentTransport() - { - if ($transport = array_pop($this->_transports)) { - try { - $transport->stop(); - } catch (Exception $e) { - } - $this->_deadTransports[] = $transport; - } - } -} diff --git a/tools/swift/classes/Swift/Transport/MailInvoker.php b/tools/swift/classes/Swift/Transport/MailInvoker.php deleted file mode 100644 index 77489cedc..000000000 --- a/tools/swift/classes/Swift/Transport/MailInvoker.php +++ /dev/null @@ -1,32 +0,0 @@ -_invoker = $invoker; - $this->_eventDispatcher = $eventDispatcher; - } - - /** - * Not used. - */ - public function isStarted() - { - return false; - } - - /** - * Not used. - */ - public function start() - { - } - - /** - * Not used. - */ - public function stop() - { - } - - /** - * Set the additional parameters used on the mail() function. - * - * This string is formatted for sprintf() where %s is the sender address. - * - * @param string $params - * - * @return $this - */ - public function setExtraParams($params) - { - $this->_extraParams = $params; - - return $this; - } - - /** - * Get the additional parameters used on the mail() function. - * - * This string is formatted for sprintf() where %s is the sender address. - * - * @return string - */ - public function getExtraParams() - { - return $this->_extraParams; - } - - /** - * Send the given Message. - * - * Recipient/sender data will be retrieved from the Message API. - * The return value is the number of recipients who were accepted for delivery. - * - * @param Swift_Mime_Message $message - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int - */ - public function send(Swift_Mime_Message $message, &$failedRecipients = null) - { - $failedRecipients = (array) $failedRecipients; - - if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { - $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); - if ($evt->bubbleCancelled()) { - return 0; - } - } - - $count = ( - count((array) $message->getTo()) - + count((array) $message->getCc()) - + count((array) $message->getBcc()) - ); - - $toHeader = $message->getHeaders()->get('To'); - $subjectHeader = $message->getHeaders()->get('Subject'); - - if (0 === $count) { - $this->_throwException(new Swift_TransportException('Cannot send message without a recipient')); - } - $to = $toHeader ? $toHeader->getFieldBody() : ''; - $subject = $subjectHeader ? $subjectHeader->getFieldBody() : ''; - - $reversePath = $this->_getReversePath($message); - - // Remove headers that would otherwise be duplicated - $message->getHeaders()->remove('To'); - $message->getHeaders()->remove('Subject'); - - $messageStr = $message->toString(); - - if ($toHeader) { - $message->getHeaders()->set($toHeader); - } - $message->getHeaders()->set($subjectHeader); - - // Separate headers from body - if (false !== $endHeaders = strpos($messageStr, "\r\n\r\n")) { - $headers = substr($messageStr, 0, $endHeaders)."\r\n"; //Keep last EOL - $body = substr($messageStr, $endHeaders + 4); - } else { - $headers = $messageStr."\r\n"; - $body = ''; - } - - unset($messageStr); - - if ("\r\n" != PHP_EOL) { - // Non-windows (not using SMTP) - $headers = str_replace("\r\n", PHP_EOL, $headers); - $subject = str_replace("\r\n", PHP_EOL, $subject); - $body = str_replace("\r\n", PHP_EOL, $body); - $to = str_replace("\r\n", PHP_EOL, $to); - } else { - // Windows, using SMTP - $headers = str_replace("\r\n.", "\r\n..", $headers); - $subject = str_replace("\r\n.", "\r\n..", $subject); - $body = str_replace("\r\n.", "\r\n..", $body); - $to = str_replace("\r\n.", "\r\n..", $to); - } - - if ($this->_invoker->mail($to, $subject, $body, $headers, $this->_formatExtraParams($this->_extraParams, $reversePath))) { - if ($evt) { - $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); - $evt->setFailedRecipients($failedRecipients); - $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); - } - } else { - $failedRecipients = array_merge( - $failedRecipients, - array_keys((array) $message->getTo()), - array_keys((array) $message->getCc()), - array_keys((array) $message->getBcc()) - ); - - if ($evt) { - $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED); - $evt->setFailedRecipients($failedRecipients); - $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); - } - - $message->generateId(); - - $count = 0; - } - - return $count; - } - - /** - * Register a plugin. - * - * @param Swift_Events_EventListener $plugin - */ - public function registerPlugin(Swift_Events_EventListener $plugin) - { - $this->_eventDispatcher->bindEventListener($plugin); - } - - /** Throw a TransportException, first sending it to any listeners */ - protected function _throwException(Swift_TransportException $e) - { - if ($evt = $this->_eventDispatcher->createTransportExceptionEvent($this, $e)) { - $this->_eventDispatcher->dispatchEvent($evt, 'exceptionThrown'); - if (!$evt->bubbleCancelled()) { - throw $e; - } - } else { - throw $e; - } - } - - /** Determine the best-use reverse path for this message */ - private function _getReversePath(Swift_Mime_Message $message) - { - $return = $message->getReturnPath(); - $sender = $message->getSender(); - $from = $message->getFrom(); - $path = null; - if (!empty($return)) { - $path = $return; - } elseif (!empty($sender)) { - $keys = array_keys($sender); - $path = array_shift($keys); - } elseif (!empty($from)) { - $keys = array_keys($from); - $path = array_shift($keys); - } - - return $path; - } - - /** - * Fix CVE-2016-10074 by disallowing potentially unsafe shell characters. - * - * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows. - * - * @param string $string The string to be validated - * - * @return bool - */ - private function _isShellSafe($string) - { - // Future-proof - if (escapeshellcmd($string) !== $string || !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))) { - return false; - } - - $length = strlen($string); - for ($i = 0; $i < $length; ++$i) { - $c = $string[$i]; - // All other characters have a special meaning in at least one common shell, including = and +. - // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here. - // Note that this does permit non-Latin alphanumeric characters based on the current locale. - if (!ctype_alnum($c) && strpos('@_-.', $c) === false) { - return false; - } - } - - return true; - } - - /** - * Return php mail extra params to use for invoker->mail. - * - * @param $extraParams - * @param $reversePath - * - * @return string|null - */ - private function _formatExtraParams($extraParams, $reversePath) - { - if (false !== strpos($extraParams, '-f%s')) { - if (empty($reversePath) || false === $this->_isShellSafe($reversePath)) { - $extraParams = str_replace('-f%s', '', $extraParams); - } else { - $extraParams = sprintf($extraParams, $reversePath); - } - } - - return !empty($extraParams) ? $extraParams : null; - } -} diff --git a/tools/swift/classes/Swift/Transport/NullTransport.php b/tools/swift/classes/Swift/Transport/NullTransport.php deleted file mode 100644 index ad20e0e53..000000000 --- a/tools/swift/classes/Swift/Transport/NullTransport.php +++ /dev/null @@ -1,93 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Pretends messages have been sent, but just ignores them. - * - * @author Fabien Potencier - */ -class Swift_Transport_NullTransport implements Swift_Transport -{ - /** The event dispatcher from the plugin API */ - private $_eventDispatcher; - - /** - * Constructor. - */ - public function __construct(Swift_Events_EventDispatcher $eventDispatcher) - { - $this->_eventDispatcher = $eventDispatcher; - } - - /** - * Tests if this Transport mechanism has started. - * - * @return bool - */ - public function isStarted() - { - return true; - } - - /** - * Starts this Transport mechanism. - */ - public function start() - { - } - - /** - * Stops this Transport mechanism. - */ - public function stop() - { - } - - /** - * Sends the given message. - * - * @param Swift_Mime_Message $message - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int The number of sent emails - */ - public function send(Swift_Mime_Message $message, &$failedRecipients = null) - { - if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { - $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); - if ($evt->bubbleCancelled()) { - return 0; - } - } - - if ($evt) { - $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); - $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); - } - - $count = ( - count((array) $message->getTo()) - + count((array) $message->getCc()) - + count((array) $message->getBcc()) - ); - - return $count; - } - - /** - * Register a plugin. - * - * @param Swift_Events_EventListener $plugin - */ - public function registerPlugin(Swift_Events_EventListener $plugin) - { - $this->_eventDispatcher->bindEventListener($plugin); - } -} diff --git a/tools/swift/classes/Swift/Transport/SendmailTransport.php b/tools/swift/classes/Swift/Transport/SendmailTransport.php deleted file mode 100644 index 6430d5f6b..000000000 --- a/tools/swift/classes/Swift/Transport/SendmailTransport.php +++ /dev/null @@ -1,160 +0,0 @@ - 30, - 'blocking' => 1, - 'command' => '/usr/sbin/sendmail -bs', - 'type' => Swift_Transport_IoBuffer::TYPE_PROCESS, - ); - - /** - * Create a new SendmailTransport with $buf for I/O. - * - * @param Swift_Transport_IoBuffer $buf - * @param Swift_Events_EventDispatcher $dispatcher - */ - public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher) - { - parent::__construct($buf, $dispatcher); - } - - /** - * Start the standalone SMTP session if running in -bs mode. - */ - public function start() - { - if (false !== strpos($this->getCommand(), ' -bs')) { - parent::start(); - } - } - - /** - * Set the command to invoke. - * - * If using -t mode you are strongly advised to include -oi or -i in the flags. - * For example: /usr/sbin/sendmail -oi -t - * Swift will append a -f flag if one is not present. - * - * The recommended mode is "-bs" since it is interactive and failure notifications - * are hence possible. - * - * @param string $command - * - * @return $this - */ - public function setCommand($command) - { - $this->_params['command'] = $command; - - return $this; - } - - /** - * Get the sendmail command which will be invoked. - * - * @return string - */ - public function getCommand() - { - return $this->_params['command']; - } - - /** - * Send the given Message. - * - * Recipient/sender data will be retrieved from the Message API. - * - * The return value is the number of recipients who were accepted for delivery. - * NOTE: If using 'sendmail -t' you will not be aware of any failures until - * they bounce (i.e. send() will always return 100% success). - * - * @param Swift_Mime_Message $message - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int - */ - public function send(Swift_Mime_Message $message, &$failedRecipients = null) - { - $failedRecipients = (array) $failedRecipients; - $command = $this->getCommand(); - $buffer = $this->getBuffer(); - $count = 0; - - if (false !== strpos($command, ' -t')) { - if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { - $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); - if ($evt->bubbleCancelled()) { - return 0; - } - } - - if (false === strpos($command, ' -f')) { - $command .= ' -f'.escapeshellarg($this->_getReversePath($message)); - } - - $buffer->initialize(array_merge($this->_params, array('command' => $command))); - - if (false === strpos($command, ' -i') && false === strpos($command, ' -oi')) { - $buffer->setWriteTranslations(array("\r\n" => "\n", "\n." => "\n..")); - } else { - $buffer->setWriteTranslations(array("\r\n" => "\n")); - } - - $count = count((array) $message->getTo()) - + count((array) $message->getCc()) - + count((array) $message->getBcc()) - ; - $message->toByteStream($buffer); - $buffer->flushBuffers(); - $buffer->setWriteTranslations(array()); - $buffer->terminate(); - - if ($evt) { - $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); - $evt->setFailedRecipients($failedRecipients); - $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); - } - - $message->generateId(); - } elseif (false !== strpos($command, ' -bs')) { - $count = parent::send($message, $failedRecipients); - } else { - $this->_throwException(new Swift_TransportException( - 'Unsupported sendmail command flags ['.$command.']. '. - 'Must be one of "-bs" or "-t" but can include additional flags.' - )); - } - - return $count; - } - - /** Get the params to initialize the buffer */ - protected function _getBufferParams() - { - return $this->_params; - } -} diff --git a/tools/swift/classes/Swift/Transport/SimpleMailInvoker.php b/tools/swift/classes/Swift/Transport/SimpleMailInvoker.php deleted file mode 100644 index 4cab66bd6..000000000 --- a/tools/swift/classes/Swift/Transport/SimpleMailInvoker.php +++ /dev/null @@ -1,39 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Stores Messages in a queue. - * - * @author Fabien Potencier - */ -class Swift_Transport_SpoolTransport implements Swift_Transport -{ - /** The spool instance */ - private $_spool; - - /** The event dispatcher from the plugin API */ - private $_eventDispatcher; - - /** - * Constructor. - */ - public function __construct(Swift_Events_EventDispatcher $eventDispatcher, Swift_Spool $spool = null) - { - $this->_eventDispatcher = $eventDispatcher; - $this->_spool = $spool; - } - - /** - * Sets the spool object. - * - * @param Swift_Spool $spool - * - * @return $this - */ - public function setSpool(Swift_Spool $spool) - { - $this->_spool = $spool; - - return $this; - } - - /** - * Get the spool object. - * - * @return Swift_Spool - */ - public function getSpool() - { - return $this->_spool; - } - - /** - * Tests if this Transport mechanism has started. - * - * @return bool - */ - public function isStarted() - { - return true; - } - - /** - * Starts this Transport mechanism. - */ - public function start() - { - } - - /** - * Stops this Transport mechanism. - */ - public function stop() - { - } - - /** - * Sends the given message. - * - * @param Swift_Mime_Message $message - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int The number of sent e-mail's - */ - public function send(Swift_Mime_Message $message, &$failedRecipients = null) - { - if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { - $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); - if ($evt->bubbleCancelled()) { - return 0; - } - } - - $success = $this->_spool->queueMessage($message); - - if ($evt) { - $evt->setResult($success ? Swift_Events_SendEvent::RESULT_SPOOLED : Swift_Events_SendEvent::RESULT_FAILED); - $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); - } - - return 1; - } - - /** - * Register a plugin. - * - * @param Swift_Events_EventListener $plugin - */ - public function registerPlugin(Swift_Events_EventListener $plugin) - { - $this->_eventDispatcher->bindEventListener($plugin); - } -} diff --git a/tools/swift/classes/Swift/Transport/StreamBuffer.php b/tools/swift/classes/Swift/Transport/StreamBuffer.php deleted file mode 100644 index 3a9fe76b2..000000000 --- a/tools/swift/classes/Swift/Transport/StreamBuffer.php +++ /dev/null @@ -1,334 +0,0 @@ -_replacementFactory = $replacementFactory; - } - - /** - * Perform any initialization needed, using the given $params. - * - * Parameters will vary depending upon the type of IoBuffer used. - * - * @param array $params - */ - public function initialize(array $params) - { - $this->_params = $params; - switch ($params['type']) { - case self::TYPE_PROCESS: - $this->_establishProcessConnection(); - break; - case self::TYPE_SOCKET: - default: - $this->_establishSocketConnection(); - break; - } - } - - /** - * Set an individual param on the buffer (e.g. switching to SSL). - * - * @param string $param - * @param mixed $value - */ - public function setParam($param, $value) - { - if (isset($this->_stream)) { - switch ($param) { - case 'timeout': - if ($this->_stream) { - stream_set_timeout($this->_stream, $value); - } - break; - - case 'blocking': - if ($this->_stream) { - stream_set_blocking($this->_stream, 1); - } - } - } - $this->_params[$param] = $value; - } - - public function startTLS() - { - // STREAM_CRYPTO_METHOD_TLS_CLIENT only allow tls1.0 connections (some php versions) - // To support modern tls we allow explicit tls1.0, tls1.1, tls1.2 - // Ssl3 and older are not allowed because they are vulnerable - // @TODO make tls arguments configurable - $cryptoType = STREAM_CRYPTO_METHOD_TLS_CLIENT; - if (PHP_VERSION_ID >= 50600) { - $cryptoType = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; - } - - return stream_socket_enable_crypto($this->_stream, true, $cryptoType); - } - - /** - * Perform any shutdown logic needed. - */ - public function terminate() - { - if (isset($this->_stream)) { - switch ($this->_params['type']) { - case self::TYPE_PROCESS: - fclose($this->_in); - fclose($this->_out); - proc_close($this->_stream); - break; - case self::TYPE_SOCKET: - default: - fclose($this->_stream); - break; - } - } - $this->_stream = null; - $this->_out = null; - $this->_in = null; - } - - /** - * Set an array of string replacements which should be made on data written - * to the buffer. - * - * This could replace LF with CRLF for example. - * - * @param string[] $replacements - */ - public function setWriteTranslations(array $replacements) - { - foreach ($this->_translations as $search => $replace) { - if (!isset($replacements[$search])) { - $this->removeFilter($search); - unset($this->_translations[$search]); - } - } - - foreach ($replacements as $search => $replace) { - if (!isset($this->_translations[$search])) { - $this->addFilter( - $this->_replacementFactory->createFilter($search, $replace), $search - ); - $this->_translations[$search] = true; - } - } - } - - /** - * Get a line of output (including any CRLF). - * - * The $sequence number comes from any writes and may or may not be used - * depending upon the implementation. - * - * @param int $sequence of last write to scan from - * - * @throws Swift_IoException - * - * @return string - */ - public function readLine($sequence) - { - if (isset($this->_out) && !feof($this->_out)) { - $line = fgets($this->_out); - if (strlen($line) == 0) { - $metas = stream_get_meta_data($this->_out); - if ($metas['timed_out']) { - throw new Swift_IoException( - 'Connection to '. - $this->_getReadConnectionDescription(). - ' Timed Out' - ); - } - } - - return $line; - } - } - - /** - * Reads $length bytes from the stream into a string and moves the pointer - * through the stream by $length. - * - * If less bytes exist than are requested the remaining bytes are given instead. - * If no bytes are remaining at all, boolean false is returned. - * - * @param int $length - * - * @throws Swift_IoException - * - * @return string|bool - */ - public function read($length) - { - if (isset($this->_out) && !feof($this->_out)) { - $ret = fread($this->_out, $length); - if (strlen($ret) == 0) { - $metas = stream_get_meta_data($this->_out); - if ($metas['timed_out']) { - throw new Swift_IoException( - 'Connection to '. - $this->_getReadConnectionDescription(). - ' Timed Out' - ); - } - } - - return $ret; - } - } - - /** Not implemented */ - public function setReadPointer($byteOffset) - { - } - - /** Flush the stream contents */ - protected function _flush() - { - if (isset($this->_in)) { - fflush($this->_in); - } - } - - /** Write this bytes to the stream */ - protected function _commit($bytes) - { - if (isset($this->_in)) { - $bytesToWrite = strlen($bytes); - $totalBytesWritten = 0; - - while ($totalBytesWritten < $bytesToWrite) { - $bytesWritten = fwrite($this->_in, substr($bytes, $totalBytesWritten)); - if (false === $bytesWritten || 0 === $bytesWritten) { - break; - } - - $totalBytesWritten += $bytesWritten; - } - - if ($totalBytesWritten > 0) { - return ++$this->_sequence; - } - } - } - - /** - * Establishes a connection to a remote server. - */ - private function _establishSocketConnection() - { - $host = $this->_params['host']; - if (!empty($this->_params['protocol'])) { - $host = $this->_params['protocol'].'://'.$host; - } - $timeout = 15; - if (!empty($this->_params['timeout'])) { - $timeout = $this->_params['timeout']; - } - $options = array(); - if (!empty($this->_params['sourceIp'])) { - $options['socket']['bindto'] = $this->_params['sourceIp'].':0'; - } - if (isset($this->_params['stream_context_options'])) { - $options = array_merge($options, $this->_params['stream_context_options']); - } - $streamContext = stream_context_create($options); - $this->_stream = @stream_socket_client($host.':'.$this->_params['port'], $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $streamContext); - if (false === $this->_stream) { - throw new Swift_TransportException( - 'Connection could not be established with host '.$this->_params['host']. - ' ['.$errstr.' #'.$errno.']' - ); - } - if (!empty($this->_params['blocking'])) { - stream_set_blocking($this->_stream, 1); - } else { - stream_set_blocking($this->_stream, 0); - } - stream_set_timeout($this->_stream, $timeout); - $this->_in = &$this->_stream; - $this->_out = &$this->_stream; - } - - /** - * Opens a process for input/output. - */ - private function _establishProcessConnection() - { - $command = $this->_params['command']; - $descriptorSpec = array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - 2 => array('pipe', 'w'), - ); - $pipes = array(); - $this->_stream = proc_open($command, $descriptorSpec, $pipes); - stream_set_blocking($pipes[2], 0); - if ($err = stream_get_contents($pipes[2])) { - throw new Swift_TransportException( - 'Process could not be started ['.$err.']' - ); - } - $this->_in = &$pipes[0]; - $this->_out = &$pipes[1]; - } - - private function _getReadConnectionDescription() - { - switch ($this->_params['type']) { - case self::TYPE_PROCESS: - return 'Process '.$this->_params['command']; - break; - - case self::TYPE_SOCKET: - default: - $host = $this->_params['host']; - if (!empty($this->_params['protocol'])) { - $host = $this->_params['protocol'].'://'.$host; - } - $host .= ':'.$this->_params['port']; - - return $host; - break; - } - } -} diff --git a/tools/swift/classes/Swift/TransportException.php b/tools/swift/classes/Swift/TransportException.php deleted file mode 100644 index 4ae2412e6..000000000 --- a/tools/swift/classes/Swift/TransportException.php +++ /dev/null @@ -1,29 +0,0 @@ - - */ -class Swift_Validate -{ - /** - * Grammar Object. - * - * @var Swift_Mime_Grammar - */ - private static $grammar = null; - - /** - * Checks if an e-mail address matches the current grammars. - * - * @param string $email - * - * @return bool - */ - public static function email($email) - { - if (self::$grammar === null) { - self::$grammar = Swift_DependencyContainer::getInstance() - ->lookup('mime.grammar'); - } - - return (bool) preg_match( - '/^'.self::$grammar->getDefinition('addr-spec').'$/D', - $email - ); - } -} diff --git a/tools/swift/dependency_maps/cache_deps.php b/tools/swift/dependency_maps/cache_deps.php deleted file mode 100644 index 6023448e8..000000000 --- a/tools/swift/dependency_maps/cache_deps.php +++ /dev/null @@ -1,23 +0,0 @@ -register('cache') - ->asAliasOf('cache.array') - - ->register('tempdir') - ->asValue('/tmp') - - ->register('cache.null') - ->asSharedInstanceOf('Swift_KeyCache_NullKeyCache') - - ->register('cache.array') - ->asSharedInstanceOf('Swift_KeyCache_ArrayKeyCache') - ->withDependencies(array('cache.inputstream')) - - ->register('cache.disk') - ->asSharedInstanceOf('Swift_KeyCache_DiskKeyCache') - ->withDependencies(array('cache.inputstream', 'tempdir')) - - ->register('cache.inputstream') - ->asNewInstanceOf('Swift_KeyCache_SimpleKeyCacheInputStream') -; diff --git a/tools/swift/dependency_maps/message_deps.php b/tools/swift/dependency_maps/message_deps.php deleted file mode 100644 index 64d69d215..000000000 --- a/tools/swift/dependency_maps/message_deps.php +++ /dev/null @@ -1,9 +0,0 @@ -register('message.message') - ->asNewInstanceOf('Swift_Message') - - ->register('message.mimepart') - ->asNewInstanceOf('Swift_MimePart') -; diff --git a/tools/swift/dependency_maps/mime_deps.php b/tools/swift/dependency_maps/mime_deps.php deleted file mode 100644 index d575e4f2d..000000000 --- a/tools/swift/dependency_maps/mime_deps.php +++ /dev/null @@ -1,123 +0,0 @@ -register('properties.charset') - ->asValue('utf-8') - - ->register('mime.grammar') - ->asSharedInstanceOf('Swift_Mime_Grammar') - - ->register('mime.message') - ->asNewInstanceOf('Swift_Mime_SimpleMessage') - ->withDependencies(array( - 'mime.headerset', - 'mime.qpcontentencoder', - 'cache', - 'mime.grammar', - 'properties.charset', - )) - - ->register('mime.part') - ->asNewInstanceOf('Swift_Mime_MimePart') - ->withDependencies(array( - 'mime.headerset', - 'mime.qpcontentencoder', - 'cache', - 'mime.grammar', - 'properties.charset', - )) - - ->register('mime.attachment') - ->asNewInstanceOf('Swift_Mime_Attachment') - ->withDependencies(array( - 'mime.headerset', - 'mime.base64contentencoder', - 'cache', - 'mime.grammar', - )) - ->addConstructorValue($swift_mime_types) - - ->register('mime.embeddedfile') - ->asNewInstanceOf('Swift_Mime_EmbeddedFile') - ->withDependencies(array( - 'mime.headerset', - 'mime.base64contentencoder', - 'cache', - 'mime.grammar', - )) - ->addConstructorValue($swift_mime_types) - - ->register('mime.headerfactory') - ->asNewInstanceOf('Swift_Mime_SimpleHeaderFactory') - ->withDependencies(array( - 'mime.qpheaderencoder', - 'mime.rfc2231encoder', - 'mime.grammar', - 'properties.charset', - )) - - ->register('mime.headerset') - ->asNewInstanceOf('Swift_Mime_SimpleHeaderSet') - ->withDependencies(array('mime.headerfactory', 'properties.charset')) - - ->register('mime.qpheaderencoder') - ->asNewInstanceOf('Swift_Mime_HeaderEncoder_QpHeaderEncoder') - ->withDependencies(array('mime.charstream')) - - ->register('mime.base64headerencoder') - ->asNewInstanceOf('Swift_Mime_HeaderEncoder_Base64HeaderEncoder') - ->withDependencies(array('mime.charstream')) - - ->register('mime.charstream') - ->asNewInstanceOf('Swift_CharacterStream_NgCharacterStream') - ->withDependencies(array('mime.characterreaderfactory', 'properties.charset')) - - ->register('mime.bytecanonicalizer') - ->asSharedInstanceOf('Swift_StreamFilters_ByteArrayReplacementFilter') - ->addConstructorValue(array(array(0x0D, 0x0A), array(0x0D), array(0x0A))) - ->addConstructorValue(array(array(0x0A), array(0x0A), array(0x0D, 0x0A))) - - ->register('mime.characterreaderfactory') - ->asSharedInstanceOf('Swift_CharacterReaderFactory_SimpleCharacterReaderFactory') - - ->register('mime.safeqpcontentencoder') - ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder') - ->withDependencies(array('mime.charstream', 'mime.bytecanonicalizer')) - - ->register('mime.rawcontentencoder') - ->asNewInstanceOf('Swift_Mime_ContentEncoder_RawContentEncoder') - - ->register('mime.nativeqpcontentencoder') - ->withDependencies(array('properties.charset')) - ->asNewInstanceOf('Swift_Mime_ContentEncoder_NativeQpContentEncoder') - - ->register('mime.qpcontentencoderproxy') - ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoderProxy') - ->withDependencies(array('mime.safeqpcontentencoder', 'mime.nativeqpcontentencoder', 'properties.charset')) - - ->register('mime.7bitcontentencoder') - ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder') - ->addConstructorValue('7bit') - ->addConstructorValue(true) - - ->register('mime.8bitcontentencoder') - ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder') - ->addConstructorValue('8bit') - ->addConstructorValue(true) - - ->register('mime.base64contentencoder') - ->asSharedInstanceOf('Swift_Mime_ContentEncoder_Base64ContentEncoder') - - ->register('mime.rfc2231encoder') - ->asNewInstanceOf('Swift_Encoder_Rfc2231Encoder') - ->withDependencies(array('mime.charstream')) - - // As of PHP 5.4.7, the quoted_printable_encode() function behaves correctly. - // see https://github.com/php/php-src/commit/18bb426587d62f93c54c40bf8535eb8416603629 - ->register('mime.qpcontentencoder') - ->asAliasOf(PHP_VERSION_ID >= 50407 ? 'mime.qpcontentencoderproxy' : 'mime.safeqpcontentencoder') -; - -unset($swift_mime_types); diff --git a/tools/swift/dependency_maps/transport_deps.php b/tools/swift/dependency_maps/transport_deps.php deleted file mode 100644 index 77e432cfa..000000000 --- a/tools/swift/dependency_maps/transport_deps.php +++ /dev/null @@ -1,76 +0,0 @@ -register('transport.smtp') - ->asNewInstanceOf('Swift_Transport_EsmtpTransport') - ->withDependencies(array( - 'transport.buffer', - array('transport.authhandler'), - 'transport.eventdispatcher', - )) - - ->register('transport.sendmail') - ->asNewInstanceOf('Swift_Transport_SendmailTransport') - ->withDependencies(array( - 'transport.buffer', - 'transport.eventdispatcher', - )) - - ->register('transport.mail') - ->asNewInstanceOf('Swift_Transport_MailTransport') - ->withDependencies(array('transport.mailinvoker', 'transport.eventdispatcher')) - - ->register('transport.loadbalanced') - ->asNewInstanceOf('Swift_Transport_LoadBalancedTransport') - - ->register('transport.failover') - ->asNewInstanceOf('Swift_Transport_FailoverTransport') - - ->register('transport.spool') - ->asNewInstanceOf('Swift_Transport_SpoolTransport') - ->withDependencies(array('transport.eventdispatcher')) - - ->register('transport.null') - ->asNewInstanceOf('Swift_Transport_NullTransport') - ->withDependencies(array('transport.eventdispatcher')) - - ->register('transport.mailinvoker') - ->asSharedInstanceOf('Swift_Transport_SimpleMailInvoker') - - ->register('transport.buffer') - ->asNewInstanceOf('Swift_Transport_StreamBuffer') - ->withDependencies(array('transport.replacementfactory')) - - ->register('transport.authhandler') - ->asNewInstanceOf('Swift_Transport_Esmtp_AuthHandler') - ->withDependencies(array( - array( - 'transport.crammd5auth', - 'transport.loginauth', - 'transport.plainauth', - 'transport.ntlmauth', - 'transport.xoauth2auth', - ), - )) - - ->register('transport.crammd5auth') - ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_CramMd5Authenticator') - - ->register('transport.loginauth') - ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_LoginAuthenticator') - - ->register('transport.plainauth') - ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_PlainAuthenticator') - - ->register('transport.xoauth2auth') - ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_XOAuth2Authenticator') - - ->register('transport.ntlmauth') - ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_NTLMAuthenticator') - - ->register('transport.eventdispatcher') - ->asNewInstanceOf('Swift_Events_SimpleEventDispatcher') - - ->register('transport.replacementfactory') - ->asSharedInstanceOf('Swift_StreamFilters_StringReplacementFilterFactory') -; diff --git a/tools/swift/index.php b/tools/swift/index.php deleted file mode 100644 index 9a99a8662..000000000 --- a/tools/swift/index.php +++ /dev/null @@ -1,35 +0,0 @@ - -* @copyright 2007-2017 PrestaShop SA -* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) -* International Registered Trademark & Property of PrestaShop SA -*/ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/tools/swift/mime_types.php b/tools/swift/mime_types.php deleted file mode 100644 index b42c1cc1a..000000000 --- a/tools/swift/mime_types.php +++ /dev/null @@ -1,1007 +0,0 @@ - 'text/vnd.in3d.3dml', - '3ds' => 'image/x-3ds', - '3g2' => 'video/3gpp2', - '3gp' => 'video/3gpp', - '7z' => 'application/x-7z-compressed', - 'aab' => 'application/x-authorware-bin', - 'aac' => 'audio/x-aac', - 'aam' => 'application/x-authorware-map', - 'aas' => 'application/x-authorware-seg', - 'abw' => 'application/x-abiword', - 'ac' => 'application/pkix-attr-cert', - 'acc' => 'application/vnd.americandynamics.acc', - 'ace' => 'application/x-ace-compressed', - 'acu' => 'application/vnd.acucobol', - 'acutc' => 'application/vnd.acucorp', - 'adp' => 'audio/adpcm', - 'aep' => 'application/vnd.audiograph', - 'afm' => 'application/x-font-type1', - 'afp' => 'application/vnd.ibm.modcap', - 'ahead' => 'application/vnd.ahead.space', - 'ai' => 'application/postscript', - 'aif' => 'audio/x-aiff', - 'aifc' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'air' => 'application/vnd.adobe.air-application-installer-package+zip', - 'ait' => 'application/vnd.dvb.ait', - 'ami' => 'application/vnd.amiga.ami', - 'apk' => 'application/vnd.android.package-archive', - 'appcache' => 'text/cache-manifest', - 'apr' => 'application/vnd.lotus-approach', - 'aps' => 'application/postscript', - 'arc' => 'application/x-freearc', - 'asc' => 'application/pgp-signature', - 'asf' => 'video/x-ms-asf', - 'asm' => 'text/x-asm', - 'aso' => 'application/vnd.accpac.simply.aso', - 'asx' => 'video/x-ms-asf', - 'atc' => 'application/vnd.acucorp', - 'atom' => 'application/atom+xml', - 'atomcat' => 'application/atomcat+xml', - 'atomsvc' => 'application/atomsvc+xml', - 'atx' => 'application/vnd.antix.game-component', - 'au' => 'audio/basic', - 'avi' => 'video/x-msvideo', - 'aw' => 'application/applixware', - 'azf' => 'application/vnd.airzip.filesecure.azf', - 'azs' => 'application/vnd.airzip.filesecure.azs', - 'azw' => 'application/vnd.amazon.ebook', - 'bat' => 'application/x-msdownload', - 'bcpio' => 'application/x-bcpio', - 'bdf' => 'application/x-font-bdf', - 'bdm' => 'application/vnd.syncml.dm+wbxml', - 'bed' => 'application/vnd.realvnc.bed', - 'bh2' => 'application/vnd.fujitsu.oasysprs', - 'bin' => 'application/octet-stream', - 'blb' => 'application/x-blorb', - 'blorb' => 'application/x-blorb', - 'bmi' => 'application/vnd.bmi', - 'bmp' => 'image/bmp', - 'book' => 'application/vnd.framemaker', - 'box' => 'application/vnd.previewsystems.box', - 'boz' => 'application/x-bzip2', - 'bpk' => 'application/octet-stream', - 'btif' => 'image/prs.btif', - 'bz' => 'application/x-bzip', - 'bz2' => 'application/x-bzip2', - 'c' => 'text/x-c', - 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', - 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', - 'c4d' => 'application/vnd.clonk.c4group', - 'c4f' => 'application/vnd.clonk.c4group', - 'c4g' => 'application/vnd.clonk.c4group', - 'c4p' => 'application/vnd.clonk.c4group', - 'c4u' => 'application/vnd.clonk.c4group', - 'cab' => 'application/vnd.ms-cab-compressed', - 'caf' => 'audio/x-caf', - 'cap' => 'application/vnd.tcpdump.pcap', - 'car' => 'application/vnd.curl.car', - 'cat' => 'application/vnd.ms-pki.seccat', - 'cb7' => 'application/x-cbr', - 'cba' => 'application/x-cbr', - 'cbr' => 'application/x-cbr', - 'cbt' => 'application/x-cbr', - 'cbz' => 'application/x-cbr', - 'cc' => 'text/x-c', - 'cct' => 'application/x-director', - 'ccxml' => 'application/ccxml+xml', - 'cdbcmsg' => 'application/vnd.contact.cmsg', - 'cdf' => 'application/x-netcdf', - 'cdkey' => 'application/vnd.mediastation.cdkey', - 'cdmia' => 'application/cdmi-capability', - 'cdmic' => 'application/cdmi-container', - 'cdmid' => 'application/cdmi-domain', - 'cdmio' => 'application/cdmi-object', - 'cdmiq' => 'application/cdmi-queue', - 'cdx' => 'chemical/x-cdx', - 'cdxml' => 'application/vnd.chemdraw+xml', - 'cdy' => 'application/vnd.cinderella', - 'cer' => 'application/pkix-cert', - 'cfs' => 'application/x-cfs-compressed', - 'cgm' => 'image/cgm', - 'chat' => 'application/x-chat', - 'chm' => 'application/vnd.ms-htmlhelp', - 'chrt' => 'application/vnd.kde.kchart', - 'cif' => 'chemical/x-cif', - 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', - 'cil' => 'application/vnd.ms-artgalry', - 'cla' => 'application/vnd.claymore', - 'class' => 'application/java-vm', - 'clkk' => 'application/vnd.crick.clicker.keyboard', - 'clkp' => 'application/vnd.crick.clicker.palette', - 'clkt' => 'application/vnd.crick.clicker.template', - 'clkw' => 'application/vnd.crick.clicker.wordbank', - 'clkx' => 'application/vnd.crick.clicker', - 'clp' => 'application/x-msclip', - 'cmc' => 'application/vnd.cosmocaller', - 'cmdf' => 'chemical/x-cmdf', - 'cml' => 'chemical/x-cml', - 'cmp' => 'application/vnd.yellowriver-custom-menu', - 'cmx' => 'image/x-cmx', - 'cod' => 'application/vnd.rim.cod', - 'com' => 'application/x-msdownload', - 'conf' => 'text/plain', - 'cpio' => 'application/x-cpio', - 'cpp' => 'text/x-c', - 'cpt' => 'application/mac-compactpro', - 'crd' => 'application/x-mscardfile', - 'crl' => 'application/pkix-crl', - 'crt' => 'application/x-x509-ca-cert', - 'csh' => 'application/x-csh', - 'csml' => 'chemical/x-csml', - 'csp' => 'application/vnd.commonspace', - 'css' => 'text/css', - 'cst' => 'application/x-director', - 'csv' => 'text/csv', - 'cu' => 'application/cu-seeme', - 'curl' => 'text/vnd.curl', - 'cww' => 'application/prs.cww', - 'cxt' => 'application/x-director', - 'cxx' => 'text/x-c', - 'dae' => 'model/vnd.collada+xml', - 'daf' => 'application/vnd.mobius.daf', - 'dart' => 'application/vnd.dart', - 'dataless' => 'application/vnd.fdsn.seed', - 'davmount' => 'application/davmount+xml', - 'dbk' => 'application/docbook+xml', - 'dcr' => 'application/x-director', - 'dcurl' => 'text/vnd.curl.dcurl', - 'dd2' => 'application/vnd.oma.dd2+xml', - 'ddd' => 'application/vnd.fujixerox.ddd', - 'deb' => 'application/x-debian-package', - 'def' => 'text/plain', - 'deploy' => 'application/octet-stream', - 'der' => 'application/x-x509-ca-cert', - 'dfac' => 'application/vnd.dreamfactory', - 'dgc' => 'application/x-dgc-compressed', - 'dic' => 'text/x-c', - 'dir' => 'application/x-director', - 'dis' => 'application/vnd.mobius.dis', - 'dist' => 'application/octet-stream', - 'distz' => 'application/octet-stream', - 'djv' => 'image/vnd.djvu', - 'djvu' => 'image/vnd.djvu', - 'dll' => 'application/x-msdownload', - 'dmg' => 'application/x-apple-diskimage', - 'dmp' => 'application/vnd.tcpdump.pcap', - 'dms' => 'application/octet-stream', - 'dna' => 'application/vnd.dna', - 'doc' => 'application/msword', - 'docm' => 'application/vnd.ms-word.document.macroenabled.12', - 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'dot' => 'application/msword', - 'dotm' => 'application/vnd.ms-word.template.macroenabled.12', - 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', - 'dp' => 'application/vnd.osgi.dp', - 'dpg' => 'application/vnd.dpgraph', - 'dra' => 'audio/vnd.dra', - 'dsc' => 'text/prs.lines.tag', - 'dssc' => 'application/dssc+der', - 'dtb' => 'application/x-dtbook+xml', - 'dtd' => 'application/xml-dtd', - 'dts' => 'audio/vnd.dts', - 'dtshd' => 'audio/vnd.dts.hd', - 'dump' => 'application/octet-stream', - 'dvb' => 'video/vnd.dvb.file', - 'dvi' => 'application/x-dvi', - 'dwf' => 'model/vnd.dwf', - 'dwg' => 'image/vnd.dwg', - 'dxf' => 'image/vnd.dxf', - 'dxp' => 'application/vnd.spotfire.dxp', - 'dxr' => 'application/x-director', - 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', - 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', - 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', - 'ecma' => 'application/ecmascript', - 'edm' => 'application/vnd.novadigm.edm', - 'edx' => 'application/vnd.novadigm.edx', - 'efif' => 'application/vnd.picsel', - 'ei6' => 'application/vnd.pg.osasli', - 'elc' => 'application/octet-stream', - 'emf' => 'application/x-msmetafile', - 'eml' => 'message/rfc822', - 'emma' => 'application/emma+xml', - 'emz' => 'application/x-msmetafile', - 'eol' => 'audio/vnd.digital-winds', - 'eot' => 'application/vnd.ms-fontobject', - 'eps' => 'application/postscript', - 'epub' => 'application/epub+zip', - 'es3' => 'application/vnd.eszigno3+xml', - 'esa' => 'application/vnd.osgi.subsystem', - 'esf' => 'application/vnd.epson.esf', - 'et3' => 'application/vnd.eszigno3+xml', - 'etx' => 'text/x-setext', - 'eva' => 'application/x-eva', - 'evy' => 'application/x-envoy', - 'exe' => 'application/x-msdownload', - 'exi' => 'application/exi', - 'ext' => 'application/vnd.novadigm.ext', - 'ez' => 'application/andrew-inset', - 'ez2' => 'application/vnd.ezpix-album', - 'ez3' => 'application/vnd.ezpix-package', - 'f' => 'text/x-fortran', - 'f4v' => 'video/x-f4v', - 'f77' => 'text/x-fortran', - 'f90' => 'text/x-fortran', - 'fbs' => 'image/vnd.fastbidsheet', - 'fcdt' => 'application/vnd.adobe.formscentral.fcdt', - 'fcs' => 'application/vnd.isac.fcs', - 'fdf' => 'application/vnd.fdf', - 'fe_launch' => 'application/vnd.denovo.fcselayout-link', - 'fg5' => 'application/vnd.fujitsu.oasysgp', - 'fgd' => 'application/x-director', - 'fh' => 'image/x-freehand', - 'fh4' => 'image/x-freehand', - 'fh5' => 'image/x-freehand', - 'fh7' => 'image/x-freehand', - 'fhc' => 'image/x-freehand', - 'fig' => 'application/x-xfig', - 'flac' => 'audio/x-flac', - 'fli' => 'video/x-fli', - 'flo' => 'application/vnd.micrografx.flo', - 'flv' => 'video/x-flv', - 'flw' => 'application/vnd.kde.kivio', - 'flx' => 'text/vnd.fmi.flexstor', - 'fly' => 'text/vnd.fly', - 'fm' => 'application/vnd.framemaker', - 'fnc' => 'application/vnd.frogans.fnc', - 'for' => 'text/x-fortran', - 'fpx' => 'image/vnd.fpx', - 'frame' => 'application/vnd.framemaker', - 'fsc' => 'application/vnd.fsc.weblaunch', - 'fst' => 'image/vnd.fst', - 'ftc' => 'application/vnd.fluxtime.clip', - 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', - 'fvt' => 'video/vnd.fvt', - 'fxp' => 'application/vnd.adobe.fxp', - 'fxpl' => 'application/vnd.adobe.fxp', - 'fzs' => 'application/vnd.fuzzysheet', - 'g2w' => 'application/vnd.geoplan', - 'g3' => 'image/g3fax', - 'g3w' => 'application/vnd.geospace', - 'gac' => 'application/vnd.groove-account', - 'gam' => 'application/x-tads', - 'gbr' => 'application/rpki-ghostbusters', - 'gca' => 'application/x-gca-compressed', - 'gdl' => 'model/vnd.gdl', - 'geo' => 'application/vnd.dynageo', - 'gex' => 'application/vnd.geometry-explorer', - 'ggb' => 'application/vnd.geogebra.file', - 'ggt' => 'application/vnd.geogebra.tool', - 'ghf' => 'application/vnd.groove-help', - 'gif' => 'image/gif', - 'gim' => 'application/vnd.groove-identity-message', - 'gml' => 'application/gml+xml', - 'gmx' => 'application/vnd.gmx', - 'gnumeric' => 'application/x-gnumeric', - 'gph' => 'application/vnd.flographit', - 'gpx' => 'application/gpx+xml', - 'gqf' => 'application/vnd.grafeq', - 'gqs' => 'application/vnd.grafeq', - 'gram' => 'application/srgs', - 'gramps' => 'application/x-gramps-xml', - 'gre' => 'application/vnd.geometry-explorer', - 'grv' => 'application/vnd.groove-injector', - 'grxml' => 'application/srgs+xml', - 'gsf' => 'application/x-font-ghostscript', - 'gtar' => 'application/x-gtar', - 'gtm' => 'application/vnd.groove-tool-message', - 'gtw' => 'model/vnd.gtw', - 'gv' => 'text/vnd.graphviz', - 'gxf' => 'application/gxf', - 'gxt' => 'application/vnd.geonext', - 'gz' => 'application/x-gzip', - 'h' => 'text/x-c', - 'h261' => 'video/h261', - 'h263' => 'video/h263', - 'h264' => 'video/h264', - 'hal' => 'application/vnd.hal+xml', - 'hbci' => 'application/vnd.hbci', - 'hdf' => 'application/x-hdf', - 'hh' => 'text/x-c', - 'hlp' => 'application/winhlp', - 'hpgl' => 'application/vnd.hp-hpgl', - 'hpid' => 'application/vnd.hp-hpid', - 'hps' => 'application/vnd.hp-hps', - 'hqx' => 'application/mac-binhex40', - 'htke' => 'application/vnd.kenameaapp', - 'htm' => 'text/html', - 'html' => 'text/html', - 'hvd' => 'application/vnd.yamaha.hv-dic', - 'hvp' => 'application/vnd.yamaha.hv-voice', - 'hvs' => 'application/vnd.yamaha.hv-script', - 'i2g' => 'application/vnd.intergeo', - 'icc' => 'application/vnd.iccprofile', - 'ice' => 'x-conference/x-cooltalk', - 'icm' => 'application/vnd.iccprofile', - 'ico' => 'image/x-icon', - 'ics' => 'text/calendar', - 'ief' => 'image/ief', - 'ifb' => 'text/calendar', - 'ifm' => 'application/vnd.shana.informed.formdata', - 'iges' => 'model/iges', - 'igl' => 'application/vnd.igloader', - 'igm' => 'application/vnd.insors.igm', - 'igs' => 'model/iges', - 'igx' => 'application/vnd.micrografx.igx', - 'iif' => 'application/vnd.shana.informed.interchange', - 'imp' => 'application/vnd.accpac.simply.imp', - 'ims' => 'application/vnd.ms-ims', - 'in' => 'text/plain', - 'ink' => 'application/inkml+xml', - 'inkml' => 'application/inkml+xml', - 'install' => 'application/x-install-instructions', - 'iota' => 'application/vnd.astraea-software.iota', - 'ipfix' => 'application/ipfix', - 'ipk' => 'application/vnd.shana.informed.package', - 'irm' => 'application/vnd.ibm.rights-management', - 'irp' => 'application/vnd.irepository.package+xml', - 'iso' => 'application/x-iso9660-image', - 'itp' => 'application/vnd.shana.informed.formtemplate', - 'ivp' => 'application/vnd.immervision-ivp', - 'ivu' => 'application/vnd.immervision-ivu', - 'jad' => 'text/vnd.sun.j2me.app-descriptor', - 'jam' => 'application/vnd.jam', - 'jar' => 'application/java-archive', - 'java' => 'text/x-java-source', - 'jisp' => 'application/vnd.jisp', - 'jlt' => 'application/vnd.hp-jlyt', - 'jnlp' => 'application/x-java-jnlp-file', - 'joda' => 'application/vnd.joost.joda-archive', - 'jpe' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'jpgm' => 'video/jpm', - 'jpgv' => 'video/jpeg', - 'jpm' => 'video/jpm', - 'js' => 'application/javascript', - 'json' => 'application/json', - 'jsonml' => 'application/jsonml+json', - 'kar' => 'audio/midi', - 'karbon' => 'application/vnd.kde.karbon', - 'kfo' => 'application/vnd.kde.kformula', - 'kia' => 'application/vnd.kidspiration', - 'kml' => 'application/vnd.google-earth.kml+xml', - 'kmz' => 'application/vnd.google-earth.kmz', - 'kne' => 'application/vnd.kinar', - 'knp' => 'application/vnd.kinar', - 'kon' => 'application/vnd.kde.kontour', - 'kpr' => 'application/vnd.kde.kpresenter', - 'kpt' => 'application/vnd.kde.kpresenter', - 'kpxx' => 'application/vnd.ds-keypoint', - 'ksp' => 'application/vnd.kde.kspread', - 'ktr' => 'application/vnd.kahootz', - 'ktx' => 'image/ktx', - 'ktz' => 'application/vnd.kahootz', - 'kwd' => 'application/vnd.kde.kword', - 'kwt' => 'application/vnd.kde.kword', - 'lasxml' => 'application/vnd.las.las+xml', - 'latex' => 'application/x-latex', - 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', - 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', - 'les' => 'application/vnd.hhe.lesson-player', - 'lha' => 'application/x-lzh-compressed', - 'link66' => 'application/vnd.route66.link66+xml', - 'list' => 'text/plain', - 'list3820' => 'application/vnd.ibm.modcap', - 'listafp' => 'application/vnd.ibm.modcap', - 'lnk' => 'application/x-ms-shortcut', - 'log' => 'text/plain', - 'lostxml' => 'application/lost+xml', - 'lrf' => 'application/octet-stream', - 'lrm' => 'application/vnd.ms-lrm', - 'ltf' => 'application/vnd.frogans.ltf', - 'lvp' => 'audio/vnd.lucent.voice', - 'lwp' => 'application/vnd.lotus-wordpro', - 'lzh' => 'application/x-lzh-compressed', - 'm13' => 'application/x-msmediaview', - 'm14' => 'application/x-msmediaview', - 'm1v' => 'video/mpeg', - 'm21' => 'application/mp21', - 'm2a' => 'audio/mpeg', - 'm2v' => 'video/mpeg', - 'm3a' => 'audio/mpeg', - 'm3u' => 'audio/x-mpegurl', - 'm3u8' => 'application/vnd.apple.mpegurl', - 'm4a' => 'audio/mp4', - 'm4u' => 'video/vnd.mpegurl', - 'm4v' => 'video/x-m4v', - 'ma' => 'application/mathematica', - 'mads' => 'application/mads+xml', - 'mag' => 'application/vnd.ecowin.chart', - 'maker' => 'application/vnd.framemaker', - 'man' => 'text/troff', - 'mar' => 'application/octet-stream', - 'mathml' => 'application/mathml+xml', - 'mb' => 'application/mathematica', - 'mbk' => 'application/vnd.mobius.mbk', - 'mbox' => 'application/mbox', - 'mc1' => 'application/vnd.medcalcdata', - 'mcd' => 'application/vnd.mcd', - 'mcurl' => 'text/vnd.curl.mcurl', - 'mdb' => 'application/x-msaccess', - 'mdi' => 'image/vnd.ms-modi', - 'me' => 'text/troff', - 'mesh' => 'model/mesh', - 'meta4' => 'application/metalink4+xml', - 'metalink' => 'application/metalink+xml', - 'mets' => 'application/mets+xml', - 'mfm' => 'application/vnd.mfmp', - 'mft' => 'application/rpki-manifest', - 'mgp' => 'application/vnd.osgeo.mapguide.package', - 'mgz' => 'application/vnd.proteus.magazine', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'mie' => 'application/x-mie', - 'mif' => 'application/vnd.mif', - 'mime' => 'message/rfc822', - 'mj2' => 'video/mj2', - 'mjp2' => 'video/mj2', - 'mk3d' => 'video/x-matroska', - 'mka' => 'audio/x-matroska', - 'mks' => 'video/x-matroska', - 'mkv' => 'video/x-matroska', - 'mlp' => 'application/vnd.dolby.mlp', - 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', - 'mmf' => 'application/vnd.smaf', - 'mmr' => 'image/vnd.fujixerox.edmics-mmr', - 'mng' => 'video/x-mng', - 'mny' => 'application/x-msmoney', - 'mobi' => 'application/x-mobipocket-ebook', - 'mods' => 'application/mods+xml', - 'mov' => 'video/quicktime', - 'movie' => 'video/x-sgi-movie', - 'mp2' => 'audio/mpeg', - 'mp21' => 'application/mp21', - 'mp2a' => 'audio/mpeg', - 'mp3' => 'audio/mpeg', - 'mp4' => 'video/mp4', - 'mp4a' => 'audio/mp4', - 'mp4s' => 'application/mp4', - 'mp4v' => 'video/mp4', - 'mpc' => 'application/vnd.mophun.certificate', - 'mpe' => 'video/mpeg', - 'mpeg' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'mpg4' => 'video/mp4', - 'mpga' => 'audio/mpeg', - 'mpkg' => 'application/vnd.apple.installer+xml', - 'mpm' => 'application/vnd.blueice.multipass', - 'mpn' => 'application/vnd.mophun.application', - 'mpp' => 'application/vnd.ms-project', - 'mpt' => 'application/vnd.ms-project', - 'mpy' => 'application/vnd.ibm.minipay', - 'mqy' => 'application/vnd.mobius.mqy', - 'mrc' => 'application/marc', - 'mrcx' => 'application/marcxml+xml', - 'ms' => 'text/troff', - 'mscml' => 'application/mediaservercontrol+xml', - 'mseed' => 'application/vnd.fdsn.mseed', - 'mseq' => 'application/vnd.mseq', - 'msf' => 'application/vnd.epson.msf', - 'msh' => 'model/mesh', - 'msi' => 'application/x-msdownload', - 'msl' => 'application/vnd.mobius.msl', - 'msty' => 'application/vnd.muvee.style', - 'mts' => 'model/vnd.mts', - 'mus' => 'application/vnd.musician', - 'musicxml' => 'application/vnd.recordare.musicxml+xml', - 'mvb' => 'application/x-msmediaview', - 'mwf' => 'application/vnd.mfer', - 'mxf' => 'application/mxf', - 'mxl' => 'application/vnd.recordare.musicxml', - 'mxml' => 'application/xv+xml', - 'mxs' => 'application/vnd.triscape.mxs', - 'mxu' => 'video/vnd.mpegurl', - 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', - 'n3' => 'text/n3', - 'nb' => 'application/mathematica', - 'nbp' => 'application/vnd.wolfram.player', - 'nc' => 'application/x-netcdf', - 'ncx' => 'application/x-dtbncx+xml', - 'nfo' => 'text/x-nfo', - 'ngdat' => 'application/vnd.nokia.n-gage.data', - 'nitf' => 'application/vnd.nitf', - 'nlu' => 'application/vnd.neurolanguage.nlu', - 'nml' => 'application/vnd.enliven', - 'nnd' => 'application/vnd.noblenet-directory', - 'nns' => 'application/vnd.noblenet-sealer', - 'nnw' => 'application/vnd.noblenet-web', - 'npx' => 'image/vnd.net-fpx', - 'nsc' => 'application/x-conference', - 'nsf' => 'application/vnd.lotus-notes', - 'ntf' => 'application/vnd.nitf', - 'nzb' => 'application/x-nzb', - 'oa2' => 'application/vnd.fujitsu.oasys2', - 'oa3' => 'application/vnd.fujitsu.oasys3', - 'oas' => 'application/vnd.fujitsu.oasys', - 'obd' => 'application/x-msbinder', - 'obj' => 'application/x-tgif', - 'oda' => 'application/oda', - 'odb' => 'application/vnd.oasis.opendocument.database', - 'odc' => 'application/vnd.oasis.opendocument.chart', - 'odf' => 'application/vnd.oasis.opendocument.formula', - 'odft' => 'application/vnd.oasis.opendocument.formula-template', - 'odg' => 'application/vnd.oasis.opendocument.graphics', - 'odi' => 'application/vnd.oasis.opendocument.image', - 'odm' => 'application/vnd.oasis.opendocument.text-master', - 'odp' => 'application/vnd.oasis.opendocument.presentation', - 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', - 'odt' => 'application/vnd.oasis.opendocument.text', - 'oga' => 'audio/ogg', - 'ogg' => 'audio/ogg', - 'ogv' => 'video/ogg', - 'ogx' => 'application/ogg', - 'omdoc' => 'application/omdoc+xml', - 'onepkg' => 'application/onenote', - 'onetmp' => 'application/onenote', - 'onetoc' => 'application/onenote', - 'onetoc2' => 'application/onenote', - 'opf' => 'application/oebps-package+xml', - 'opml' => 'text/x-opml', - 'oprc' => 'application/vnd.palm', - 'org' => 'application/vnd.lotus-organizer', - 'osf' => 'application/vnd.yamaha.openscoreformat', - 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', - 'otc' => 'application/vnd.oasis.opendocument.chart-template', - 'otf' => 'application/x-font-otf', - 'otg' => 'application/vnd.oasis.opendocument.graphics-template', - 'oth' => 'application/vnd.oasis.opendocument.text-web', - 'oti' => 'application/vnd.oasis.opendocument.image-template', - 'otp' => 'application/vnd.oasis.opendocument.presentation-template', - 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', - 'ott' => 'application/vnd.oasis.opendocument.text-template', - 'oxps' => 'application/oxps', - 'oxt' => 'application/vnd.openofficeorg.extension', - 'p' => 'text/x-pascal', - 'p10' => 'application/pkcs10', - 'p12' => 'application/x-pkcs12', - 'p7b' => 'application/x-pkcs7-certificates', - 'p7c' => 'application/pkcs7-mime', - 'p7m' => 'application/pkcs7-mime', - 'p7r' => 'application/x-pkcs7-certreqresp', - 'p7s' => 'application/pkcs7-signature', - 'p8' => 'application/pkcs8', - 'pas' => 'text/x-pascal', - 'paw' => 'application/vnd.pawaafile', - 'pbd' => 'application/vnd.powerbuilder6', - 'pbm' => 'image/x-portable-bitmap', - 'pcap' => 'application/vnd.tcpdump.pcap', - 'pcf' => 'application/x-font-pcf', - 'pcl' => 'application/vnd.hp-pcl', - 'pclxl' => 'application/vnd.hp-pclxl', - 'pct' => 'image/x-pict', - 'pcurl' => 'application/vnd.curl.pcurl', - 'pcx' => 'image/x-pcx', - 'pdb' => 'application/vnd.palm', - 'pdf' => 'application/pdf', - 'pfa' => 'application/x-font-type1', - 'pfb' => 'application/x-font-type1', - 'pfm' => 'application/x-font-type1', - 'pfr' => 'application/font-tdpfr', - 'pfx' => 'application/x-pkcs12', - 'pgm' => 'image/x-portable-graymap', - 'pgn' => 'application/x-chess-pgn', - 'pgp' => 'application/pgp-encrypted', - 'php' => 'application/x-php', - 'php3' => 'application/x-php', - 'php4' => 'application/x-php', - 'php5' => 'application/x-php', - 'pic' => 'image/x-pict', - 'pkg' => 'application/octet-stream', - 'pki' => 'application/pkixcmp', - 'pkipath' => 'application/pkix-pkipath', - 'plb' => 'application/vnd.3gpp.pic-bw-large', - 'plc' => 'application/vnd.mobius.plc', - 'plf' => 'application/vnd.pocketlearn', - 'pls' => 'application/pls+xml', - 'pml' => 'application/vnd.ctc-posml', - 'png' => 'image/png', - 'pnm' => 'image/x-portable-anymap', - 'portpkg' => 'application/vnd.macports.portpkg', - 'pot' => 'application/vnd.ms-powerpoint', - 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12', - 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', - 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12', - 'ppd' => 'application/vnd.cups-ppd', - 'ppm' => 'image/x-portable-pixmap', - 'pps' => 'application/vnd.ms-powerpoint', - 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12', - 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', - 'ppt' => 'application/vnd.ms-powerpoint', - 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12', - 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'pqa' => 'application/vnd.palm', - 'prc' => 'application/x-mobipocket-ebook', - 'pre' => 'application/vnd.lotus-freelance', - 'prf' => 'application/pics-rules', - 'ps' => 'application/postscript', - 'psb' => 'application/vnd.3gpp.pic-bw-small', - 'psd' => 'image/vnd.adobe.photoshop', - 'psf' => 'application/x-font-linux-psf', - 'pskcxml' => 'application/pskc+xml', - 'ptid' => 'application/vnd.pvi.ptid1', - 'pub' => 'application/x-mspublisher', - 'pvb' => 'application/vnd.3gpp.pic-bw-var', - 'pwn' => 'application/vnd.3m.post-it-notes', - 'pya' => 'audio/vnd.ms-playready.media.pya', - 'pyv' => 'video/vnd.ms-playready.media.pyv', - 'qam' => 'application/vnd.epson.quickanime', - 'qbo' => 'application/vnd.intu.qbo', - 'qfx' => 'application/vnd.intu.qfx', - 'qps' => 'application/vnd.publishare-delta-tree', - 'qt' => 'video/quicktime', - 'qwd' => 'application/vnd.quark.quarkxpress', - 'qwt' => 'application/vnd.quark.quarkxpress', - 'qxb' => 'application/vnd.quark.quarkxpress', - 'qxd' => 'application/vnd.quark.quarkxpress', - 'qxl' => 'application/vnd.quark.quarkxpress', - 'qxt' => 'application/vnd.quark.quarkxpress', - 'ra' => 'audio/x-pn-realaudio', - 'ram' => 'audio/x-pn-realaudio', - 'rar' => 'application/x-rar-compressed', - 'ras' => 'image/x-cmu-raster', - 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', - 'rdf' => 'application/rdf+xml', - 'rdz' => 'application/vnd.data-vision.rdz', - 'rep' => 'application/vnd.businessobjects', - 'res' => 'application/x-dtbresource+xml', - 'rgb' => 'image/x-rgb', - 'rif' => 'application/reginfo+xml', - 'rip' => 'audio/vnd.rip', - 'ris' => 'application/x-research-info-systems', - 'rl' => 'application/resource-lists+xml', - 'rlc' => 'image/vnd.fujixerox.edmics-rlc', - 'rld' => 'application/resource-lists-diff+xml', - 'rm' => 'application/vnd.rn-realmedia', - 'rmi' => 'audio/midi', - 'rmp' => 'audio/x-pn-realaudio-plugin', - 'rms' => 'application/vnd.jcp.javame.midlet-rms', - 'rmvb' => 'application/vnd.rn-realmedia-vbr', - 'rnc' => 'application/relax-ng-compact-syntax', - 'roa' => 'application/rpki-roa', - 'roff' => 'text/troff', - 'rp9' => 'application/vnd.cloanto.rp9', - 'rpss' => 'application/vnd.nokia.radio-presets', - 'rpst' => 'application/vnd.nokia.radio-preset', - 'rq' => 'application/sparql-query', - 'rs' => 'application/rls-services+xml', - 'rsd' => 'application/rsd+xml', - 'rss' => 'application/rss+xml', - 'rtf' => 'application/rtf', - 'rtx' => 'text/richtext', - 's' => 'text/x-asm', - 's3m' => 'audio/s3m', - 'saf' => 'application/vnd.yamaha.smaf-audio', - 'sbml' => 'application/sbml+xml', - 'sc' => 'application/vnd.ibm.secure-container', - 'scd' => 'application/x-msschedule', - 'scm' => 'application/vnd.lotus-screencam', - 'scq' => 'application/scvp-cv-request', - 'scs' => 'application/scvp-cv-response', - 'scurl' => 'text/vnd.curl.scurl', - 'sda' => 'application/vnd.stardivision.draw', - 'sdc' => 'application/vnd.stardivision.calc', - 'sdd' => 'application/vnd.stardivision.impress', - 'sdkd' => 'application/vnd.solent.sdkm+xml', - 'sdkm' => 'application/vnd.solent.sdkm+xml', - 'sdp' => 'application/sdp', - 'sdw' => 'application/vnd.stardivision.writer', - 'see' => 'application/vnd.seemail', - 'seed' => 'application/vnd.fdsn.seed', - 'sema' => 'application/vnd.sema', - 'semd' => 'application/vnd.semd', - 'semf' => 'application/vnd.semf', - 'ser' => 'application/java-serialized-object', - 'setpay' => 'application/set-payment-initiation', - 'setreg' => 'application/set-registration-initiation', - 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', - 'sfs' => 'application/vnd.spotfire.sfs', - 'sfv' => 'text/x-sfv', - 'sgi' => 'image/sgi', - 'sgl' => 'application/vnd.stardivision.writer-global', - 'sgm' => 'text/sgml', - 'sgml' => 'text/sgml', - 'sh' => 'application/x-sh', - 'shar' => 'application/x-shar', - 'shf' => 'application/shf+xml', - 'sid' => 'image/x-mrsid-image', - 'sig' => 'application/pgp-signature', - 'sil' => 'audio/silk', - 'silo' => 'model/mesh', - 'sis' => 'application/vnd.symbian.install', - 'sisx' => 'application/vnd.symbian.install', - 'sit' => 'application/x-stuffit', - 'sitx' => 'application/x-stuffitx', - 'skd' => 'application/vnd.koan', - 'skm' => 'application/vnd.koan', - 'skp' => 'application/vnd.koan', - 'skt' => 'application/vnd.koan', - 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', - 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', - 'slt' => 'application/vnd.epson.salt', - 'sm' => 'application/vnd.stepmania.stepchart', - 'smf' => 'application/vnd.stardivision.math', - 'smi' => 'application/smil+xml', - 'smil' => 'application/smil+xml', - 'smv' => 'video/x-smv', - 'smzip' => 'application/vnd.stepmania.package', - 'snd' => 'audio/basic', - 'snf' => 'application/x-font-snf', - 'so' => 'application/octet-stream', - 'spc' => 'application/x-pkcs7-certificates', - 'spf' => 'application/vnd.yamaha.smaf-phrase', - 'spl' => 'application/x-futuresplash', - 'spot' => 'text/vnd.in3d.spot', - 'spp' => 'application/scvp-vp-response', - 'spq' => 'application/scvp-vp-request', - 'spx' => 'audio/ogg', - 'sql' => 'application/x-sql', - 'src' => 'application/x-wais-source', - 'srt' => 'application/x-subrip', - 'sru' => 'application/sru+xml', - 'srx' => 'application/sparql-results+xml', - 'ssdl' => 'application/ssdl+xml', - 'sse' => 'application/vnd.kodak-descriptor', - 'ssf' => 'application/vnd.epson.ssf', - 'ssml' => 'application/ssml+xml', - 'st' => 'application/vnd.sailingtracker.track', - 'stc' => 'application/vnd.sun.xml.calc.template', - 'std' => 'application/vnd.sun.xml.draw.template', - 'stf' => 'application/vnd.wt.stf', - 'sti' => 'application/vnd.sun.xml.impress.template', - 'stk' => 'application/hyperstudio', - 'stl' => 'application/vnd.ms-pki.stl', - 'str' => 'application/vnd.pg.format', - 'stw' => 'application/vnd.sun.xml.writer.template', - 'sub' => 'text/vnd.dvb.subtitle', - 'sus' => 'application/vnd.sus-calendar', - 'susp' => 'application/vnd.sus-calendar', - 'sv4cpio' => 'application/x-sv4cpio', - 'sv4crc' => 'application/x-sv4crc', - 'svc' => 'application/vnd.dvb.service', - 'svd' => 'application/vnd.svd', - 'svg' => 'image/svg+xml', - 'svgz' => 'image/svg+xml', - 'swa' => 'application/x-director', - 'swf' => 'application/x-shockwave-flash', - 'swi' => 'application/vnd.aristanetworks.swi', - 'sxc' => 'application/vnd.sun.xml.calc', - 'sxd' => 'application/vnd.sun.xml.draw', - 'sxg' => 'application/vnd.sun.xml.writer.global', - 'sxi' => 'application/vnd.sun.xml.impress', - 'sxm' => 'application/vnd.sun.xml.math', - 'sxw' => 'application/vnd.sun.xml.writer', - 't' => 'text/troff', - 't3' => 'application/x-t3vm-image', - 'taglet' => 'application/vnd.mynfc', - 'tao' => 'application/vnd.tao.intent-module-archive', - 'tar' => 'application/x-tar', - 'tcap' => 'application/vnd.3gpp2.tcap', - 'tcl' => 'application/x-tcl', - 'teacher' => 'application/vnd.smart.teacher', - 'tei' => 'application/tei+xml', - 'teicorpus' => 'application/tei+xml', - 'tex' => 'application/x-tex', - 'texi' => 'application/x-texinfo', - 'texinfo' => 'application/x-texinfo', - 'text' => 'text/plain', - 'tfi' => 'application/thraud+xml', - 'tfm' => 'application/x-tex-tfm', - 'tga' => 'image/x-tga', - 'thmx' => 'application/vnd.ms-officetheme', - 'tif' => 'image/tiff', - 'tiff' => 'image/tiff', - 'tmo' => 'application/vnd.tmobile-livetv', - 'torrent' => 'application/x-bittorrent', - 'tpl' => 'application/vnd.groove-tool-template', - 'tpt' => 'application/vnd.trid.tpt', - 'tr' => 'text/troff', - 'tra' => 'application/vnd.trueapp', - 'trm' => 'application/x-msterminal', - 'tsd' => 'application/timestamped-data', - 'tsv' => 'text/tab-separated-values', - 'ttc' => 'application/x-font-ttf', - 'ttf' => 'application/x-font-ttf', - 'ttl' => 'text/turtle', - 'twd' => 'application/vnd.simtech-mindmapper', - 'twds' => 'application/vnd.simtech-mindmapper', - 'txd' => 'application/vnd.genomatix.tuxedo', - 'txf' => 'application/vnd.mobius.txf', - 'txt' => 'text/plain', - 'u32' => 'application/x-authorware-bin', - 'udeb' => 'application/x-debian-package', - 'ufd' => 'application/vnd.ufdl', - 'ufdl' => 'application/vnd.ufdl', - 'ulx' => 'application/x-glulx', - 'umj' => 'application/vnd.umajin', - 'unityweb' => 'application/vnd.unity', - 'uoml' => 'application/vnd.uoml+xml', - 'uri' => 'text/uri-list', - 'uris' => 'text/uri-list', - 'urls' => 'text/uri-list', - 'ustar' => 'application/x-ustar', - 'utz' => 'application/vnd.uiq.theme', - 'uu' => 'text/x-uuencode', - 'uva' => 'audio/vnd.dece.audio', - 'uvd' => 'application/vnd.dece.data', - 'uvf' => 'application/vnd.dece.data', - 'uvg' => 'image/vnd.dece.graphic', - 'uvh' => 'video/vnd.dece.hd', - 'uvi' => 'image/vnd.dece.graphic', - 'uvm' => 'video/vnd.dece.mobile', - 'uvp' => 'video/vnd.dece.pd', - 'uvs' => 'video/vnd.dece.sd', - 'uvt' => 'application/vnd.dece.ttml+xml', - 'uvu' => 'video/vnd.uvvu.mp4', - 'uvv' => 'video/vnd.dece.video', - 'uvva' => 'audio/vnd.dece.audio', - 'uvvd' => 'application/vnd.dece.data', - 'uvvf' => 'application/vnd.dece.data', - 'uvvg' => 'image/vnd.dece.graphic', - 'uvvh' => 'video/vnd.dece.hd', - 'uvvi' => 'image/vnd.dece.graphic', - 'uvvm' => 'video/vnd.dece.mobile', - 'uvvp' => 'video/vnd.dece.pd', - 'uvvs' => 'video/vnd.dece.sd', - 'uvvt' => 'application/vnd.dece.ttml+xml', - 'uvvu' => 'video/vnd.uvvu.mp4', - 'uvvv' => 'video/vnd.dece.video', - 'uvvx' => 'application/vnd.dece.unspecified', - 'uvvz' => 'application/vnd.dece.zip', - 'uvx' => 'application/vnd.dece.unspecified', - 'uvz' => 'application/vnd.dece.zip', - 'vcard' => 'text/vcard', - 'vcd' => 'application/x-cdlink', - 'vcf' => 'text/x-vcard', - 'vcg' => 'application/vnd.groove-vcard', - 'vcs' => 'text/x-vcalendar', - 'vcx' => 'application/vnd.vcx', - 'vis' => 'application/vnd.visionary', - 'viv' => 'video/vnd.vivo', - 'vob' => 'video/x-ms-vob', - 'vor' => 'application/vnd.stardivision.writer', - 'vox' => 'application/x-authorware-bin', - 'vrml' => 'model/vrml', - 'vsd' => 'application/vnd.visio', - 'vsf' => 'application/vnd.vsf', - 'vss' => 'application/vnd.visio', - 'vst' => 'application/vnd.visio', - 'vsw' => 'application/vnd.visio', - 'vtu' => 'model/vnd.vtu', - 'vxml' => 'application/voicexml+xml', - 'w3d' => 'application/x-director', - 'wad' => 'application/x-doom', - 'wav' => 'audio/x-wav', - 'wax' => 'audio/x-ms-wax', - 'wbmp' => 'image/vnd.wap.wbmp', - 'wbs' => 'application/vnd.criticaltools.wbs+xml', - 'wbxml' => 'application/vnd.wap.wbxml', - 'wcm' => 'application/vnd.ms-works', - 'wdb' => 'application/vnd.ms-works', - 'wdp' => 'image/vnd.ms-photo', - 'weba' => 'audio/webm', - 'webm' => 'video/webm', - 'webp' => 'image/webp', - 'wg' => 'application/vnd.pmi.widget', - 'wgt' => 'application/widget', - 'wks' => 'application/vnd.ms-works', - 'wm' => 'video/x-ms-wm', - 'wma' => 'audio/x-ms-wma', - 'wmd' => 'application/x-ms-wmd', - 'wmf' => 'application/x-msmetafile', - 'wml' => 'text/vnd.wap.wml', - 'wmlc' => 'application/vnd.wap.wmlc', - 'wmls' => 'text/vnd.wap.wmlscript', - 'wmlsc' => 'application/vnd.wap.wmlscriptc', - 'wmv' => 'video/x-ms-wmv', - 'wmx' => 'video/x-ms-wmx', - 'wmz' => 'application/x-msmetafile', - 'woff' => 'application/font-woff', - 'wpd' => 'application/vnd.wordperfect', - 'wpl' => 'application/vnd.ms-wpl', - 'wps' => 'application/vnd.ms-works', - 'wqd' => 'application/vnd.wqd', - 'wri' => 'application/x-mswrite', - 'wrl' => 'model/vrml', - 'wsdl' => 'application/wsdl+xml', - 'wspolicy' => 'application/wspolicy+xml', - 'wtb' => 'application/vnd.webturbo', - 'wvx' => 'video/x-ms-wvx', - 'x32' => 'application/x-authorware-bin', - 'x3d' => 'model/x3d+xml', - 'x3db' => 'model/x3d+binary', - 'x3dbz' => 'model/x3d+binary', - 'x3dv' => 'model/x3d+vrml', - 'x3dvz' => 'model/x3d+vrml', - 'x3dz' => 'model/x3d+xml', - 'xaml' => 'application/xaml+xml', - 'xap' => 'application/x-silverlight-app', - 'xar' => 'application/vnd.xara', - 'xbap' => 'application/x-ms-xbap', - 'xbd' => 'application/vnd.fujixerox.docuworks.binder', - 'xbm' => 'image/x-xbitmap', - 'xdf' => 'application/xcap-diff+xml', - 'xdm' => 'application/vnd.syncml.dm+xml', - 'xdp' => 'application/vnd.adobe.xdp+xml', - 'xdssc' => 'application/dssc+xml', - 'xdw' => 'application/vnd.fujixerox.docuworks', - 'xenc' => 'application/xenc+xml', - 'xer' => 'application/patch-ops-error+xml', - 'xfdf' => 'application/vnd.adobe.xfdf', - 'xfdl' => 'application/vnd.xfdl', - 'xht' => 'application/xhtml+xml', - 'xhtml' => 'application/xhtml+xml', - 'xhvml' => 'application/xv+xml', - 'xif' => 'image/vnd.xiff', - 'xla' => 'application/vnd.ms-excel', - 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12', - 'xlc' => 'application/vnd.ms-excel', - 'xlf' => 'application/x-xliff+xml', - 'xlm' => 'application/vnd.ms-excel', - 'xls' => 'application/vnd.ms-excel', - 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12', - 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12', - 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'xlt' => 'application/vnd.ms-excel', - 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12', - 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', - 'xlw' => 'application/vnd.ms-excel', - 'xm' => 'audio/xm', - 'xml' => 'application/xml', - 'xo' => 'application/vnd.olpc-sugar', - 'xop' => 'application/xop+xml', - 'xpi' => 'application/x-xpinstall', - 'xpl' => 'application/xproc+xml', - 'xpm' => 'image/x-xpixmap', - 'xpr' => 'application/vnd.is-xpr', - 'xps' => 'application/vnd.ms-xpsdocument', - 'xpw' => 'application/vnd.intercon.formnet', - 'xpx' => 'application/vnd.intercon.formnet', - 'xsl' => 'application/xml', - 'xslt' => 'application/xslt+xml', - 'xsm' => 'application/vnd.syncml+xml', - 'xspf' => 'application/xspf+xml', - 'xul' => 'application/vnd.mozilla.xul+xml', - 'xvm' => 'application/xv+xml', - 'xvml' => 'application/xv+xml', - 'xwd' => 'image/x-xwindowdump', - 'xyz' => 'chemical/x-xyz', - 'xz' => 'application/x-xz', - 'yang' => 'application/yang', - 'yin' => 'application/yin+xml', - 'z1' => 'application/x-zmachine', - 'z2' => 'application/x-zmachine', - 'z3' => 'application/x-zmachine', - 'z4' => 'application/x-zmachine', - 'z5' => 'application/x-zmachine', - 'z6' => 'application/x-zmachine', - 'z7' => 'application/x-zmachine', - 'z8' => 'application/x-zmachine', - 'zaz' => 'application/vnd.zzazz.deck+xml', - 'zip' => 'application/zip', - 'zir' => 'application/vnd.zul', - 'zirz' => 'application/vnd.zul', - 'zmm' => 'application/vnd.handheld-entertainment+xml', - '123' => 'application/vnd.lotus-1-2-3', -); diff --git a/tools/swift/preferences.php b/tools/swift/preferences.php deleted file mode 100644 index 0b430e67d..000000000 --- a/tools/swift/preferences.php +++ /dev/null @@ -1,25 +0,0 @@ -setCharset('utf-8'); - -// Without these lines the default caching mechanism is "array" but this uses a lot of memory. -// If possible, use a disk cache to enable attaching large attachments etc. -// You can override the default temporary directory by setting the TMPDIR environment variable. -if (@is_writable($tmpDir = sys_get_temp_dir())) { - $preferences->setTempDir($tmpDir)->setCacheType('disk'); -} - -// this should only be done when Swiftmailer won't use the native QP content encoder -// see mime_deps.php -if (PHP_VERSION_ID < 50407) { - $preferences->setQPDotEscape(false); -} diff --git a/tools/swift/swift_init.php b/tools/swift/swift_init.php deleted file mode 100644 index ff7196344..000000000 --- a/tools/swift/swift_init.php +++ /dev/null @@ -1,28 +0,0 @@ - 'application/x-php', - 'php3' => 'application/x-php', - 'php4' => 'application/x-php', - 'php5' => 'application/x-php', - 'zip' => 'application/zip', - 'gif' => 'image/gif', - 'png' => 'image/png', - 'css' => 'text/css', - 'js' => 'text/javascript', - 'txt' => 'text/plain', - 'aif' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'avi' => 'video/avi', - 'bmp' => 'image/bmp', - 'bz2' => 'application/x-bz2', - 'csv' => 'text/csv', - 'dmg' => 'application/x-apple-diskimage', - 'doc' => 'application/msword', - 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'eml' => 'message/rfc822', - 'aps' => 'application/postscript', - 'exe' => 'application/x-ms-dos-executable', - 'flv' => 'video/x-flv', - 'gz' => 'application/x-gzip', - 'hqx' => 'application/stuffit', - 'htm' => 'text/html', - 'html' => 'text/html', - 'jar' => 'application/x-java-archive', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'm3u' => 'audio/x-mpegurl', - 'm4a' => 'audio/mp4', - 'mdb' => 'application/x-msaccess', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'mov' => 'video/quicktime', - 'mp3' => 'audio/mpeg', - 'mp4' => 'video/mp4', - 'mpeg' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'odg' => 'vnd.oasis.opendocument.graphics', - 'odp' => 'vnd.oasis.opendocument.presentation', - 'odt' => 'vnd.oasis.opendocument.text', - 'ods' => 'vnd.oasis.opendocument.spreadsheet', - 'ogg' => 'audio/ogg', - 'pdf' => 'application/pdf', - 'ppt' => 'application/vnd.ms-powerpoint', - 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'ps' => 'application/postscript', - 'rar' => 'application/x-rar-compressed', - 'rtf' => 'application/rtf', - 'tar' => 'application/x-tar', - 'sit' => 'application/x-stuffit', - 'svg' => 'image/svg+xml', - 'tif' => 'image/tiff', - 'tiff' => 'image/tiff', - 'ttf' => 'application/x-font-truetype', - 'vcf' => 'text/x-vcard', - 'wav' => 'audio/wav', - 'wma' => 'audio/x-ms-wma', - 'wmv' => 'audio/x-ms-wmv', - 'xls' => 'application/vnd.ms-excel', - 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'xml' => 'application/xml', - ); - - // wrap array for generating file - foreach ($valid_mime_types_preset as $extension => $mime_type) { - // generate array for mimetype to extension resolver (only first match) - $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; - } - - // collect extensions - $valid_extensions = array(); - - // all extensions from second match - foreach ($matches[2] as $i => $extensions) { - // explode multiple extensions from string - $extensions = explode(' ', strtolower($extensions)); - - // force array for foreach - if (!is_array($extensions)) { - $extensions = array($extensions); - } - - foreach ($extensions as $extension) { - // get mime type - $mime_type = $matches[1][$i]; - - // check if string length lower than 10 - if (strlen($extension) < 10) { - // add extension - $valid_extensions[] = $extension; - - if (!isset($valid_mime_types[$mime_type])) { - // generate array for mimetype to extension resolver (only first match) - $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; - } - } - } - } - } - - $xml = simplexml_load_string($mime_xml); - - foreach ($xml as $node) { - // check if there is no pattern - if (!isset($node->glob['pattern'])) { - continue; - } - - // get all matching extensions from match - foreach ((array) $node->glob['pattern'] as $extension) { - // skip none glob extensions - if (strpos($extension, '.') === false) { - continue; - } - - // remove get only last part - $extension = explode('.', strtolower($extension)); - $extension = end($extension); - - // maximum length in database column - if (strlen($extension) <= 9) { - $valid_extensions[] = $extension; - } - } - - if (isset($node->glob['pattern'][0])) { - // mime type - $mime_type = strtolower((string) $node['type']); - - // get first extension - $extension = strtolower(trim($node->glob['ddpattern'][0], '*.')); - - // skip none glob extensions and check if string length between 1 and 10 - if (strpos($extension, '.') !== false || strlen($extension) < 1 || strlen($extension) > 9) { - continue; - } - - // check if string length lower than 10 - if (!isset($valid_mime_types[$mime_type])) { - // generate array for mimetype to extension resolver (only first match) - $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; - } - } - } - - // full list of valid extensions only - $valid_mime_types = array_unique($valid_mime_types); - ksort($valid_mime_types); - - // combine mime types and extensions array - $output = "$preamble\$swift_mime_types = array(\n ".implode($valid_mime_types, ",\n ")."\n);"; - - // write mime_types.php config file - @file_put_contents('./mime_types.php', $output); -} - -generateUpToDateMimeArray(); diff --git a/tools/tar/Tar.php b/tools/tar/Tar.php index 532584622..532bc74de 100644 --- a/tools/tar/Tar.php +++ b/tools/tar/Tar.php @@ -280,7 +280,7 @@ class Archive_Tar extends PEAR * single string with names separated by a single * blank space. * - * @return true on success, false on error. + * @return bool true on success, false on error. * @see createModify() */ public function create($p_filelist) @@ -300,7 +300,7 @@ class Archive_Tar extends PEAR * single string with names separated by a single * blank space. * - * @return true on success, false on error. + * @return bool true on success, false on error. * @see createModify() * @access public */ @@ -443,7 +443,7 @@ class Archive_Tar extends PEAR * each element in the list, when * relevant. * - * @return true on success, false on error. + * @return bool true on success, false on error. */ public function addModify($p_filelist, $p_add_dir, $p_remove_dir = '') { @@ -496,7 +496,7 @@ class Archive_Tar extends PEAR * gid => the group ID of the file * (default = 0 = root) * - * @return true on success, false on error. + * @return bool true on success, false on error. */ public function addString($p_filename, $p_string, $p_datetime = false, $p_params = array()) { @@ -622,7 +622,7 @@ class Archive_Tar extends PEAR * @param boolean $p_preserve Preserve user/group ownership of files * @param boolean $p_symlinks Allow symlinks. * - * @return true on success, false on error. + * @return bool true on success, false on error. * @see extractModify() */ public function extractList($p_filelist, $p_path = '', $p_remove_path = '', $p_preserve = false, $p_symlinks = true) @@ -660,7 +660,7 @@ class Archive_Tar extends PEAR * list of parameters, in the format attribute code + attribute values : * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ','); * - * @return true on success, false on error. + * @return bool true on success, false on error. */ public function setAttribute() { @@ -2115,7 +2115,7 @@ class Archive_Tar extends PEAR if ($v_extract_file) { if ($v_header['typeflag'] == "5") { if (!@file_exists($v_header['filename'])) { - if (!@mkdir($v_header['filename'], 0777)) { + if (!@mkdir($v_header['filename'], 0775)) { $this->_error( 'Unable to create directory {' . $v_header['filename'] . '}' @@ -2124,32 +2124,6 @@ class Archive_Tar extends PEAR } } } elseif ($v_header['typeflag'] == "2") { - $link_depth = 0; - foreach (explode("/", $v_header['filename']) as $dir) { - if ($dir === "..") { - $link_depth--; - } elseif ($dir !== "" && $dir !== "." ) { - $link_depth++; - } - } - foreach (explode("/", $v_header['link']) as $dir){ - if ($link_depth <= 0) { - break; - } - if ($dir === "..") { - $link_depth--; - } elseif ($dir !== "" && $dir !== ".") { - $link_depth++; - } - } - if (strpos($v_header['link'], "/") === 0 or $link_depth <= 0) { - $this->_error( - 'Out-of-path file extraction {' - . $v_header['filename'] . ' --> ' . - $v_header['link'] . '}' - ); - return false; - } if (!$p_symlinks) { $this->_warning('Symbolic links are not allowed. ' . 'Unable to extract {' @@ -2157,6 +2131,40 @@ class Archive_Tar extends PEAR ); return false; } + $absolute_link = FALSE; + $link_depth = 0; + if (strpos($v_header['link'], "/") === 0 || strpos($v_header['link'], ':') !== FALSE) { + $absolute_link = TRUE; + } + else { + $s_filename = preg_replace('@^' . preg_quote($p_path) . '@', "", $v_header['filename']); + $s_linkname = str_replace('\\', '/', $v_header['link']); + foreach (explode("/", $s_filename) as $dir) { + if ($dir === "..") { + $link_depth--; + } elseif ($dir !== "" && $dir !== "." ) { + $link_depth++; + } + } + foreach (explode("/", $s_linkname) as $dir){ + if ($link_depth <= 0) { + break; + } + if ($dir === "..") { + $link_depth--; + } elseif ($dir !== "" && $dir !== ".") { + $link_depth++; + } + } + } + if ($absolute_link || $link_depth <= 0) { + $this->_error( + 'Out-of-path file extraction {' + . $v_header['filename'] . ' --> ' . + $v_header['link'] . '}' + ); + return false; + } if (@file_exists($v_header['filename'])) { @unlink($v_header['filename']); } @@ -2440,7 +2448,7 @@ class Archive_Tar extends PEAR return false; } - if (!@mkdir($p_dir, 0777)) { + if (!@mkdir($p_dir, 0775)) { $this->_error("Unable to create directory '$p_dir'"); return false; } @@ -2519,4 +2527,4 @@ class Archive_Tar extends PEAR } return $p_path; } -} +} \ No newline at end of file diff --git a/tools/tcpdf/CHANGELOG.TXT b/tools/tcpdf/CHANGELOG.TXT index 3bdae3e24..4437e2cf3 100644 --- a/tools/tcpdf/CHANGELOG.TXT +++ b/tools/tcpdf/CHANGELOG.TXT @@ -1,16 +1,211 @@ -6.2.25 +6.7.8 (2024-12-13) + - Improve SVG detection by checking for (mandatory) namespace. + - Use late state binding now that minimum PHP version is 5.5. + +6.7.7 (2024-10-26) + - Update regular expression to avoid ReDoS (CVE-2024-22641) + - [PHP 8.4] Fix: Curl CURLOPT_BINARYTRANSFER deprecated #675 + - SVG detection fix for inline data images #646 + - Fix count svg #647 + - Since the version 6.7.4, the "0" is considered like empty string and not displayed + - Fixed handling of transparency in PDF/A mode in addExtGState method + - Encrypt /DA string when document is encrypted + - Improve quality of generated seed, avoid potential security pitfall + - Try to use random_bytes() first if it's available + - Do not include the server parameters in the generated seed, as they might contain sensitive data + - Fix bug on _getannotsrefs when there are empty signature appearances but not other annot on a page + - Fix SVG coordinate parser that caused drawing artifacts + - Remove usage of xml_set_object() function + +6.7.6 (2024-10-06) + - Forbid access to parent folder in HTML images. + +6.7.5 (2024-04-20) + - Update GitHub actions + - fix: CSV-2024-22640 (#712) + +6.7.4 (2024-03-24) + - Upgrade tcpdf tag encryption algorithm. + - Fix regression issue #699. + - Fix security issue. + - [BREAKING CHANGE] The tcpdf HTML tag syntax has changed, see example_049.php. + - New K_ALLOWED_TCPDF_TAGS configuration constant to set the allowed methods for the tcdpf HTML tag. + - Raised minimum PHP version to PHP 5.5.0. + +6.6.5 (2023-09-02) + - Fix corrupted file. + - Fix GitHub automation tests. + - Fix SPDX license ID (#591) + - Fix warning "array offset on value of type null" (#620) + - Improve the README about the status of this library (#589) + - Fix deprecation warning with PHP 8.1 (#614) + - Fixes for PHP 8.2 in tcpdf_fonts.php (#632) + - Fix some php 8+ edge cases (#630) + - Fix composite glyph output (#581) + - Fix "access array offset on value of type bool" with PDF/A (#583) + - Fix non-numeric value warning (#627) + - Fix issues with S25 barcode (#611) + - Fix return type annotations (#613) + - Fix some inconsistencies in type hints (#598) + +6.6.2 (2022-12-17) + - Ensure pregSplit return type is always array. + - Add ability to run tests on various operating systems (#566) + - Avoid a deprecated error from PHP8.1 (#573) + +6.6.1 (2022-12-12) + - Add PHPStan and fix level 1 errors (#307) + +6.6.0 (2022-12-06) + - Multi-byte character support for filename during output (#561). (#562) + - Fix garbage collection (#509) + - FIX: PDF417 corrupt output problem, solution set bcmath scale parameter to zero (#534) + - Fix TypeError: count() in PHP8 (#556) + - Fix-getHTMLFontUnits (#547) + - Improved embedded image in HTML allowing src="data:..." format (#552) + - Fix image abscissa when in RTL (#510) + - fix: php 8.1 notices (#548) + - Optimize PNG files (#563) + - Update documentation for a known issue. (#569) + - Fix for PHP 8.1 (#571) + +6.5.0 (2022-08-12) + - encodeUrlQuery takes into account the port (#493) + - Fixing undefined offset error in writeHTML() when last DOM element ha… + - correct some type hints (#495) + - fix: php 8.1 notices (#481) + - Fixed: null check for PHP 8.1 (#476) + - Fix Infinite Loop in Multicell with Auto Page Breaks Off (#473) + - GetCssBorderStyle Has Problem When !important Is Specified (#467) + - Support Apache 2.4 directives in htaccess file (#530) + - Remove examples from dist package (#542) + +6.4.4 (2021-12-31) + - PHP 8.1 fixes + +6.4.3 (2021-12-28) + - Fix MultiCell PHPDoc typehint (#407) + - Fix type hint for \TCPDF_STATIC::_freadint (#414) + - Footer and Header font phpdoc fixes + constructor $pdfa phpdoc fix + setHeaderData lw param fix (#402) + - Fix text-annotation state options (#412) + - Fix - Named links have been broken. This fixes. (#415) + - Fixed type in comment for $lw header image logo width in mm + - Change Set to set. Fixes #419 (#421) + - Fix failing tests and failing tests not marking exit code as 1 (#426) + - Fix phpdoc and prefer null as default value (#444) + - Run on PHP 8.1 normally and add nightly PHP as allowed to fail (#452) + - Fix AES128 encryption if the OpenSSL extension is installed (#453) + - Explicitly cast values to int for imagesetpixel (#460) + - Fix cell_height_ratio type (#405) + - Leave &NBSP; lowercase when using text-transform (#403) + +6.4.2 (2021-07-20) + - Fix PHP 8.1 type error with TCPDF_STATIC::pregSplit on preg_split + - Fix a PHP array offset error + - Fixed phpdoc blocks + - Drop a PHP 4 polyfill and add a .gitattributes file + - Added a test-suite + - Removed pointless assignments + - Fix docblock spelling error + - Update version info + - Fix color being filled to type 0 with PHP 8 + - Fix warnings for undefined tags for $lineStyle + - Normalized composer.json + - Allowed transparency in PDF/A-2 and PDF/A-3 + - Add a TCPDF composer example + - Fixed implicit conversion from float to int for PHP 8.1 + - Removed status.txt from font directories, because of filesize + - Fixed type hints + - Removed "U" modifier from regexes + +6.4.1 (2021-03-27) + - Update tcpdf version (no code changes) + +6.4.0 (2021-03-27) + - allow styles on
tags + - check if file exists before calling unlink + - Fix image file type for urls with query params + - Fix SVGPath should accept 1.19.30 (equiv 1.19,.30) compacted values list + - Fix Second parameter of TCPDF::cell() must be a number + - PHP 8.0 function signature fixes + - Fix vulnerability to roman numeral bombs + - Optimized a regular expression + - Cache file get contents calls + - Remove mb_internal encoding handling + +6.3.5 (2020-02-14) + - Fixed curly braces in pdf417 + - Fixed a syntax error issue when accessing an index of a casted variable + +6.3.4 (2020-02-12) + - Check if imagekeys exist + - Unlink only images in cache + +6.3.3 (2020-02-12) + - Fixed PHP 7.4 - cannot use array offset on integers + - Fixed PDF/A-3B validation issue caused by missing pdfaSchema:property. + - Removed backup changelog files from repo + - Prevents the deletion of non-existent files in /tmp + - Prevent crash in case of no list access in cache path + - Check existence of file before delete it + - Fixed erase users pictures + - Fixed problem with $imagekeys undefined or unlinked + - Fix SVGPath elliptical arc with rx/ry=0 + z should return to initial point + - Fixed PHP 7.4 errors + - handle integers for pages + - Fixed background image doesn't work in RTL + - Fixed PDF/A validity + - Fixed datamatrix.php for PHP 7.4 + - Fixed deprecated PHP features + +6.3.2 (2019-09-20) + - Update ICC profile + +6.3.1 (2019-09-20) + - Fix reported version + - Fix Undefined property: GLPIPDF::$imagekeys + +6.3.0 (2019-09-19) + - fix SpotColor handling in HTML + - Add an additional empty test to prevent error in PHP 7.2 + - Fix the documentation how to calculate the cell height + - Drop duplicated array indices + - Fix TCPDF_STATIC::fileGetContents() + - Introduce other version of pdfA (2 and 3) + - Add UF and AFRelationship missing + - Fix performance issue of cloned instances + - Change glob to readdir which performs better + - URI in PDF can result in E_NOTICE + - Fix a warning for PHP 7.4 + - Fixed gradient offsets for percentage-based stops. + - Fixed file_get_contents return value should also be checked for a non-empty string + - Fix Array and string offset access syntax with curly braces is deprecated + - Fix PHP Warning: chr() expects parameter 1 to be int + - Add a VERSION file + +6.2.26 (2018-10-16) + - Update sRGB.icc with the one from the Debian package icc-profiles-free + - Fix unsupported operand types error when codepoints arrays are merged + +6.2.25 (2018-09-23) - Fix support for image URLs. 6.2.24 - Support remote urls when checking if file exists. -6.2.23 +6.2.23 (2018-09-22) - Simplify file_exists function. -6.2.22 +6.2.22 (2018-09-14) + - Fixes on `include/tcpdf_images.php`, `include/tcpdf_static.php` and `tcpdf.php` about file handling + +6.2.21 (2018-09-14) + - _no code changes_ + +6.2.20 (2018-09-14) - Fix for security vulnerability: Using the phar:// wrapper it was possible to trigger the unserialization of user provided data. -6.2.19 +6.2.19 (2018-09-14) - Merge various fixes for PHP 7.3 compatibility and security. 6.2.13 (2016-06-10) diff --git a/tools/tcpdf/LICENSE.TXT b/tools/tcpdf/LICENSE.TXT index 49147d01a..ec7968a7e 100644 --- a/tools/tcpdf/LICENSE.TXT +++ b/tools/tcpdf/LICENSE.TXT @@ -7,7 +7,7 @@ published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - 2002-2019 Nicola Asuni - Tecnick.com LTD + 2002-2024 Nicola Asuni - Tecnick.com LTD ********************************************************************** ********************************************************************** diff --git a/tools/tcpdf/README.md b/tools/tcpdf/README.md index db0149f69..f59f66339 100644 --- a/tools/tcpdf/README.md +++ b/tools/tcpdf/README.md @@ -6,15 +6,14 @@ * **category** Library * **author** Nicola Asuni -* **copyright** 2002-2020 Nicola Asuni - Tecnick.com LTD +* **copyright** 2002-2024 Nicola Asuni - Tecnick.com LTD * **license** http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) * **link** http://www.tcpdf.org * **source** https://github.com/tecnickcom/TCPDF -## IMPORTANT -A new version of this library is under development at https://github.com/tecnickcom/tc-lib-pdf and as a consequence this version will not receive any additional development or support. -This version should be considered obsolete, new projects should use the new version as soon it will become stable. +## NOTE +A new version of this library is under development at https://github.com/tecnickcom/tc-lib-pdf and as a consequence this library is in support only mode. diff --git a/tools/tcpdf/VERSION b/tools/tcpdf/VERSION index b98d1d3fa..eed6de4bb 100644 --- a/tools/tcpdf/VERSION +++ b/tools/tcpdf/VERSION @@ -1 +1 @@ -6.3.5 +6.7.8 diff --git a/tools/tcpdf/config/index.php b/tools/tcpdf/config/index.php deleted file mode 100644 index d295cc517..000000000 --- a/tools/tcpdf/config/index.php +++ /dev/null @@ -1,35 +0,0 @@ - -* @copyright 2007-2017 PrestaShop SA -* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) -* International Registered Trademark & Property of PrestaShop SA -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/tcpdf/config/tcpdf_config.php b/tools/tcpdf/config/tcpdf_config.php index 92317b121..9888a6778 100644 --- a/tools/tcpdf/config/tcpdf_config.php +++ b/tools/tcpdf/config/tcpdf_config.php @@ -212,6 +212,14 @@ define('K_THAI_TOPCHARS', true); */ define('K_TCPDF_CALLS_IN_HTML', false); +/** + * List of TCPDF methods that are allowed to be called using HTML syntax. + * Note: each method name must end with surrounded with | (pipe) character. + * The constant K_TCPDF_CALLS_IN_HTML must be set to true. + * IMPORTANT: For security reason, disable this feature if you are allowing user HTML content. + */ +define('K_ALLOWED_TCPDF_TAGS', ''); + /** * If true and PHP version is greater than 5, then the Error() method throw new exception instead of terminating the execution. */ diff --git a/tools/tcpdf/examples/barcodes/example_1d_html.php b/tools/tcpdf/examples/barcodes/example_1d_html.php new file mode 100644 index 000000000..6d3233bd6 --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_1d_html.php @@ -0,0 +1,57 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_1d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_1d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.000 + * @group barcode + * @group 1d + * @group html + * @group comparable + */ + +// include 1D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_1d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDFBarcode('http://www.tcpdf.org', 'C128'); + +// output the barcode as HTML object +echo $barcodeobj->getBarcodeHTML(2, 30, 'black'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_1d_png.php b/tools/tcpdf/examples/barcodes/example_1d_png.php new file mode 100644 index 000000000..02ed1660e --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_1d_png.php @@ -0,0 +1,56 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_1d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_1d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.000 + * @group barcode + * @group 1d + * @group png + */ + +// include 1D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_1d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDFBarcode('http://www.tcpdf.org', 'C128'); + +// output the barcode as PNG image +$barcodeobj->getBarcodePNG(2, 30, array(0,0,0)); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_1d_svg.php b/tools/tcpdf/examples/barcodes/example_1d_svg.php new file mode 100644 index 000000000..5e5ccfc35 --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_1d_svg.php @@ -0,0 +1,57 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_1d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_1d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.000 + * @group barcode + * @group 1d + * @group svg + * @group comparable + */ + +// include 1D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_1d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDFBarcode('http://www.tcpdf.org', 'C128'); + +// output the barcode as SVG image +$barcodeobj->getBarcodeSVG(2, 30, 'black'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_1d_svgi.php b/tools/tcpdf/examples/barcodes/example_1d_svgi.php new file mode 100644 index 000000000..8c65b669b --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_1d_svgi.php @@ -0,0 +1,57 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_1d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_1d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.000 + * @group barcode + * @group 1d + * @group svg + * @group comparable + */ + +// include 1D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_1d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDFBarcode('http://www.tcpdf.org', 'C128'); + +// output the barcode as SVG inline code +echo $barcodeobj->getBarcodeSVGcode(2, 40, 'black'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_2d_datamatrix_html.php b/tools/tcpdf/examples/barcodes/example_2d_datamatrix_html.php new file mode 100644 index 000000000..e0d200cc7 --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_2d_datamatrix_html.php @@ -0,0 +1,57 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_2d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_2d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.009 + * @group barcode + * @group datamatrix + * @group html + * @group comparable + */ + +// include 2D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_2d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDF2DBarcode('http://www.tcpdf.org', 'DATAMATRIX'); + +// output the barcode as HTML object +echo $barcodeobj->getBarcodeHTML(6, 6, 'black'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_2d_datamatrix_png.php b/tools/tcpdf/examples/barcodes/example_2d_datamatrix_png.php new file mode 100644 index 000000000..35d344dac --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_2d_datamatrix_png.php @@ -0,0 +1,56 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_2d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_2d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.009 + * @group barcode + * @group datamatrix + * @group png + */ + +// include 2D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_2d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDF2DBarcode('http://www.tcpdf.org', 'DATAMATRIX'); + +// output the barcode as PNG image +$barcodeobj->getBarcodePNG(6, 6, array(0,0,0)); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_2d_datamatrix_svg.php b/tools/tcpdf/examples/barcodes/example_2d_datamatrix_svg.php new file mode 100644 index 000000000..10d0aa36a --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_2d_datamatrix_svg.php @@ -0,0 +1,57 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_2d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_2d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.009 + * @group barcode + * @group datamatrix + * @group svg + * @group comparable + */ + +// include 2D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_2d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDF2DBarcode('http://www.tcpdf.org', 'DATAMATRIX'); + +// output the barcode as SVG image +$barcodeobj->getBarcodeSVG(6, 6, 'black'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_2d_datamatrix_svgi.php b/tools/tcpdf/examples/barcodes/example_2d_datamatrix_svgi.php new file mode 100644 index 000000000..42627006f --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_2d_datamatrix_svgi.php @@ -0,0 +1,57 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_2d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_2d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.009 + * @group barcode + * @group datamatrix + * @group svg + * @group comparable + */ + +// include 2D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_2d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDF2DBarcode('http://www.tcpdf.org', 'DATAMATRIX'); + +// output the barcode as SVG inline code +echo $barcodeobj->getBarcodeSVGcode(6, 6, 'black'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_2d_pdf417_html.php b/tools/tcpdf/examples/barcodes/example_2d_pdf417_html.php new file mode 100644 index 000000000..3d8de3102 --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_2d_pdf417_html.php @@ -0,0 +1,57 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_2d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_2d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.009 + * @group barcode + * @group pdf417 + * @group html + * @group comparable + */ + +// include 2D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_2d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDF2DBarcode('http://www.tcpdf.org', 'PDF417'); + +// output the barcode as HTML object +echo $barcodeobj->getBarcodeHTML(4, 4, 'black'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_2d_pdf417_png.php b/tools/tcpdf/examples/barcodes/example_2d_pdf417_png.php new file mode 100644 index 000000000..b7c95855a --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_2d_pdf417_png.php @@ -0,0 +1,56 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_2d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_2d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.009 + * @group barcode + * @group pdf417 + * @group png + */ + +// include 2D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_2d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDF2DBarcode('http://www.tcpdf.org', 'PDF417'); + +// output the barcode as PNG image +$barcodeobj->getBarcodePNG(4, 4, array(0,0,0)); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_2d_pdf417_svg.php b/tools/tcpdf/examples/barcodes/example_2d_pdf417_svg.php new file mode 100644 index 000000000..9017e5bcb --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_2d_pdf417_svg.php @@ -0,0 +1,57 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_2d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_2d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.009 + * @group barcode + * @group pdf417 + * @group svg + * @group comparable + */ + +// include 2D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_2d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDF2DBarcode('http://www.tcpdf.org', 'PDF417'); + +// output the barcode as SVG image +$barcodeobj->getBarcodeSVG(4, 4, 'black'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_2d_pdf417_svgi.php b/tools/tcpdf/examples/barcodes/example_2d_pdf417_svgi.php new file mode 100644 index 000000000..2075da740 --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_2d_pdf417_svgi.php @@ -0,0 +1,57 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_2d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_2d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.009 + * @group barcode + * @group pdf417 + * @group svg + * @group comparable + */ + +// include 2D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_2d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDF2DBarcode('http://www.tcpdf.org', 'PDF417'); + +// output the barcode as SVG inline code +echo $barcodeobj->getBarcodeSVGcode(4, 4, 'black'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_2d_qrcode_html.php b/tools/tcpdf/examples/barcodes/example_2d_qrcode_html.php new file mode 100644 index 000000000..7c05f00f2 --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_2d_qrcode_html.php @@ -0,0 +1,56 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_2d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_2d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.009 + * @group barcode + * @group qrcode + * @group html + */ + +// include 2D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_2d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDF2DBarcode('http://www.tcpdf.org', 'QRCODE,H'); + +// output the barcode as HTML object +echo $barcodeobj->getBarcodeHTML(6, 6, 'black'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_2d_qrcode_png.php b/tools/tcpdf/examples/barcodes/example_2d_qrcode_png.php new file mode 100644 index 000000000..75daa7c07 --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_2d_qrcode_png.php @@ -0,0 +1,56 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_2d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_2d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.009 + * @group barcode + * @group qrcode + * @group png + */ + +// include 2D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_2d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDF2DBarcode('http://www.tcpdf.org', 'QRCODE,H'); + +// output the barcode as PNG image +$barcodeobj->getBarcodePNG(6, 6, array(0,0,0)); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_2d_qrcode_svg.php b/tools/tcpdf/examples/barcodes/example_2d_qrcode_svg.php new file mode 100644 index 000000000..c104ca63f --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_2d_qrcode_svg.php @@ -0,0 +1,56 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_2d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_2d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.009 + * @group barcode + * @group qrcode + * @group svg + */ + +// include 2D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_2d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDF2DBarcode('http://www.tcpdf.org', 'QRCODE,H'); + +// output the barcode as SVG image +$barcodeobj->getBarcodeSVG(6, 6, 'black'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/example_2d_qrcode_svgi.php b/tools/tcpdf/examples/barcodes/example_2d_qrcode_svgi.php new file mode 100644 index 000000000..f31a10083 --- /dev/null +++ b/tools/tcpdf/examples/barcodes/example_2d_qrcode_svgi.php @@ -0,0 +1,56 @@ +. +// +// See LICENSE.TXT file for more information. +// ------------------------------------------------------------------- +// +// Description : Example for tcpdf_barcodes_2d.php class +// +//============================================================+ + +/** + * @file + * Example for tcpdf_barcodes_2d.php class + * @package com.tecnick.tcpdf + * @author Nicola Asuni + * @version 1.0.009 + * @group barcode + * @group qrcode + * @group svg + */ + +// include 2D barcode class (search for installation path) +require_once(dirname(__FILE__).'/tcpdf_barcodes_2d_include.php'); + +// set the barcode content and type +$barcodeobj = new TCPDF2DBarcode('http://www.tcpdf.org', 'QRCODE,H'); + +// output the barcode as SVG inline code +echo $barcodeobj->getBarcodeSVGcode(6, 6, 'black'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/barcodes/tcpdf_barcodes_1d_include.php b/tools/tcpdf/examples/barcodes/tcpdf_barcodes_1d_include.php new file mode 100644 index 000000000..0add5ec6f --- /dev/null +++ b/tools/tcpdf/examples/barcodes/tcpdf_barcodes_1d_include.php @@ -0,0 +1,46 @@ +. +// +// See LICENSE.TXT file for more information. +//============================================================+ + +/** + * Example of alternative configuration file for TCPDF. + * @author Nicola Asuni + * @package com.tecnick.tcpdf + * @version 4.9.005 + * @since 2004-10-27 + */ + +/** + * Define the following constant to ignore the default configuration file. + */ +define ('K_TCPDF_EXTERNAL_CONFIG', true); + +/** + * Installation path (/var/www/tcpdf/). + * By default it is automatically calculated but you can also set it as a fixed string to improve performances. + */ +//define ('K_PATH_MAIN', ''); + +/** + * URL path to tcpdf installation folder (http://localhost/tcpdf/). + * By default it is automatically set but you can also set it as a fixed string to improve performances. + */ +//define ('K_PATH_URL', ''); + +/** + * Path for PDF fonts. + * By default it is automatically set but you can also set it as a fixed string to improve performances. + */ +//define ('K_PATH_FONTS', K_PATH_MAIN.'fonts/'); + +/** + * Default images directory. + * By default it is automatically set but you can also set it as a fixed string to improve performances. + */ +define ('K_PATH_IMAGES', dirname(__FILE__).'/../images/'); + +/** + * Deafult image logo used be the default Header() method. + * Please set here your own logo or an empty string to disable it. + */ +define ('PDF_HEADER_LOGO', 'tcpdf_logo.jpg'); + +/** + * Header logo image width in user units. + */ +define ('PDF_HEADER_LOGO_WIDTH', 30); + +/** + * Cache directory for temporary files (full path). + */ +define ('K_PATH_CACHE', sys_get_temp_dir().'/'); + +/** + * Generic name for a blank image. + */ +define ('K_BLANK_IMAGE', '_blank.png'); + +/** + * Page format. + */ +define ('PDF_PAGE_FORMAT', 'A4'); + +/** + * Page orientation (P=portrait, L=landscape). + */ +define ('PDF_PAGE_ORIENTATION', 'P'); + +/** + * Document creator. + */ +define ('PDF_CREATOR', 'TCPDF'); + +/** + * Document author. + */ +define ('PDF_AUTHOR', 'TCPDF'); + +/** + * Header title. + */ +define ('PDF_HEADER_TITLE', 'TCPDF Example'); + +/** + * Header description string. + */ +define ('PDF_HEADER_STRING', "by Nicola Asuni - Tecnick.com\nwww.tcpdf.org"); + +/** + * Document unit of measure [pt=point, mm=millimeter, cm=centimeter, in=inch]. + */ +define ('PDF_UNIT', 'mm'); + +/** + * Header margin. + */ +define ('PDF_MARGIN_HEADER', 5); + +/** + * Footer margin. + */ +define ('PDF_MARGIN_FOOTER', 10); + +/** + * Top margin. + */ +define ('PDF_MARGIN_TOP', 27); + +/** + * Bottom margin. + */ +define ('PDF_MARGIN_BOTTOM', 25); + +/** + * Left margin. + */ +define ('PDF_MARGIN_LEFT', 15); + +/** + * Right margin. + */ +define ('PDF_MARGIN_RIGHT', 15); + +/** + * Default main font name. + */ +define ('PDF_FONT_NAME_MAIN', 'helvetica'); + +/** + * Default main font size. + */ +define ('PDF_FONT_SIZE_MAIN', 10); + +/** + * Default data font name. + */ +define ('PDF_FONT_NAME_DATA', 'helvetica'); + +/** + * Default data font size. + */ +define ('PDF_FONT_SIZE_DATA', 8); + +/** + * Default monospaced font name. + */ +define ('PDF_FONT_MONOSPACED', 'courier'); + +/** + * Ratio used to adjust the conversion of pixels to user units. + */ +define ('PDF_IMAGE_SCALE_RATIO', 1.25); + +/** + * Magnification factor for titles. + */ +define('HEAD_MAGNIFICATION', 1.1); + +/** + * Height of cell respect font height. + */ +define('K_CELL_HEIGHT_RATIO', 1.25); + +/** + * Title magnification respect main font size. + */ +define('K_TITLE_MAGNIFICATION', 1.3); + +/** + * Reduction factor for small font. + */ +define('K_SMALL_RATIO', 2/3); + +/** + * Set to true to enable the special procedure used to avoid the overlappind of symbols on Thai language. + */ +define('K_THAI_TOPCHARS', true); + +/** + * If true allows to call TCPDF methods using HTML syntax + * IMPORTANT: For security reason, disable this feature if you are printing user HTML content. + */ +define('K_TCPDF_CALLS_IN_HTML', true); + +/** + * List of TCPDF methods that are allowed to be called using HTML syntax. + * Note: each method name must end with surrounded with | (pipe) character. + * The constant K_TCPDF_CALLS_IN_HTML must be set to true. + * IMPORTANT: For security reason, disable this feature if you are allowing user HTML content. + */ +define('K_ALLOWED_TCPDF_TAGS', '|AddPage|Rect|SetDrawColor|write1DBarcode|'); + +/** + * If true and PHP version is greater than 5, then the Error() method throw new exception instead of terminating the execution. + */ +define('K_TCPDF_THROW_EXCEPTION_ERROR', false); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/data/cert/tcpdf.crt b/tools/tcpdf/examples/data/cert/tcpdf.crt new file mode 100644 index 000000000..f0491391c --- /dev/null +++ b/tools/tcpdf/examples/data/cert/tcpdf.crt @@ -0,0 +1,40 @@ +Bag Attributes + localKeyID: 7B AB 1B 7A BE 4C 85 C0 1A A6 DC 59 3F 79 48 C3 93 38 68 9C +subject=/CN=TCPDF DEMO/O=TCPDF/OU=DEMO/emailAddress=you@example.com/C=IT +issuer=/CN=TCPDF DEMO/O=TCPDF/OU=DEMO/emailAddress=you@example.com/C=IT +-----BEGIN CERTIFICATE----- +MIIC1TCCAj6gAwIBAgIKkehOL/XGkB5cjjANBgkqhkiG9w0BAQUFADBhMRMwEQYD +VQQDEwpUQ1BERiBERU1PMQ4wDAYDVQQKEwVUQ1BERjENMAsGA1UECxMEREVNTzEe +MBwGCSqGSIb3DQEJARYPeW91QGV4YW1wbGUuY29tMQswCQYDVQQGEwJJVDAeFw0w +OTA4MjExMjU0NDhaFw0xNDA4MjExMjU0NDhaMGExEzARBgNVBAMTClRDUERGIERF +TU8xDjAMBgNVBAoTBVRDUERGMQ0wCwYDVQQLEwRERU1PMR4wHAYJKoZIhvcNAQkB +Fg95b3VAZXhhbXBsZS5jb20xCzAJBgNVBAYTAklUMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDAqIL0uGKmTR98Lxx2vEEE1OGKkMXFo0JViitALe7Onhxxqx0H +XMUDKF5mvEVu1rcvh7/oAnAfrCuEpL/up3u1mQCgBE7WXBnFFE/AE3jCksh9OkS0 +Z0Xj9woN5bzxRDsGoPiOu/4xzk5qSEXt8jf2Ep90QuNkqLIRT4swAzpDbwIDAQAB +o4GTMIGQMDcGA1UdEgQwMC6gEQYDVQQDDApUQ1BERiBERU1PoAwGA1UECgwFVENQ +REagCwYDVQQLDARERU1PMDcGA1UdEQQwMC6gEQYDVQQDDApUQ1BERiBERU1PoAwG +A1UECgwFVENQREagCwYDVQQLDARERU1PMA8GCSqGSIb3LwEBCgQCBQAwCwYDVR0P +BAQDAgSQMA0GCSqGSIb3DQEBBQUAA4GBAEhTQfqX3ZNdHmpTLDbIj22RHXii2roE +OavCbu9WsHoWpva0qSd+yIoD594VHvYAd29sfzDfiN+7W0aiZfDhq5jpaSQMVlN8 +RGYMupbHY/+a9Gz1wqxnR84mlTtIkZVRYAhsfPwy6M1BEjdMqfdh9h40JIdkdjtb +8faTCfXPePWQ +-----END CERTIFICATE----- +Bag Attributes + localKeyID: 7B AB 1B 7A BE 4C 85 C0 1A A6 DC 59 3F 79 48 C3 93 38 68 9C +Key Attributes: +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDAqIL0uGKmTR98Lxx2vEEE1OGKkMXFo0JViitALe7Onhxxqx0H +XMUDKF5mvEVu1rcvh7/oAnAfrCuEpL/up3u1mQCgBE7WXBnFFE/AE3jCksh9OkS0 +Z0Xj9woN5bzxRDsGoPiOu/4xzk5qSEXt8jf2Ep90QuNkqLIRT4swAzpDbwIDAQAB +AoGAXc+wNMmz/5Z+RlIKYia44klmqbplEx+0JULqXI4BQsrqvs67i+I4bJkznoL+ +rEIRYSuQ3sCRKFsFtckjTGpxadnxkB+uwGKc6pZChv99BFX6HFR4hgBlT/BBRAQA +hMDlM2JIRr4S4SMVXR7MHwGMUf9mUeanGLR3ZWtU3aXJrIECQQD7OaYUVYNEEnM9 +uXyjm22CuHyqyEf5gb13sK0uQty67547yJTMUQZd/sQc9KGwhzBbhrob2LO2jAhh +S+f+NSRnAkEAxFHm3fMI5RgXmswxlGm4QW07a/Ueo7ZJG6xjTkFXluJhd+XHswRD +dQIO3zG9nGjNUoeMrPhXhPvKqFc2F9RDuQJAQBEGin74N77gxqfr4ik79y8nE8J5 +oGZ2s/RJZdfFRKLg3mwbjjNHhWb4Ck5UgZkoOt8TzRApXG8/n9hktE5HFwJBALur +M5AueO1Pl5kB489lNJ9OxUQRYUXMxpxuscuoCQwSwmv0O2+0/qtG2WKhUQnI4aYo +L+FV0YwtivBb1jj3T/kCQQDIWOxq8eRowdaMzvJpRUHFgMcf1AVZExKyrugwYOWd +KNsDxC4KaQOsPt8iT/Ulo4g/MJC0HolCOhWibKmR9Ayl +-----END RSA PRIVATE KEY----- diff --git a/tools/tcpdf/examples/data/cert/tcpdf.fdf b/tools/tcpdf/examples/data/cert/tcpdf.fdf new file mode 100644 index 0000000000000000000000000000000000000000..a8f7c35d9af83d2579adafbe8d2745daa30dfd3f GIT binary patch literal 1286 zcmY#&b8*u()HC8$ef0SJWnL~r1p|frq%2+=8-1XRf)S7#r0=WYVr67tU}<1sWNK(+ zVqj{ZZD6EsV4$w4A5vM6s_&dwl9-d9ZfD1vnwJ974blcRB_P0C!5Cx;LKeh@%DVa{ zX69&A=9fC8RwU*YU-uEiZ?;rfP&Z2LK)A;_B7r3kke!oRl4_NlT2$g%0n&r%SOWtqBSU91S93#0P5mGRLt{e&OJj)R zfezFUQ!unNGcz$2Stmap^>SHiA5BUZ)k$Vr=CM% zc=0=>aXxA&FtRc*H}*0ZG&u@?wgf?)m6q&9>l2-|l~g=lrrfT;F~&|0XoQ#OZO$icNz4 z-3H87&iPEtj0}v68z&nyPB1VB2BNGGi-CdO0!TdZAji`JXe{wSVrc;=ieh+KxOu>l z1ko%=ie|W0erW9KGcv~Hu`mIX3dn3(eijyHCYA}PK?qDp%)qeo2zLB6{qE#gxvXFv zvlIQf6J;wF-P*-sx%yDv`>+jFV#~g5S*c!kqKo)Yp8S8-mz=MM)}*_iQ=4k-F>z{O0!L2GAEOs%9fiz&R(?FEV{qfsm&adYyzE04L)pyR%D@jZ)LCJsMoDa#P`pJ37QixnsQIwj-%VnTo z3MAk_!OYau*i-=|0R@I;3SgE(9zx6lQ_K*HIwK1Mgx-=OU}=(C#LERNy@E5VQWZ?~ kgYxrB6hMU zY-rcU0s;sCfPw=!#BpZA(3DXgvNT6SMx2c3M^p9_<~*qj&~k|Wio#7(scRd zVB;~P(%~|g!$#H)Uj>}ly*mK-K*NcRU+dxygiF7$BDFu;YqjVO#_{qT;h+#I>a(HG z6~@vJ%56(B0~rm^94uG!F&Q6%9$*+cPTn~18aH}n`p;SwVUc3}cGnJV33D`@$5Df5 zka5G^;jy@bF*5dt7yj?!On2m{6(lU}`+Ngz(u>-st&u3q&_N{T-$B(t9@HplX>tLm z<+%6V-nXIed*8 zvh$I?cs-H$tTFYyLYOK&N@y0$j3(wM=r+RHOFm_l_Ew3J zjZ|cTFZc?kMLbIRq9#Je0!uHg$!6L_|JSTh4SBDC^kz-4Q$rl0exLwuv7)I*(A$u( z4~P;V(@gR1lQvQ9WUL5F(7#Oi)Yh-}TXhqUaHvL^;{PKZ_!c^5TIaYzP~~Y~ol!Ix zIU5LwA?E0d=I<-Og-X;m1K5(@AtP)n6jQ1{Q2ko=_)Bd{1(bAXe>Coeda=}lih)j$ z2>zQNzJ;fmRdBanq`^ZJV5@Ra+72~oPcmiLf=NHQP1lj<)-k#CXYR9X=4kR3k!;Y8h(}v0#D@^oeB!oK*4q{yIW*$U z&LNQUbi3jQQ0AALA`*I zEfwAUX0Q~1Fi>8l{3I2b+YV;2v~q$Ht)BfYyxTJvSQ3SoAxX}JT3QHXqu~l@W;f&? zvySO921ne7{yT!I)^oWbM&abJwv8?L zM@*J>12l+CQ;QV!Y|w=vINzLD8!z3$e&b>m;bngGpZYK)8EI}digPEz z`_pvC6Afky&Q2vvrHY~v?ZeFbT?m+rp=p=tij1id`L#ceB43YATh$S6RuVfPIPHzQGmAuP1O9==9r!_9t z(XXtxXOZ1gWS49JT5NEHFG{7{?SuzHx8kV3=tHXcRlJ=U+G!T)+ z?jrd2IhsLxK1dcI7Bz#699SwDG5!;?5@oG>vkAutIB1uG5% r0vZJX1QaJKFP)8IPAOWT%X#|+d4hgQWoQHlY+QLorem ipsum dolor sit amet, consectetur adipiscing elit. In sed imperdiet lectus. Phasellus quis velit velit, non condimentum quam. Sed neque urna, ultrices ac volutpat vel, laoreet vitae augue. Sed vel velit erat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras eget velit nulla, eu sagittis elit. Nunc ac arcu est, in lobortis tellus. Praesent condimentum rhoncus sodales. In hac habitasse platea dictumst. Proin porta eros pharetra enim tincidunt dignissim nec vel dolor. Cras sapien elit, ornare ac dignissim eu, ultricies ac eros. Maecenas augue magna, ultrices a congue in, mollis eu nulla. Nunc venenatis massa at est eleifend faucibus. Vivamus sed risus lectus, nec interdum nunc.

+ + + +

Fusce et felis vitae diam lobortis sollicitudin. Aenean tincidunt accumsan nisi, id vehicula quam laoreet elementum. Phasellus egestas interdum erat, et viverra ipsum ultricies ac. Praesent sagittis augue at augue volutpat eleifend. Cras nec orci neque. Mauris bibendum posuere blandit. Donec feugiat mollis dui sit amet pellentesque. Sed a enim justo. Donec tincidunt, nisl eget elementum aliquam, odio ipsum ultrices quam, eu porttitor ligula urna at lorem. Donec varius, eros et convallis laoreet, ligula tellus consequat felis, ut ornare metus tellus sodales velit. Duis sed diam ante. Ut rutrum malesuada massa, vitae consectetur ipsum rhoncus sed. Suspendisse potenti. Pellentesque a congue massa.

+ +

Integer non sem eget neque mattis accumsan. Maecenas eu nisl mauris, sit amet interdum ipsum. In pharetra erat vel lectus venenatis elementum. Nulla non elit ligula, sit amet mollis urna. Morbi ut gravida est. Mauris tincidunt sem et turpis molestie malesuada. Curabitur vel nulla risus, sed mollis erat. Suspendisse vehicula accumsan purus nec varius. Donec fermentum lorem id felis sodales dictum. Quisque et dolor ipsum. Nam luctus consectetur dui vitae fermentum. Curabitur sodales consequat augue, id ultricies augue tempor ac. Aliquam ac magna id ipsum vehicula bibendum. Sed elementum congue tristique. Phasellus vel lorem eu lectus porta sodales. Etiam neque tortor, sagittis id pharetra quis, laoreet vel arcu.

+ +

Cras quam mi, ornare laoreet laoreet vel, vehicula at lacus. Maecenas a lacus accumsan augue convallis sagittis sed quis odio. Morbi sit amet turpis diam, dictum convallis urna. Cras eget interdum augue. Cras eu nisi sit amet dolor faucibus porttitor. Suspendisse potenti. Nunc vitae dolor risus, at cursus libero. Suspendisse bibendum tellus non nibh hendrerit tristique. Mauris eget orci elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam porta libero non ante laoreet semper. Proin volutpat sodales mi, ac fermentum erat sagittis in. Vivamus at viverra felis. Ut pretium facilisis ante et pharetra.

+ +

Nulla facilisi. Cras varius quam eget libero aliquam vitae tincidunt leo rutrum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque a nisl massa, quis pretium urna. Proin vel porttitor tortor. Cras rhoncus congue velit in bibendum. Donec pharetra semper augue id lacinia. Quisque magna quam, hendrerit eu aliquam et, pellentesque ut tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Maecenas nulla quam, rutrum eu feugiat at, elementum eu libero. Maecenas ullamcorper leo et turpis rutrum ac laoreet eros faucibus. Phasellus condimentum lorem quis neque imperdiet quis molestie enim iaculis. Phasellus risus est, vestibulum ut convallis ultrices, dignissim nec erat. Etiam congue lobortis laoreet. Nulla ut neque sed velit dapibus semper. Quisque nec dolor id nibh eleifend iaculis. Vivamus vitae fermentum odio. Etiam malesuada quam in nulla aliquam sed convallis dui feugiat.

+ +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. In sed imperdiet lectus. Phasellus quis velit velit, non condimentum quam. Sed neque urna, ultrices ac volutpat vel, laoreet vitae augue. Sed vel velit erat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras eget velit nulla, eu sagittis elit. Nunc ac arcu est, in lobortis tellus. Praesent condimentum rhoncus sodales. In hac habitasse platea dictumst. Proin porta eros pharetra enim tincidunt dignissim nec vel dolor. Cras sapien elit, ornare ac dignissim eu, ultricies ac eros. Maecenas augue magna, ultrices a congue in, mollis eu nulla. Nunc venenatis massa at est eleifend faucibus. Vivamus sed risus lectus, nec interdum nunc.

+ + + +

Fusce et felis vitae diam lobortis sollicitudin. Aenean tincidunt accumsan nisi, id vehicula quam laoreet elementum. Phasellus egestas interdum erat, et viverra ipsum ultricies ac. Praesent sagittis augue at augue volutpat eleifend. Cras nec orci neque. Mauris bibendum posuere blandit. Donec feugiat mollis dui sit amet pellentesque. Sed a enim justo. Donec tincidunt, nisl eget elementum aliquam, odio ipsum ultrices quam, eu porttitor ligula urna at lorem. Donec varius, eros et convallis laoreet, ligula tellus consequat felis, ut ornare metus tellus sodales velit. Duis sed diam ante. Ut rutrum malesuada massa, vitae consectetur ipsum rhoncus sed. Suspendisse potenti. Pellentesque a congue massa.

+ +

Integer non sem eget neque mattis accumsan. Maecenas eu nisl mauris, sit amet interdum ipsum. In pharetra erat vel lectus venenatis elementum. Nulla non elit ligula, sit amet mollis urna. Morbi ut gravida est. Mauris tincidunt sem et turpis molestie malesuada. Curabitur vel nulla risus, sed mollis erat. Suspendisse vehicula accumsan purus nec varius. Donec fermentum lorem id felis sodales dictum. Quisque et dolor ipsum. Nam luctus consectetur dui vitae fermentum. Curabitur sodales consequat augue, id ultricies augue tempor ac. Aliquam ac magna id ipsum vehicula bibendum. Sed elementum congue tristique. Phasellus vel lorem eu lectus porta sodales. Etiam neque tortor, sagittis id pharetra quis, laoreet vel arcu.

+ +

Cras quam mi, ornare laoreet laoreet vel, vehicula at lacus. Maecenas a lacus accumsan augue convallis sagittis sed quis odio. Morbi sit amet turpis diam, dictum convallis urna. Cras eget interdum augue. Cras eu nisi sit amet dolor faucibus porttitor. Suspendisse potenti. Nunc vitae dolor risus, at cursus libero. Suspendisse bibendum tellus non nibh hendrerit tristique. Mauris eget orci elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam porta libero non ante laoreet semper. Proin volutpat sodales mi, ac fermentum erat sagittis in. Vivamus at viverra felis. Ut pretium facilisis ante et pharetra.

+ +

Nulla facilisi. Cras varius quam eget libero aliquam vitae tincidunt leo rutrum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque a nisl massa, quis pretium urna. Proin vel porttitor tortor. Cras rhoncus congue velit in bibendum. Donec pharetra semper augue id lacinia. Quisque magna quam, hendrerit eu aliquam et, pellentesque ut tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Maecenas nulla quam, rutrum eu feugiat at, elementum eu libero. Maecenas ullamcorper leo et turpis rutrum ac laoreet eros faucibus. Phasellus condimentum lorem quis neque imperdiet quis molestie enim iaculis. Phasellus risus est, vestibulum ut convallis ultrices, dignissim nec erat. Etiam congue lobortis laoreet. Nulla ut neque sed velit dapibus semper. Quisque nec dolor id nibh eleifend iaculis. Vivamus vitae fermentum odio. Etiam malesuada quam in nulla aliquam sed convallis dui feugiat.

diff --git a/tools/tcpdf/examples/data/table_data_demo.txt b/tools/tcpdf/examples/data/table_data_demo.txt new file mode 100644 index 000000000..5a48a42e7 --- /dev/null +++ b/tools/tcpdf/examples/data/table_data_demo.txt @@ -0,0 +1,15 @@ +Austria;Vienna;83859;8075 +Belgium;Brussels;30518;10192 +Denmark;Copenhagen;43094;5295 +Finland;Helsinki;304529;5147 +France;Paris;543965;58728 +Germany;Berlin;357022;82057 +Greece;Athens;131625;10511 +Ireland;Dublin;70723;3694 +Italy;Roma;301316;57563 +Luxembourg;Luxembourg;2586;424 +Netherlands;Amsterdam;41526;15654 +Portugal;Lisbon;91906;9957 +Spain;Madrid;504790;39348 +Sweden;Stockholm;410934;8839 +United Kingdom;London;243820;58862 diff --git a/tools/tcpdf/examples/data/utf8test.txt b/tools/tcpdf/examples/data/utf8test.txt new file mode 100644 index 000000000..291d4e735 --- /dev/null +++ b/tools/tcpdf/examples/data/utf8test.txt @@ -0,0 +1,128 @@ +Sentences that contain all letters commonly used in a language +-------------------------------------------------------------- + +This file is UTF-8 encoded. + +Czech (cz) +--------- + + Příšerně žluťoučký kůň úpěl ďábelské ódy. + Hleď, toť přízračný kůň v mátožné póze šíleně úpí. + Zvlášť zákeřný učeň s ďolíčky běží podél zóny úlů. + Loď čeří kýlem tůň obzvlášť v Grónské úžině. + Ó, náhlý déšť již zvířil prach a čilá laň teď běží s houfcem gazel k úkrytům. + +Danish (da) +--------- + + Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen + Wolther spillede på xylofon. + (= Quiz contestants were eating strawbery with cream while Wolther + the circus clown played on xylophone.) + +German (de) +----------- + + Falsches Üben von Xylophonmusik quält jeden größeren Zwerg + (= Wrongful practicing of xylophone music tortures every larger dwarf) + + Zwölf Boxkämpfer jagten Eva quer über den Sylter Deich + (= Twelve boxing fighters hunted Eva across the dike of Sylt) + + Heizölrückstoßabdämpfung + (= fuel oil recoil absorber) + (jqvwxy missing, but all non-ASCII letters in one word) + +English (en) +------------ + + The quick brown fox jumps over the lazy dog + +Spanish (es) +------------ + + El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y + frío, añoraba a su querido cachorro. + (Contains every letter and every accent, but not every combination + of vowel + acute.) + +French (fr) +----------- + + Portez ce vieux whisky au juge blond qui fume sur son île intérieure, à + côté de l'alcôve ovoïde, où les bûches se consument dans l'âtre, ce + qui lui permet de penser à la cænogenèse de l'être dont il est question + dans la cause ambiguë entendue à Moÿ, dans un capharnaüm qui, + pense-t-il, diminue çà et là la qualité de son œuvre. + + l'île exiguë + Où l'obèse jury mûr + Fête l'haï volapük, + Âne ex aéquo au whist, + Ôtez ce vœu déçu. + + Le cœur déçu mais l'âme plutôt naïve, Louÿs rêva de crapaüter en + canoë au delà des îles, près du mälström où brûlent les novæ. + +Irish Gaelic (ga) +----------------- + + D'fhuascail Íosa, Úrmhac na hÓighe Beannaithe, pór Éava agus Ádhaimh + +Hungarian (hu) +-------------- + + Árvíztűrő tükörfúrógép + (= flood-proof mirror-drilling machine, only all non-ASCII letters) + +Icelandic (is) +-------------- + + Kæmi ný öxi hér ykist þjófum nú bæði víl og ádrepa + + Sævör grét áðan því úlpan var ónýt + (some ASCII letters missing) + +Greek (el) +------------- + + Γαζέες καὶ μυρτιὲς δὲν θὰ βρῶ πιὰ στὸ χρυσαφὶ ξέφωτο + (= No more shall I see acacias or myrtles in the golden clearing) + + Ξεσκεπάζω τὴν ψυχοφθόρα βδελυγμία + (= I uncover the soul-destroying abhorrence) + +Hebrew (iw) +----------- + + ? דג סקרן שט בים מאוכזב ולפתע מצא לו חברה איך הקליטה + +Polish (pl) +----------- + + Pchnąć w tę łódź jeża lub osiem skrzyń fig + (= To push a hedgehog or eight bins of figs in this boat) + + Zażółć gęślą jaźń + +Russian (ru) +------------ + + В чащах юга жил бы цитрус? Да, но фальшивый экземпляр! + (= Would a citrus live in the bushes of south? Yes, but only a fake one!) + +Thai (th) +--------- + + [--------------------------|------------------------] + ๏ เป็นมนุษย์สุดประเสริฐเลิศคุณค่า กว่าบรรดาฝูงสัตว์เดรัจฉาน + จงฝ่าฟันพัฒนาวิชาการ อย่าล้างผลาญฤๅเข่นฆ่าบีฑาใคร + ไม่ถือโทษโกรธแช่งซัดฮึดฮัดด่า หัดอภัยเหมือนกีฬาอัชฌาสัย + ปฏิบัติประพฤติกฎกำหนดใจ พูดจาให้จ๊ะๆ จ๋าๆ น่าฟังเอย ฯ + + [The copyright for the Thai example is owned by The Computer + Association of Thailand under the Royal Patronage of His Majesty the + King.] + +Please let me know if you find others! Special thanks to the people +from all over the world who contributed these sentences. diff --git a/tools/tcpdf/examples/example_001.php b/tools/tcpdf/examples/example_001.php new file mode 100644 index 000000000..82555e6b2 --- /dev/null +++ b/tools/tcpdf/examples/example_001.php @@ -0,0 +1,110 @@ +setCreator(PDF_CREATOR); +$pdf->setAuthor('Nicola Asuni'); +$pdf->setTitle('TCPDF Example 001'); +$pdf->setSubject('TCPDF Tutorial'); +$pdf->setKeywords('TCPDF, PDF, example, test, guide'); + +// set default header data +$pdf->setHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 001', PDF_HEADER_STRING, array(0,64,255), array(0,64,128)); +$pdf->setFooterData(array(0,64,0), array(0,64,128)); + +// set header and footer fonts +$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN)); +$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA)); + +// set default monospaced font +$pdf->setDefaultMonospacedFont(PDF_FONT_MONOSPACED); + +// set margins +$pdf->setMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); +$pdf->setHeaderMargin(PDF_MARGIN_HEADER); +$pdf->setFooterMargin(PDF_MARGIN_FOOTER); + +// set auto page breaks +$pdf->setAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); + +// set image scale factor +$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); + +// set some language-dependent strings (optional) +if (@file_exists(dirname(__FILE__).'/lang/eng.php')) { + require_once(dirname(__FILE__).'/lang/eng.php'); + $pdf->setLanguageArray($l); +} + +// --------------------------------------------------------- + +// set default font subsetting mode +$pdf->setFontSubsetting(true); + +// Set font +// dejavusans is a UTF-8 Unicode font, if you only need to +// print standard ASCII chars, you can use core fonts like +// helvetica or times to reduce file size. +$pdf->setFont('dejavusans', '', 14, '', true); + +// Add a page +// This method has several options, check the source code documentation for more information. +$pdf->AddPage(); + +// set text shadow effect +$pdf->setTextShadow(array('enabled'=>true, 'depth_w'=>0.2, 'depth_h'=>0.2, 'color'=>array(196,196,196), 'opacity'=>1, 'blend_mode'=>'Normal')); + +// Set some content to print +$html = <<Welcome to  TCPDF ! +This is the first example of TCPDF library. +

This text is printed using the writeHTMLCell() method but you can also use: Multicell(), writeHTML(), Write(), Cell() and Text().

+

Please check the source code documentation and other examples for further information.

+

TO IMPROVE AND EXPAND TCPDF I NEED YOUR SUPPORT, PLEASE MAKE A DONATION!

+EOD; + +// Print text using writeHTMLCell() +$pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true); + +// --------------------------------------------------------- + +// Close and output PDF document +// This method has several options, check the source code documentation for more information. +$pdf->Output('example_001.pdf', 'I'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/example_002.php b/tools/tcpdf/examples/example_002.php new file mode 100644 index 000000000..f40a2014a --- /dev/null +++ b/tools/tcpdf/examples/example_002.php @@ -0,0 +1,91 @@ +setCreator(PDF_CREATOR); +$pdf->setAuthor('Nicola Asuni'); +$pdf->setTitle('TCPDF Example 002'); +$pdf->setSubject('TCPDF Tutorial'); +$pdf->setKeywords('TCPDF, PDF, example, test, guide'); + +// remove default header/footer +$pdf->setPrintHeader(false); +$pdf->setPrintFooter(false); + +// set default monospaced font +$pdf->setDefaultMonospacedFont(PDF_FONT_MONOSPACED); + +// set margins +$pdf->setMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); + +// set auto page breaks +$pdf->setAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); + +// set image scale factor +$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); + +// set some language-dependent strings (optional) +if (@file_exists(dirname(__FILE__).'/lang/eng.php')) { + require_once(dirname(__FILE__).'/lang/eng.php'); + $pdf->setLanguageArray($l); +} + +// --------------------------------------------------------- + +// set font +$pdf->setFont('times', 'BI', 20); + +// add a page +$pdf->AddPage(); + +// set some text to print +$txt = <<Write(0, $txt, '', 0, 'C', true, 0, false, false, 0); + +// --------------------------------------------------------- + +//Close and output PDF document +$pdf->Output('example_002.pdf', 'I'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/example_003.php b/tools/tcpdf/examples/example_003.php new file mode 100644 index 000000000..eeeb0c8d5 --- /dev/null +++ b/tools/tcpdf/examples/example_003.php @@ -0,0 +1,122 @@ +Image($image_file, 10, 10, 15, '', 'JPG', '', 'T', false, 300, '', false, false, 0, false, false, false); + // Set font + $this->setFont('helvetica', 'B', 20); + // Title + $this->Cell(0, 15, '<< TCPDF Example 003 >>', 0, false, 'C', 0, '', 0, false, 'M', 'M'); + } + + // Page footer + public function Footer() { + // Position at 15 mm from bottom + $this->setY(-15); + // Set font + $this->setFont('helvetica', 'I', 8); + // Page number + $this->Cell(0, 10, 'Page '.$this->getAliasNumPage().'/'.$this->getAliasNbPages(), 0, false, 'C', 0, '', 0, false, 'T', 'M'); + } +} + +// create new PDF document +$pdf = new MYPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); + +// set document information +$pdf->setCreator(PDF_CREATOR); +$pdf->setAuthor('Nicola Asuni'); +$pdf->setTitle('TCPDF Example 003'); +$pdf->setSubject('TCPDF Tutorial'); +$pdf->setKeywords('TCPDF, PDF, example, test, guide'); + +// set default header data +$pdf->setHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE, PDF_HEADER_STRING); + +// set header and footer fonts +$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN)); +$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA)); + +// set default monospaced font +$pdf->setDefaultMonospacedFont(PDF_FONT_MONOSPACED); + +// set margins +$pdf->setMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); +$pdf->setHeaderMargin(PDF_MARGIN_HEADER); +$pdf->setFooterMargin(PDF_MARGIN_FOOTER); + +// set auto page breaks +$pdf->setAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); + +// set image scale factor +$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); + +// set some language-dependent strings (optional) +if (@file_exists(dirname(__FILE__).'/lang/eng.php')) { + require_once(dirname(__FILE__).'/lang/eng.php'); + $pdf->setLanguageArray($l); +} + +// --------------------------------------------------------- + +// set font +$pdf->setFont('times', 'BI', 12); + +// add a page +$pdf->AddPage(); + +// set some text to print +$txt = <<Write(0, $txt, '', 0, 'C', true, 0, false, false, 0); + +// --------------------------------------------------------- + +//Close and output PDF document +$pdf->Output('example_003.pdf', 'I'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/example_004.php b/tools/tcpdf/examples/example_004.php new file mode 100644 index 000000000..a1f69a5b9 --- /dev/null +++ b/tools/tcpdf/examples/example_004.php @@ -0,0 +1,123 @@ +setCreator(PDF_CREATOR); +$pdf->setAuthor('Nicola Asuni'); +$pdf->setTitle('TCPDF Example 004'); +$pdf->setSubject('TCPDF Tutorial'); +$pdf->setKeywords('TCPDF, PDF, example, test, guide'); + +// set default header data +$pdf->setHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 004', PDF_HEADER_STRING); + +// set header and footer fonts +$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN)); +$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA)); + +// set default monospaced font +$pdf->setDefaultMonospacedFont(PDF_FONT_MONOSPACED); + +// set margins +$pdf->setMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); +$pdf->setHeaderMargin(PDF_MARGIN_HEADER); +$pdf->setFooterMargin(PDF_MARGIN_FOOTER); + +// set auto page breaks +$pdf->setAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); + +// set image scale factor +$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); + +// set some language-dependent strings (optional) +if (@file_exists(dirname(__FILE__).'/lang/eng.php')) { + require_once(dirname(__FILE__).'/lang/eng.php'); + $pdf->setLanguageArray($l); +} + +// --------------------------------------------------------- + +// set font +$pdf->setFont('times', '', 11); + +// add a page +$pdf->AddPage(); + +//Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=0, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='M') + +// test Cell stretching +$pdf->Cell(0, 0, 'TEST CELL STRETCH: no stretch', 1, 1, 'C', 0, '', 0); +$pdf->Cell(0, 0, 'TEST CELL STRETCH: scaling', 1, 1, 'C', 0, '', 1); +$pdf->Cell(0, 0, 'TEST CELL STRETCH: force scaling', 1, 1, 'C', 0, '', 2); +$pdf->Cell(0, 0, 'TEST CELL STRETCH: spacing', 1, 1, 'C', 0, '', 3); +$pdf->Cell(0, 0, 'TEST CELL STRETCH: force spacing', 1, 1, 'C', 0, '', 4); + +$pdf->Ln(5); + +$pdf->Cell(45, 0, 'TEST CELL STRETCH: scaling', 1, 1, 'C', 0, '', 1); +$pdf->Cell(45, 0, 'TEST CELL STRETCH: force scaling', 1, 1, 'C', 0, '', 2); +$pdf->Cell(45, 0, 'TEST CELL STRETCH: spacing', 1, 1, 'C', 0, '', 3); +$pdf->Cell(45, 0, 'TEST CELL STRETCH: force spacing', 1, 1, 'C', 0, '', 4); + +$pdf->AddPage(); + +// example using general stretching and spacing + +for ($stretching = 90; $stretching <= 110; $stretching += 10) { + for ($spacing = -0.254; $spacing <= 0.254; $spacing += 0.254) { + + // set general stretching (scaling) value + $pdf->setFontStretching($stretching); + + // set general spacing value + $pdf->setFontSpacing($spacing); + + $pdf->Cell(0, 0, 'Stretching '.$stretching.'%, Spacing '.sprintf('%+.3F', $spacing).'mm, no stretch', 1, 1, 'C', 0, '', 0); + $pdf->Cell(0, 0, 'Stretching '.$stretching.'%, Spacing '.sprintf('%+.3F', $spacing).'mm, scaling', 1, 1, 'C', 0, '', 1); + $pdf->Cell(0, 0, 'Stretching '.$stretching.'%, Spacing '.sprintf('%+.3F', $spacing).'mm, force scaling', 1, 1, 'C', 0, '', 2); + $pdf->Cell(0, 0, 'Stretching '.$stretching.'%, Spacing '.sprintf('%+.3F', $spacing).'mm, spacing', 1, 1, 'C', 0, '', 3); + $pdf->Cell(0, 0, 'Stretching '.$stretching.'%, Spacing '.sprintf('%+.3F', $spacing).'mm, force spacing', 1, 1, 'C', 0, '', 4); + + $pdf->Ln(2); + } +} + +// --------------------------------------------------------- + +//Close and output PDF document +$pdf->Output('example_004.pdf', 'I'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/example_005.php b/tools/tcpdf/examples/example_005.php new file mode 100644 index 000000000..c27dfeac4 --- /dev/null +++ b/tools/tcpdf/examples/example_005.php @@ -0,0 +1,160 @@ +setCreator(PDF_CREATOR); +$pdf->setAuthor('Nicola Asuni'); +$pdf->setTitle('TCPDF Example 005'); +$pdf->setSubject('TCPDF Tutorial'); +$pdf->setKeywords('TCPDF, PDF, example, test, guide'); + +// set default header data +$pdf->setHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 005', PDF_HEADER_STRING); + +// set header and footer fonts +$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN)); +$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA)); + +// set default monospaced font +$pdf->setDefaultMonospacedFont(PDF_FONT_MONOSPACED); + +// set margins +$pdf->setMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); +$pdf->setHeaderMargin(PDF_MARGIN_HEADER); +$pdf->setFooterMargin(PDF_MARGIN_FOOTER); + +// set auto page breaks +$pdf->setAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); + +// set image scale factor +$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); + +// set some language-dependent strings (optional) +if (@file_exists(dirname(__FILE__).'/lang/eng.php')) { + require_once(dirname(__FILE__).'/lang/eng.php'); + $pdf->setLanguageArray($l); +} + +// --------------------------------------------------------- + +// set font +$pdf->setFont('times', '', 10); + +// add a page +$pdf->AddPage(); + +// set cell padding +$pdf->setCellPaddings(1, 1, 1, 1); + +// set cell margins +$pdf->setCellMargins(1, 1, 1, 1); + +// set color for background +$pdf->setFillColor(255, 255, 127); + +// MultiCell($w, $h, $txt, $border=0, $align='J', $fill=0, $ln=1, $x='', $y='', $reseth=true, $stretch=0, $ishtml=false, $autopadding=true, $maxh=0) + +// set some text for example +$txt = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'; + +// Multicell test +$pdf->MultiCell(55, 5, '[LEFT] '.$txt, 1, 'L', 1, 0, '', '', true); +$pdf->MultiCell(55, 5, '[RIGHT] '.$txt, 1, 'R', 0, 1, '', '', true); +$pdf->MultiCell(55, 5, '[CENTER] '.$txt, 1, 'C', 0, 0, '', '', true); +$pdf->MultiCell(55, 5, '[JUSTIFY] '.$txt."\n", 1, 'J', 1, 2, '' ,'', true); +$pdf->MultiCell(55, 5, '[DEFAULT] '.$txt, 1, '', 0, 1, '', '', true); + +$pdf->Ln(4); + +// set color for background +$pdf->setFillColor(220, 255, 220); + +// Vertical alignment +$pdf->MultiCell(55, 40, '[VERTICAL ALIGNMENT - TOP] '.$txt, 1, 'J', 1, 0, '', '', true, 0, false, true, 40, 'T'); +$pdf->MultiCell(55, 40, '[VERTICAL ALIGNMENT - MIDDLE] '.$txt, 1, 'J', 1, 0, '', '', true, 0, false, true, 40, 'M'); +$pdf->MultiCell(55, 40, '[VERTICAL ALIGNMENT - BOTTOM] '.$txt, 1, 'J', 1, 1, '', '', true, 0, false, true, 40, 'B'); + +$pdf->Ln(4); + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +// set color for background +$pdf->setFillColor(215, 235, 255); + +// set some text for example +$txt = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In sed imperdiet lectus. Phasellus quis velit velit, non condimentum quam. Sed neque urna, ultrices ac volutpat vel, laoreet vitae augue. Sed vel velit erat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras eget velit nulla, eu sagittis elit. Nunc ac arcu est, in lobortis tellus. Praesent condimentum rhoncus sodales. In hac habitasse platea dictumst. Proin porta eros pharetra enim tincidunt dignissim nec vel dolor. Cras sapien elit, ornare ac dignissim eu, ultricies ac eros. Maecenas augue magna, ultrices a congue in, mollis eu nulla. Nunc venenatis massa at est eleifend faucibus. Vivamus sed risus lectus, nec interdum nunc. + +Fusce et felis vitae diam lobortis sollicitudin. Aenean tincidunt accumsan nisi, id vehicula quam laoreet elementum. Phasellus egestas interdum erat, et viverra ipsum ultricies ac. Praesent sagittis augue at augue volutpat eleifend. Cras nec orci neque. Mauris bibendum posuere blandit. Donec feugiat mollis dui sit amet pellentesque. Sed a enim justo. Donec tincidunt, nisl eget elementum aliquam, odio ipsum ultrices quam, eu porttitor ligula urna at lorem. Donec varius, eros et convallis laoreet, ligula tellus consequat felis, ut ornare metus tellus sodales velit. Duis sed diam ante. Ut rutrum malesuada massa, vitae consectetur ipsum rhoncus sed. Suspendisse potenti. Pellentesque a congue massa.'; + +// print a blox of text using multicell() +$pdf->MultiCell(80, 5, $txt."\n", 1, 'J', 1, 1, '' ,'', true); + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +// AUTO-FITTING + +// set color for background +$pdf->setFillColor(255, 235, 235); + +// Fit text on cell by reducing font size +$pdf->MultiCell(55, 60, '[FIT CELL] '.$txt."\n", 1, 'J', 1, 1, 125, 145, true, 0, false, true, 60, 'M', true); + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +// CUSTOM PADDING + +// set color for background +$pdf->setFillColor(255, 255, 215); + +// set font +$pdf->setFont('helvetica', '', 8); + +// set cell padding +$pdf->setCellPaddings(2, 4, 6, 8); + +$txt = "CUSTOM PADDING:\nLeft=2, Top=4, Right=6, Bottom=8\nLorem ipsum dolor sit amet, consectetur adipiscing elit. In sed imperdiet lectus. Phasellus quis velit velit, non condimentum quam. Sed neque urna, ultrices ac volutpat vel, laoreet vitae augue.\n"; + +$pdf->MultiCell(55, 5, $txt, 1, 'J', 1, 2, 125, 210, true); + +// move pointer to last page +$pdf->lastPage(); + +// --------------------------------------------------------- + +//Close and output PDF document +$pdf->Output('example_005.pdf', 'I'); + +//============================================================+ +// END OF FILE +//============================================================+ diff --git a/tools/tcpdf/examples/example_006.php b/tools/tcpdf/examples/example_006.php new file mode 100644 index 000000000..f2c7dbca7 --- /dev/null +++ b/tools/tcpdf/examples/example_006.php @@ -0,0 +1,347 @@ +setCreator(PDF_CREATOR); +$pdf->setAuthor('Nicola Asuni'); +$pdf->setTitle('TCPDF Example 006'); +$pdf->setSubject('TCPDF Tutorial'); +$pdf->setKeywords('TCPDF, PDF, example, test, guide'); + +// set default header data +$pdf->setHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 006', PDF_HEADER_STRING); + +// set header and footer fonts +$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN)); +$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA)); + +// set default monospaced font +$pdf->setDefaultMonospacedFont(PDF_FONT_MONOSPACED); + +// set margins +$pdf->setMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); +$pdf->setHeaderMargin(PDF_MARGIN_HEADER); +$pdf->setFooterMargin(PDF_MARGIN_FOOTER); + +// set auto page breaks +$pdf->setAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); + +// set image scale factor +$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); + +// set some language-dependent strings (optional) +if (@file_exists(dirname(__FILE__).'/lang/eng.php')) { + require_once(dirname(__FILE__).'/lang/eng.php'); + $pdf->setLanguageArray($l); +} + +// --------------------------------------------------------- + +// set font +$pdf->setFont('dejavusans', '', 10); + +// add a page +$pdf->AddPage(); + +// writeHTML($html, $ln=true, $fill=false, $reseth=false, $cell=false, $align='') +// writeHTMLCell($w, $h, $x, $y, $html='', $border=0, $ln=0, $fill=0, $reseth=true, $align='', $autopadding=true) + +// create some HTML content +$html = '

HTML Example

+Some special characters: < € € € & è è © > \\slash \\\\double-slash \\\\\\triple-slash +

List

+List example: +
    +
  1. test alt attribute test image
  2. +
  3. bold text
  4. +
  5. italic text
  6. +
  7. underlined text
  8. +
  9. bbibiubib
  10. +
  11. link to http://www.tecnick.com
  12. +
  13. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
    Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
  14. +
  15. SUBLIST +
      +
    1. row one +
        +
      • sublist
      • +
      +
    2. +
    3. row two
    4. +
    +
  16. +
  17. TEST line through
  18. +
  19. font + 3
  20. +
  21. small text normal small text normal subscript normal superscript normal
  22. +
+
+
Coffee
+
Black hot drink
+
Milk
+
White cold drink
+
+
IMAGES
+test alt attributetest alt attributetest alt attribute +
'; + +// output the HTML content +$pdf->writeHTML($html, true, false, true, false, ''); + + +// output some RTL HTML content +$html = '
The words “מזל [mazel] טוב [tov]” mean “Congratulations!”
'; +$pdf->writeHTML($html, true, false, true, false, ''); + +// test some inline CSS +$html = '

This is just an example of html code to demonstrate some supported CSS inline styles. +bold text +line-trough +underline and line-trough +color +background color +bold +xx-small +x-small +small +medium +large +x-large +xx-large +

'; + +$pdf->writeHTML($html, true, false, true, false, ''); + +// reset pointer to the last page +$pdf->lastPage(); + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Print a table + +// add a page +$pdf->AddPage(); + +// create some HTML content +$subtable = '
ab
cd
'; + +$html = '

HTML TABLE:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#RIGHT alignLEFT align4A
1A1 example link column span. One two tree four five six seven eight nine ten.
line after br
small text normal subscript normal superscript normal bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
  1. first
    1. sublist
    2. sublist
  2. second
small small small small small small small small small small small small small small small small small small small small
4B
'.$subtable.'A2 € € € & è è
A2 € € € & è è
Red Yellow BG4C
1A2AA
2AB
2AC
4D
1B4E
1C2C3C4F
'; + +// output the HTML content +$pdf->writeHTML($html, true, false, true, false, ''); + +// Print some HTML Cells + +$html = 'red green blue
red green blue'; + +$pdf->setFillColor(255,255,0); + +$pdf->writeHTMLCell(0, 0, '', '', $html, 'LRTB', 1, 0, true, 'L', true); +$pdf->writeHTMLCell(0, 0, '', '', $html, 'LRTB', 1, 1, true, 'C', true); +$pdf->writeHTMLCell(0, 0, '', '', $html, 'LRTB', 1, 0, true, 'R', true); + +// reset pointer to the last page +$pdf->lastPage(); + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Print a table + +// add a page +$pdf->AddPage(); + +// create some HTML content +$html = '

Image alignments on HTML table

+ + + + + + + + +
'; + +// output the HTML content +$pdf->writeHTML($html, true, false, true, false, ''); + +// create some HTML content +$html = '

Embedded Images

+ + + +
src="@..."
src="data..."
'; + +$data = base64_encode(file_get_contents("images/logo_example.png")); +$html = str_replace("@DATA1@", "@" . $data, $html); +$html = str_replace("@DATA2@", "data:image/png;base64," . $data, $html); + +// output the HTML content +$pdf->writeHTML($html, true, false, true, false, ''); + +// reset pointer to the last page +$pdf->lastPage(); + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Print all HTML colors + +// add a page +$pdf->AddPage(); + +$textcolors = '

HTML Text Colors

'; +$bgcolors = '

HTML Background Colors

'; + +foreach(TCPDF_COLORS::$webcolor as $k => $v) { + $textcolors .= ''.$v.' '; + $bgcolors .= ''.$v.' '; +} + +// output the HTML content +$pdf->writeHTML($textcolors, true, false, true, false, ''); +$pdf->writeHTML($bgcolors, true, false, true, false, ''); + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +// Test word-wrap + +// create some HTML content +$html = '
+

Various tests

+link to page 2
+thisisaverylongword thisisanotherverylongword thisisaverylongword thisisanotherverylongword thisisaverylongword thisisaverylongword thisisanotherverylongword thisisaverylongword thisisanotherverylongword thisisaverylongword thisisaverylongword thisisanotherverylongword thisisaverylongword thisisanotherverylongword thisisaverylongword thisisaverylongword thisisanotherverylongword thisisaverylongword thisisanotherverylongword thisisaverylongword thisisaverylongword thisisanotherverylongword thisisaverylongword thisisanotherverylongword thisisaverylongword'; + +// output the HTML content +$pdf->writeHTML($html, true, false, true, false, ''); + +// Test fonts nesting +$html1 = 'Default Courier Helvetica Times dejavusans Times Helvetica Courier Default'; +$html2 = 'small text normal small text normal subscript normal superscript normal'; +$html3 = 'The quick brown fox jumps over the lazy dog.'; + +$html = $html1.'
'.$html2.'
'.$html3.'
'.$html3.'
'.$html2; + +// output the HTML content +$pdf->writeHTML($html, true, false, true, false, ''); + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// test pre tag + +// add a page +$pdf->AddPage(); + +$html = << +Hello World!
+Hello + +
+int main() {
+    printf("HelloWorld");
+    return 0;
+}
+
+Monospace font, normal font, monospace font, normal font. +
+
DIV LEVEL 1
DIV LEVEL 2
DIV LEVEL 1
+
+SPAN LEVEL 1 SPAN LEVEL 2 SPAN LEVEL 1 +EOF; + +// output the HTML content +$pdf->writeHTML($html, true, false, true, false, ''); + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +// test custom bullet points for list + +// add a page +$pdf->AddPage(); + +$html = <<Test custom bullet image for list items +
    +
  • test custom bullet image
  • +
  • test custom bullet image
  • +
  • test custom bullet image
  • +
  • test custom bullet image
  • + - * @param $txt (string) input string - * @param $unicode (boolean) True if we are in unicode mode, false otherwise. + * @param string $txt input string + * @param boolean $unicode True if we are in unicode mode, false otherwise. * @return string without SHY characters. * @since (4.5.019) 2009-02-28 * @public static @@ -201,10 +171,10 @@ class TCPDF_STATIC { /** * Get the border mode accounting for multicell position (opens bottom side of multicell crossing pages) - * @param $brd (mixed) Indicates if borders must be drawn around the cell block. The value can be a number:
    • 0: no border (default)
    • 1: frame
    or a string containing some or all of the following characters (in any order):
    • L: left
    • T: top
    • R: right
    • B: bottom
    or an array of line styles for each border group: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) - * @param $position (string) multicell position: 'start', 'middle', 'end' - * @param $opencell (boolean) True when the cell is left open at the page bottom, false otherwise. - * @return border mode array + * @param string|array|int $brd Indicates if borders must be drawn around the cell block. The value can be a number:
    • 0: no border (default)
    • 1: frame
    or a string containing some or all of the following characters (in any order):
    • L: left
    • T: top
    • R: right
    • B: bottom
    or an array of line styles for each border group: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) + * @param string $position multicell position: 'start', 'middle', 'end' + * @param boolean $opencell True when the cell is left open at the page bottom, false otherwise. + * @return array border mode array * @since 4.4.002 (2008-12-09) * @public static */ @@ -275,8 +245,8 @@ class TCPDF_STATIC { /** * Determine whether a string is empty. - * @param $str (string) string to be checked - * @return boolean true if string is empty + * @param string $str string to be checked + * @return bool true if string is empty * @since 4.5.044 (2009-04-16) * @public static */ @@ -286,8 +256,8 @@ class TCPDF_STATIC { /** * Returns a temporary filename for caching object on filesystem. - * @param $type (string) Type of file (name of the subdir on the tcpdf cache folder). - * @param $file_id (string) TCPDF file_id. + * @param string $type Type of file (name of the subdir on the tcpdf cache folder). + * @param string $file_id TCPDF file_id. * @return string filename. * @since 4.5.000 (2008-12-31) * @public static @@ -298,7 +268,7 @@ class TCPDF_STATIC { /** * Add "\" before "\", "(" and ")" - * @param $s (string) string to escape. + * @param string $s string to escape. * @return string escaped string. * @public static */ @@ -309,21 +279,21 @@ class TCPDF_STATIC { /** * Escape some special characters (< > &) for XML output. - * @param $str (string) Input string to convert. - * @return converted string + * @param string $str Input string to convert. + * @return string converted string * @since 5.9.121 (2011-09-28) * @public static */ public static function _escapeXML($str) { $replaceTable = array("\0" => '', '&' => '&', '<' => '<', '>' => '>'); - $str = strtr($str, $replaceTable); + $str = strtr($str === null ? '' : $str, $replaceTable); return $str; } /** * Creates a copy of a class object - * @param $object (object) class object to be cloned - * @return cloned object + * @param object $object class object to be cloned + * @return object cloned object * @since 4.5.029 (2009-03-19) * @public static */ @@ -337,8 +307,8 @@ class TCPDF_STATIC { /** * Output input data and compress it if possible. - * @param $data (string) Data to output. - * @param $length (int) Data length in bytes. + * @param string $data Data to output. + * @param int $length Data length in bytes. * @since 5.9.086 * @public static */ @@ -352,10 +322,10 @@ class TCPDF_STATIC { /** * Replace page number aliases with number. - * @param $page (string) Page content. - * @param $replace (array) Array of replacements (array keys are replacement strings, values are alias arrays). - * @param $diff (int) If passed, this will be set to the total char number difference between alias and replacements. - * @return replaced page content and updated $diff parameter as array. + * @param string $page Page content. + * @param array $replace Array of replacements (array keys are replacement strings, values are alias arrays). + * @param int $diff If passed, this will be set to the total char number difference between alias and replacements. + * @return array replaced page content and updated $diff parameter as array. * @public static */ public static function replacePageNumAliases($page, $replace, $diff=0) { @@ -372,7 +342,7 @@ class TCPDF_STATIC { /** * Returns timestamp in seconds from formatted date-time. - * @param $date (string) Formatted date-time. + * @param string $date Formatted date-time. * @return int seconds. * @since 5.9.152 (2012-03-23) * @public static @@ -387,7 +357,7 @@ class TCPDF_STATIC { /** * Returns a formatted date-time. - * @param $time (int) Time in seconds. + * @param int $time Time in seconds. * @return string escaped date string. * @since 5.9.152 (2012-03-23) * @public static @@ -398,7 +368,7 @@ class TCPDF_STATIC { /** * Returns a string containing random data to be used as a seed for encryption methods. - * @param $seed (string) starting seed value + * @param string $seed starting seed value * @return string containing random data * @author Nicola Asuni * @since 5.9.006 (2010-10-19) @@ -409,7 +379,10 @@ class TCPDF_STATIC { if (function_exists('posix_getpid')) { $rnd .= posix_getpid(); } - if (function_exists('openssl_random_pseudo_bytes') AND (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { + + if (function_exists('random_bytes')) { + $rnd .= random_bytes(512); + } elseif (function_exists('openssl_random_pseudo_bytes') AND (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // this is not used on windows systems because it is very slow for a know bug $rnd .= openssl_random_pseudo_bytes(512); } else { @@ -417,13 +390,13 @@ class TCPDF_STATIC { $rnd .= uniqid('', true); } } - return $rnd.$seed.__FILE__.serialize($_SERVER).microtime(true); + return $rnd.$seed.__FILE__.microtime(true); } /** * Encrypts a string using MD5 and returns it's value as a binary string. - * @param $str (string) input string - * @return String MD5 encrypted binary string + * @param string $str input string + * @return string MD5 encrypted binary string * @since 2.0.000 (2008-01-02) * @public static */ @@ -432,11 +405,11 @@ class TCPDF_STATIC { } /** - * Returns the input text exrypted using AES algorithm and the specified key. + * Returns the input text encrypted using AES algorithm and the specified key. * This method requires openssl or mcrypt. Text is padded to 16bytes blocks - * @param $key (string) encryption key - * @param $text (String) input text to be encrypted - * @return String encrypted text + * @param string $key encryption key + * @param string $text input text to be encrypted + * @return string encrypted text * @author Nicola Asuni * @since 5.0.005 (2010-05-11) * @public static @@ -446,8 +419,12 @@ class TCPDF_STATIC { $padding = 16 - (strlen($text) % 16); $text .= str_repeat(chr($padding), $padding); if (extension_loaded('openssl')) { - $iv = openssl_random_pseudo_bytes (openssl_cipher_iv_length('aes-256-cbc')); - $text = openssl_encrypt($text, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); + $algo = 'aes-256-cbc'; + if (strlen($key) == 16) { + $algo = 'aes-128-cbc'; + } + $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($algo)); + $text = openssl_encrypt($text, $algo, $key, OPENSSL_RAW_DATA, $iv); return $iv.substr($text, 0, -16); } $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND); @@ -457,19 +434,23 @@ class TCPDF_STATIC { } /** - * Returns the input text exrypted using AES algorithm and the specified key. + * Returns the input text encrypted using AES algorithm and the specified key. * This method requires openssl or mcrypt. Text is not padded - * @param $key (string) encryption key - * @param $text (String) input text to be encrypted - * @return String encrypted text + * @param string $key encryption key + * @param string $text input text to be encrypted + * @return string encrypted text * @author Nicola Asuni * @since TODO * @public static */ public static function _AESnopad($key, $text) { if (extension_loaded('openssl')) { - $iv = str_repeat("\x00", openssl_cipher_iv_length('aes-256-cbc')); - $text = openssl_encrypt($text, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); + $algo = 'aes-256-cbc'; + if (strlen($key) == 16) { + $algo = 'aes-128-cbc'; + } + $iv = str_repeat("\x00", openssl_cipher_iv_length($algo)); + $text = openssl_encrypt($text, $algo, $key, OPENSSL_RAW_DATA, $iv); return substr($text, 0, -16); } $iv = str_repeat("\x00", mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC)); @@ -480,11 +461,11 @@ class TCPDF_STATIC { /** * Returns the input text encrypted using RC4 algorithm and the specified key. * RC4 is the standard encryption algorithm used in PDF format - * @param $key (string) Encryption key. - * @param $text (String) Input text to be encrypted. - * @param $last_enc_key (String) Reference to last RC4 key encrypted. - * @param $last_enc_key_c (String) Reference to last RC4 computed key. - * @return String encrypted text + * @param string $key Encryption key. + * @param string $text Input text to be encrypted. + * @param string $last_enc_key Reference to last RC4 key encrypted. + * @param string $last_enc_key_c Reference to last RC4 computed key. + * @return string encrypted text * @since 2.0.000 (2008-01-02) * @author Klemen Vodopivec, Nicola Asuni * @public static @@ -495,7 +476,7 @@ class TCPDF_STATIC { return $out; } if ($last_enc_key != $key) { - $k = str_repeat($key, ((256 / strlen($key)) + 1)); + $k = str_repeat($key, (int) ((256 / strlen($key)) + 1)); $rc4 = range(0, 255); $j = 0; for ($i = 0; $i < 256; ++$i) { @@ -527,8 +508,8 @@ class TCPDF_STATIC { /** * Return the permission code used on encryption (P value). - * @param $permissions (Array) the set of permissions (specify the ones you want to block). - * @param $mode (int) encryption strength: 0 = RC4 40 bit; 1 = RC4 128 bit; 2 = AES 128 bit; 3 = AES 256 bit. + * @param array $permissions the set of permissions (specify the ones you want to block). + * @param int $mode encryption strength: 0 = RC4 40 bit; 1 = RC4 128 bit; 2 = AES 128 bit; 3 = AES 256 bit. * @since 5.0.005 (2010-05-12) * @author Nicola Asuni * @public static @@ -564,8 +545,8 @@ class TCPDF_STATIC { /** * Convert hexadecimal string to string - * @param $bs (string) byte-string to convert - * @return String + * @param string $bs byte-string to convert + * @return string * @since 5.0.005 (2010-05-12) * @author Nicola Asuni * @public static @@ -586,8 +567,8 @@ class TCPDF_STATIC { /** * Convert string to hexadecimal string (byte string) - * @param $s (string) string to convert - * @return byte string + * @param string $s string to convert + * @return string byte string * @since 5.0.010 (2010-05-17) * @author Nicola Asuni * @public static @@ -603,8 +584,8 @@ class TCPDF_STATIC { /** * Convert encryption P value to a string of bytes, low-order byte first. - * @param $protection (string) 32bit encryption permission value (P value) - * @return String + * @param string $protection 32bit encryption permission value (P value) + * @return string * @since 5.0.005 (2010-05-12) * @author Nicola Asuni * @public static @@ -620,8 +601,8 @@ class TCPDF_STATIC { /** * Encode a name object. - * @param $name (string) Name object to encode. - * @return (string) Encoded name object. + * @param string $name Name object to encode. + * @return string Encoded name object. * @author Nicola Asuni * @since 5.9.097 (2011-06-23) * @public static @@ -642,9 +623,9 @@ class TCPDF_STATIC { /** * Convert JavaScript form fields properties array to Annotation Properties array. - * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference. - * @param $spot_colors (array) Reference to spot colors array. - * @param $rtl (boolean) True if in Right-To-Left text direction mode, false otherwise. + * @param array $prop javascript field properties. Possible values are described on official Javascript for Acrobat API reference. + * @param array $spot_colors Reference to spot colors array. + * @param boolean $rtl True if in Right-To-Left text direction mode, false otherwise. * @return array of annotation properties * @author Nicola Asuni * @since 4.8.000 (2009-09-06) @@ -652,7 +633,7 @@ class TCPDF_STATIC { */ public static function getAnnotOptFromJSProp($prop, &$spot_colors, $rtl=false) { if (isset($prop['aopt']) AND is_array($prop['aopt'])) { - // the annotation options area lready defined + // the annotation options are already defined return $prop['aopt']; } $opt = array(); // value to be returned @@ -841,9 +822,7 @@ class TCPDF_STATIC { if (isset($prop['charLimit'])) { $opt['maxlen'] = intval($prop['charLimit']); } - if (!isset($ff)) { - $ff = 0; // default value - } + $ff = 0; // readonly: The read-only characteristic of a field. If a field is read-only, the user can see the field but cannot change it. if (isset($prop['readonly']) AND ($prop['readonly'] == 'true')) { $ff += 1 << 0; @@ -1011,8 +990,9 @@ class TCPDF_STATIC { /** * Format the page numbers. - * This method can be overriden for custom formats. - * @param $num (int) page number + * This method can be overridden for custom formats. + * @param int $num page number + * @return string * @since 4.2.005 (2008-11-06) * @public static */ @@ -1022,8 +1002,9 @@ class TCPDF_STATIC { /** * Format the page numbers on the Table Of Content. - * This method can be overriden for custom formats. - * @param $num (int) page number + * This method can be overridden for custom formats. + * @param int $num page number + * @return string * @since 4.5.001 (2009-01-04) * @see addTOC(), addHTMLTOC() * @public static @@ -1034,8 +1015,8 @@ class TCPDF_STATIC { /** * Extracts the CSS properties from a CSS string. - * @param $cssdata (string) string containing CSS definitions. - * @return An array where the keys are the CSS selectors and the values are the CSS properties. + * @param string $cssdata string containing CSS definitions. + * @return array An array where the keys are the CSS selectors and the values are the CSS properties. * @author Nicola Asuni * @since 5.1.000 (2010-05-25) * @public static @@ -1125,20 +1106,20 @@ class TCPDF_STATIC { /** * Cleanup HTML code (requires HTML Tidy library). - * @param $html (string) htmlcode to fix - * @param $default_css (string) CSS commands to add - * @param $tagvs (array) parameters for setHtmlVSpace method - * @param $tidy_options (array) options for tidy_parse_string function - * @param $tagvspaces (array) Array of vertical spaces for tags. + * @param string $html htmlcode to fix + * @param string $default_css CSS commands to add + * @param array|null $tagvs parameters for setHtmlVSpace method + * @param array|null $tidy_options options for tidy_parse_string function + * @param array $tagvspaces Array of vertical spaces for tags. * @return string XHTML code cleaned up * @author Nicola Asuni * @since 5.9.017 (2010-11-16) * @see setHtmlVSpace() * @public static */ - public static function fixHTMLCode($html, $default_css='', $tagvs='', $tidy_options='', &$tagvspaces) { + public static function fixHTMLCode($html, $default_css, $tagvs, $tidy_options, &$tagvspaces) { // configure parameters for HTML Tidy - if ($tidy_options === '') { + if (TCPDF_STATIC::empty_string($tidy_options)) { $tidy_options = array ( 'clean' => 1, 'drop-empty-paras' => 0, @@ -1185,7 +1166,7 @@ class TCPDF_STATIC { // remove some empty tag blocks $html = preg_replace('/]*)><\/div>/', '', $html); $html = preg_replace('/]*)><\/p>/', '', $html); - if ($tagvs !== '') { + if (!TCPDF_STATIC::empty_string($tagvs)) { // set vertical space for some XHTML tags $tagvspaces = $tagvs; } @@ -1195,9 +1176,9 @@ class TCPDF_STATIC { /** * Returns true if the CSS selector is valid for the selected HTML tag - * @param $dom (array) array of HTML tags and properties - * @param $key (int) key of the current HTML tag - * @param $selector (string) CSS selector string + * @param array $dom array of HTML tags and properties + * @param int $key key of the current HTML tag + * @param string $selector CSS selector string * @return true if the selector is valid, false otherwise * @since 5.1.000 (2010-05-25) * @public static @@ -1355,9 +1336,9 @@ class TCPDF_STATIC { /** * Returns the styles array that apply for the selected HTML tag. - * @param $dom (array) array of HTML tags and properties - * @param $key (int) key of the current HTML tag - * @param $css (array) array of CSS properties + * @param array $dom array of HTML tags and properties + * @param int $key key of the current HTML tag + * @param array $css array of CSS properties * @return array containing CSS properties * @since 5.1.000 (2010-05-25) * @public static @@ -1402,7 +1383,7 @@ class TCPDF_STATIC { /** * Compact CSS data array into single string. - * @param $css (array) array of CSS properties + * @param array $css array of CSS properties * @return string containing merged CSS properties * @since 5.9.070 (2011-04-19) * @public static @@ -1433,13 +1414,17 @@ class TCPDF_STATIC { /** * Returns the Roman representation of an integer number - * @param $number (int) number to convert + * @param int $number number to convert * @return string roman representation of the specified number * @since 4.4.004 (2008-12-10) * @public static */ public static function intToRoman($number) { $roman = ''; + if ($number >= 4000) { + // do not represent numbers above 4000 in Roman numerals + return strval($number); + } while ($number >= 1000) { $roman .= 'M'; $number -= 1000; @@ -1497,10 +1482,10 @@ class TCPDF_STATIC { /** * Find position of last occurrence of a substring in a string - * @param $haystack (string) The string to search in. - * @param $needle (string) substring to search. - * @param $offset (int) May be specified to begin searching an arbitrary number of characters into the string. - * @return Returns the position where the needle exists. Returns FALSE if the needle was not found. + * @param string $haystack The string to search in. + * @param string $needle substring to search. + * @param int $offset May be specified to begin searching an arbitrary number of characters into the string. + * @return int|false Returns the position where the needle exists. Returns FALSE if the needle was not found. * @since 4.8.038 (2010-03-13) * @public static */ @@ -1513,7 +1498,7 @@ class TCPDF_STATIC { /** * Returns an array of hyphenation patterns. - * @param $file (string) TEX file containing hypenation patterns. TEX pattrns can be downloaded from http://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/ + * @param string $file TEX file containing hypenation patterns. TEX patterns can be downloaded from http://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/ * @return array of hyphenation patterns * @author Nicola Asuni * @since 4.9.012 (2010-04-12) @@ -1546,7 +1531,7 @@ class TCPDF_STATIC { /** * Get the Path-Painting Operators. - * @param $style (string) Style of rendering. Possible values are: + * @param string $style Style of rendering. Possible values are: *
      *
    • S or D: Stroke the path.
    • *
    • s or d: Close and stroke the path.
    • @@ -1560,7 +1545,8 @@ class TCPDF_STATIC { *
    • CEO: Clipping mode using the nonzero winding number rule to determine which regions lie inside the clipping path
    • *
    • n: End the path object without filling or stroking it.
    • *
    - * @param $default (string) default style + * @param string $default default style + * @return string * @author Nicola Asuni * @since 5.0.000 (2010-04-30) * @public static @@ -1637,9 +1623,9 @@ class TCPDF_STATIC { /** * Get the product of two SVG tranformation matrices - * @param $ta (array) first SVG tranformation matrix - * @param $tb (array) second SVG tranformation matrix - * @return transformation array + * @param array $ta first SVG tranformation matrix + * @param array $tb second SVG tranformation matrix + * @return array transformation array * @author Nicola Asuni * @since 5.0.000 (2010-05-02) * @public static @@ -1657,7 +1643,7 @@ class TCPDF_STATIC { /** * Get the tranformation matrix from SVG transform attribute - * @param $attribute (string) transformation + * @param string $attribute transformation * @return array of transformations * @author Nicola Asuni * @since 5.0.000 (2010-05-02) @@ -1752,10 +1738,10 @@ class TCPDF_STATIC { /** * Returns the angle in radiants between two vectors - * @param $x1 (int) X coordinate of first vector point - * @param $y1 (int) Y coordinate of first vector point - * @param $x2 (int) X coordinate of second vector point - * @param $y2 (int) Y coordinate of second vector point + * @param int $x1 X coordinate of first vector point + * @param int $y1 Y coordinate of first vector point + * @param int $x2 X coordinate of second vector point + * @param int $y2 Y coordinate of second vector point * @author Nicola Asuni * @since 5.0.000 (2010-05-04) * @public static @@ -1777,20 +1763,27 @@ class TCPDF_STATIC { /** * Split string by a regular expression. * This is a wrapper for the preg_split function to avoid the bug: https://bugs.php.net/bug.php?id=45850 - * @param $pattern (string) The regular expression pattern to search for without the modifiers, as a string. - * @param $modifiers (string) The modifiers part of the pattern, - * @param $subject (string) The input string. - * @param $limit (int) If specified, then only substrings up to limit are returned with the rest of the string being placed in the last substring. A limit of -1, 0 or NULL means "no limit" and, as is standard across PHP, you can use NULL to skip to the flags parameter. - * @param $flags (int) The flags as specified on the preg_split PHP function. - * @return Returns an array containing substrings of subject split along boundaries matched by pattern.modifier + * @param string $pattern The regular expression pattern to search for without the modifiers, as a string. + * @param string $modifiers The modifiers part of the pattern, + * @param string $subject The input string. + * @param int $limit If specified, then only substrings up to limit are returned with the rest of the string being placed in the last substring. A limit of -1, 0 or NULL means "no limit" and, as is standard across PHP, you can use NULL to skip to the flags parameter. + * @param int $flags The flags as specified on the preg_split PHP function. + * @return array Returns an array containing substrings of subject split along boundaries matched by pattern.modifier * @author Nicola Asuni * @since 6.0.023 * @public static */ public static function pregSplit($pattern, $modifiers, $subject, $limit=NULL, $flags=NULL) { + // PHP 8.1 deprecates nulls for $limit and $flags + $limit = $limit === null ? -1 : $limit; + $flags = $flags === null ? 0 : $flags; // the bug only happens on PHP 5.2 when using the u modifier if ((strpos($modifiers, 'u') === FALSE) OR (count(preg_split('//u', "\n\t", -1, PREG_SPLIT_NO_EMPTY)) == 2)) { - return preg_split($pattern.$modifiers, $subject, $limit, $flags); + $ret = preg_split($pattern.$modifiers, $subject, $limit, $flags); + if ($ret === false) { + return array(); + } + return is_array($ret) ? $ret : array(); } // preg_split is bugged - try alternative solution $ret = array(); @@ -1807,9 +1800,9 @@ class TCPDF_STATIC { /** * Wrapper to use fopen only with local files - * @param filename (string) Name of the file to open - * @param $mode (string) - * @return Returns a file pointer resource on success, or FALSE on error. + * @param string $filename Name of the file to open + * @param string $mode + * @return resource|false Returns a file pointer resource on success, or FALSE on error. * @public static */ public static function fopenLocal($filename, $mode) { @@ -1823,9 +1816,10 @@ class TCPDF_STATIC { /** * Check if the URL exist. - * @param url (string) URL to check. - * @return Returns TRUE if the URL exists; FALSE otherwise. + * @param string $url URL to check. + * @return bool Returns TRUE if the URL exists; FALSE otherwise. * @public static + * @since 6.2.25 */ public static function url_exists($url) { $crs = curl_init(); @@ -1842,6 +1836,10 @@ class TCPDF_STATIC { curl_setopt($crs, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($crs, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($crs, CURLOPT_USERAGENT, 'tc-lib-file'); + curl_setopt($crs, CURLOPT_MAXREDIRS, 5); + if (defined('CURLOPT_PROTOCOLS')) { + curl_setopt($crs, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP | CURLPROTO_FTP | CURLPROTO_FTPS); + } curl_exec($crs); $code = curl_getinfo($crs, CURLINFO_HTTP_CODE); curl_close($crs); @@ -1859,9 +1857,10 @@ class TCPDF_STATIC { public static function encodeUrlQuery($url) { $urlData = parse_url($url); if (isset($urlData['query']) && $urlData['query']) { - $urlQueryData = []; + $urlQueryData = array(); parse_str(urldecode($urlData['query']), $urlQueryData); - $updatedUrl = $urlData['scheme'] . '://' . $urlData['host'] . $urlData['path'] . '?' . http_build_query($urlQueryData); + $port = isset($urlData['port']) ? ':'.$urlData['port'] : ''; + $updatedUrl = $urlData['scheme'].'://'.$urlData['host'].$port.$urlData['path'].'?'.http_build_query($urlQueryData); } else { $updatedUrl = $url; } @@ -1872,8 +1871,8 @@ class TCPDF_STATIC { * Wrapper for file_exists. * Checks whether a file or directory exists. * Only allows some protocols and local files. - * @param filename (string) Path to the file or directory. - * @return Returns TRUE if the file or directory specified by filename exists; FALSE otherwise. + * @param string $filename Path to the file or directory. + * @return bool Returns TRUE if the file or directory specified by filename exists; FALSE otherwise. * @public static */ public static function file_exists($filename) { @@ -1889,8 +1888,8 @@ class TCPDF_STATIC { /** * Reads entire file into a string. * The file can be also an URL. - * @param $file (string) Name of the file or URL to read. - * @return The function returns the read data or FALSE on failure. + * @param string $file Name of the file or URL to read. + * @return string|false The function returns the read data or FALSE on failure. * @author Nicola Asuni * @since 6.0.025 * @public static @@ -1962,7 +1961,6 @@ class TCPDF_STATIC { // try to get remote file data using cURL $crs = curl_init(); curl_setopt($crs, CURLOPT_URL, $path); - curl_setopt($crs, CURLOPT_BINARYTRANSFER, true); curl_setopt($crs, CURLOPT_FAILONERROR, true); curl_setopt($crs, CURLOPT_RETURNTRANSFER, true); if ((ini_get('open_basedir') == '') && (!ini_get('safe_mode'))) { @@ -1973,6 +1971,10 @@ class TCPDF_STATIC { curl_setopt($crs, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($crs, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($crs, CURLOPT_USERAGENT, 'tc-lib-file'); + curl_setopt($crs, CURLOPT_MAXREDIRS, 5); + if (defined('CURLOPT_PROTOCOLS')) { + curl_setopt($crs, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP | CURLPROTO_FTP | CURLPROTO_FTPS); + } $ret = curl_exec($crs); curl_close($crs); if ($ret !== false) { @@ -1985,8 +1987,8 @@ class TCPDF_STATIC { /** * Get ULONG from string (Big Endian 32-bit unsigned integer). - * @param $str (string) string from where to extract value - * @param $offset (int) point from where to read the data + * @param string $str string from where to extract value + * @param int $offset point from where to read the data * @return int 32 bit value * @author Nicola Asuni * @since 5.2.000 (2010-06-02) @@ -1999,8 +2001,8 @@ class TCPDF_STATIC { /** * Get USHORT from string (Big Endian 16-bit unsigned integer). - * @param $str (string) string from where to extract value - * @param $offset (int) point from where to read the data + * @param string $str string from where to extract value + * @param int $offset point from where to read the data * @return int 16 bit value * @author Nicola Asuni * @since 5.2.000 (2010-06-02) @@ -2013,8 +2015,8 @@ class TCPDF_STATIC { /** * Get SHORT from string (Big Endian 16-bit signed integer). - * @param $str (string) String from where to extract value. - * @param $offset (int) Point from where to read the data. + * @param string $str String from where to extract value. + * @param int $offset Point from where to read the data. * @return int 16 bit value * @author Nicola Asuni * @since 5.2.000 (2010-06-02) @@ -2027,8 +2029,8 @@ class TCPDF_STATIC { /** * Get FWORD from string (Big Endian 16-bit signed integer). - * @param $str (string) String from where to extract value. - * @param $offset (int) Point from where to read the data. + * @param string $str String from where to extract value. + * @param int $offset Point from where to read the data. * @return int 16 bit value * @author Nicola Asuni * @since 5.9.123 (2011-09-30) @@ -2044,8 +2046,8 @@ class TCPDF_STATIC { /** * Get UFWORD from string (Big Endian 16-bit unsigned integer). - * @param $str (string) string from where to extract value - * @param $offset (int) point from where to read the data + * @param string $str string from where to extract value + * @param int $offset point from where to read the data * @return int 16 bit value * @author Nicola Asuni * @since 5.9.123 (2011-09-30) @@ -2058,8 +2060,8 @@ class TCPDF_STATIC { /** * Get FIXED from string (32-bit signed fixed-point number (16.16). - * @param $str (string) string from where to extract value - * @param $offset (int) point from where to read the data + * @param string $str string from where to extract value + * @param int $offset point from where to read the data * @return int 16 bit value * @author Nicola Asuni * @since 5.9.123 (2011-09-30) @@ -2076,8 +2078,8 @@ class TCPDF_STATIC { /** * Get BYTE from string (8-bit unsigned integer). - * @param $str (string) String from where to extract value. - * @param $offset (int) Point from where to read the data. + * @param string $str String from where to extract value. + * @param int $offset Point from where to read the data. * @return int 8 bit value * @author Nicola Asuni * @since 5.2.000 (2010-06-02) @@ -2090,9 +2092,9 @@ class TCPDF_STATIC { /** * Binary-safe and URL-safe file read. * Reads up to length bytes from the file pointer referenced by handle. Reading stops as soon as one of the following conditions is met: length bytes have been read; EOF (end of file) is reached. - * @param $handle (resource) - * @param $length (int) - * @return Returns the read string or FALSE in case of error. + * @param resource $handle + * @param int $length + * @return string|false Returns the read string or FALSE in case of error. * @author Nicola Asuni * @since 4.5.027 (2009-03-16) * @public static @@ -2111,8 +2113,8 @@ class TCPDF_STATIC { /** * Read a 4-byte (32 bit) integer from file. - * @param $f (string) file name. - * @return 4-byte integer + * @param resource $f file resource. + * @return int 4-byte integer * @public static */ public static function _freadint($f) { @@ -2120,11 +2122,12 @@ class TCPDF_STATIC { return $a['i']; } - /** * Array of page formats * measures are calculated in this way: (inches * 72) or (millimeters * 72 / 25.4) * @public static + * + * @var array */ public static $page_formats = array( // ISO 216 A Series + 2 SIS 014711 extensions @@ -2480,7 +2483,7 @@ class TCPDF_STATIC { /** * Get page dimensions from format name. - * @param $format (mixed) The format name @see self::$page_format
      + * @param mixed $format The format name @see self::$page_format
        * @return array containing page width and height in points * @since 5.0.010 (2010-05-17) * @public static @@ -2494,20 +2497,20 @@ class TCPDF_STATIC { /** * Set page boundaries. - * @param $page (int) page number - * @param $type (string) valid values are:
        • 'MediaBox' : the boundaries of the physical medium on which the page shall be displayed or printed;
        • 'CropBox' : the visible region of default user space;
        • 'BleedBox' : the region to which the contents of the page shall be clipped when output in a production environment;
        • 'TrimBox' : the intended dimensions of the finished page after trimming;
        • 'ArtBox' : the page's meaningful content (including potential white space).
        - * @param $llx (float) lower-left x coordinate in user units. - * @param $lly (float) lower-left y coordinate in user units. - * @param $urx (float) upper-right x coordinate in user units. - * @param $ury (float) upper-right y coordinate in user units. - * @param $points (boolean) If true uses user units as unit of measure, otherwise uses PDF points. - * @param $k (float) Scale factor (number of points in user unit). - * @param $pagedim (array) Array of page dimensions. - * @return pagedim array of page dimensions. + * @param int $page page number + * @param string $type valid values are:
        • 'MediaBox' : the boundaries of the physical medium on which the page shall be displayed or printed;
        • 'CropBox' : the visible region of default user space;
        • 'BleedBox' : the region to which the contents of the page shall be clipped when output in a production environment;
        • 'TrimBox' : the intended dimensions of the finished page after trimming;
        • 'ArtBox' : the page's meaningful content (including potential white space).
        + * @param float $llx lower-left x coordinate in user units. + * @param float $lly lower-left y coordinate in user units. + * @param float $urx upper-right x coordinate in user units. + * @param float $ury upper-right y coordinate in user units. + * @param boolean $points If true uses user units as unit of measure, otherwise uses PDF points. + * @param float $k Scale factor (number of points in user unit). + * @param array $pagedim Array of page dimensions. + * @return array pagedim array of page dimensions. * @since 5.0.010 (2010-05-17) * @public static */ - public static function setPageBoxes($page, $type, $llx, $lly, $urx, $ury, $points=false, $k, $pagedim=array()) { + public static function setPageBoxes($page, $type, $llx, $lly, $urx, $ury, $points, $k, $pagedim=array()) { if (!isset($pagedim[$page])) { // initialize array $pagedim[$page] = array(); @@ -2527,9 +2530,9 @@ class TCPDF_STATIC { /** * Swap X and Y coordinates of page boxes (change page boxes orientation). - * @param $page (int) page number - * @param $pagedim (array) Array of page dimensions. - * @return pagedim array of page dimensions. + * @param int $page page number + * @param array $pagedim Array of page dimensions. + * @return array pagedim array of page dimensions. * @since 5.0.010 (2010-05-17) * @public static */ @@ -2550,8 +2553,8 @@ class TCPDF_STATIC { /** * Get the canonical page layout mode. - * @param $layout (string) The page layout. Possible values are:
        • SinglePage Display one page at a time
        • OneColumn Display the pages in one column
        • TwoColumnLeft Display the pages in two columns, with odd-numbered pages on the left
        • TwoColumnRight Display the pages in two columns, with odd-numbered pages on the right
        • TwoPageLeft (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the left
        • TwoPageRight (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the right
        - * @return (string) Canonical page layout name. + * @param string $layout The page layout. Possible values are:
        • SinglePage Display one page at a time
        • OneColumn Display the pages in one column
        • TwoColumnLeft Display the pages in two columns, with odd-numbered pages on the left
        • TwoColumnRight Display the pages in two columns, with odd-numbered pages on the right
        • TwoPageLeft (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the left
        • TwoPageRight (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the right
        + * @return string Canonical page layout name. * @public static */ public static function getPageLayoutMode($layout='SinglePage') { @@ -2593,8 +2596,8 @@ class TCPDF_STATIC { /** * Get the canonical page layout mode. - * @param $mode (string) A name object specifying how the document should be displayed when opened:
        • UseNone Neither document outline nor thumbnail images visible
        • UseOutlines Document outline visible
        • UseThumbs Thumbnail images visible
        • FullScreen Full-screen mode, with no menu bar, window controls, or any other window visible
        • UseOC (PDF 1.5) Optional content group panel visible
        • UseAttachments (PDF 1.6) Attachments panel visible
        - * @return (string) Canonical page mode name. + * @param string $mode A name object specifying how the document should be displayed when opened:
        • UseNone Neither document outline nor thumbnail images visible
        • UseOutlines Document outline visible
        • UseThumbs Thumbnail images visible
        • FullScreen Full-screen mode, with no menu bar, window controls, or any other window visible
        • UseOC (PDF 1.5) Optional content group panel visible
        • UseAttachments (PDF 1.6) Attachments panel visible
        + * @return string Canonical page mode name. * @public static */ public static function getPageMode($mode='UseNone') { diff --git a/tools/tcpdf/index.php b/tools/tcpdf/index.php deleted file mode 100644 index aca71cfae..000000000 --- a/tools/tcpdf/index.php +++ /dev/null @@ -1,35 +0,0 @@ - -* @copyright 2007-2017 PrestaShop SA -* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) -* International Registered Trademark & Property of PrestaShop SA -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../'); -exit; diff --git a/tools/tcpdf/tcpdf.php b/tools/tcpdf/tcpdf.php index 8b7d81223..3404c52b3 100644 --- a/tools/tcpdf/tcpdf.php +++ b/tools/tcpdf/tcpdf.php @@ -1,13 +1,13 @@ * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 6.3.2 + * @version 6.7.8 */ // TCPDF configuration @@ -128,7 +128,7 @@ require_once(dirname(__FILE__).'/include/tcpdf_static.php'); * TCPDF project (http://www.tcpdf.org) has been originally derived in 2002 from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org), but now is almost entirely rewritten.
        * @package com.tecnick.tcpdf * @brief PHP class for generating PDF documents without requiring external extensions. - * @version 6.3.2 + * @version 6.7.8 * @author Nicola Asuni - info@tecnick.com * @IgnoreAnnotation("protected") * @IgnoreAnnotation("public") @@ -574,12 +574,14 @@ class TCPDF { /** * Minimum distance between header and top page margin. * @protected + * @var float */ protected $header_margin; /** * Minimum distance between footer and bottom page margin. * @protected + * @var float */ protected $footer_margin; @@ -600,12 +602,16 @@ class TCPDF { /** * Default font used on page header. * @protected + * @var array + * @phpstan-var array{0: string, 1: string, 2: float|null} */ protected $header_font; /** * Default font used on page footer. * @protected + * @var array + * @phpstan-var array{0: string, 1: string, 2: float|null} */ protected $footer_font; @@ -652,7 +658,7 @@ class TCPDF { protected $header_title = ''; /** - * String to pring on page header after title. + * String to print on page header after title. * @protected */ protected $header_string = ''; @@ -661,6 +667,8 @@ class TCPDF { * Color for header text (RGB array). * @since 5.9.174 (2012-07-25) * @protected + * @var int[] + * @phpstan-var array{0: int, 1: int, 2: int} */ protected $header_text_color = array(0,0,0); @@ -668,6 +676,8 @@ class TCPDF { * Color for header line (RGB array). * @since 5.9.174 (2012-07-25) * @protected + * @var int[] + * @phpstan-var array{0: int, 1: int, 2: int} */ protected $header_line_color = array(0,0,0); @@ -675,6 +685,8 @@ class TCPDF { * Color for footer text (RGB array). * @since 5.9.174 (2012-07-25) * @protected + * @var int[] + * @phpstan-var array{0: int, 1: int, 2: int} */ protected $footer_text_color = array(0,0,0); @@ -682,6 +694,8 @@ class TCPDF { * Color for footer line (RGB array). * @since 5.9.174 (2012-07-25) * @protected + * @var int[] + * @phpstan-var array{0: int, 1: int, 2: int} */ protected $footer_line_color = array(0,0,0); @@ -773,13 +787,6 @@ class TCPDF { */ protected $encoding = 'UTF-8'; - /** - * PHP internal encoding. - * @protected - * @since 1.53.0.TC016 - */ - protected $internal_encoding; - /** * Boolean flag to indicate if the document language is Right-To-Left. * @protected @@ -831,6 +838,13 @@ class TCPDF { */ protected $file_id; + /** + * Internal secret used to encrypt data. + * @protected + * @since 6.7.5 (2024-03-21) + */ + protected $hash_key; + // --- bookmark --- /** @@ -923,6 +937,7 @@ class TCPDF { * Default cell height ratio. * @protected * @since 3.0.014 (2008-05-23) + * @var float */ protected $cell_height_ratio = K_CELL_HEIGHT_RATIO; @@ -1800,6 +1815,7 @@ class TCPDF { * (Check the "Entries in a Graphics State Parameter Dictionary" on PDF 32000-1:2008). * @protected * @since 5.9.152 (2012-03-23) + * @var array */ protected $overprint = array('OP' => false, 'op' => false, 'OPM' => 0); @@ -1832,6 +1848,23 @@ class TCPDF { */ protected $gdgammacache = array(); + /** + * Cache array for file content + * @protected + * @var array + * @since 6.3.5 (2020-09-28) + */ + protected $fileContentCache = array(); + + /** + * Whether to allow local file path in image html tags, when prefixed with file:// + * + * @var bool + * @protected + * @since 6.4 (2020-07-23) + */ + protected $allowLocalFiles = false; + //------------------------------------------------------------ // METHODS //------------------------------------------------------------ @@ -1840,31 +1873,24 @@ class TCPDF { * This is the class constructor. * It allows to set up the page format, the orientation and the measure unit used in all the methods (except for the font sizes). * - * IMPORTANT: Please note that this method sets the mb_internal_encoding to ASCII, so if you are using the mbstring module functions with TCPDF you need to correctly set/unset the mb_internal_encoding when needed. - * - * @param $orientation (string) page orientation. Possible values are (case insensitive):
        • P or Portrait (default)
        • L or Landscape
        • '' (empty string) for automatic orientation
        - * @param $unit (string) User measure unit. Possible values are:
        • pt: point
        • mm: millimeter (default)
        • cm: centimeter
        • in: inch

        A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This is a very common unit in typography; font sizes are expressed in that unit. - * @param $format (mixed) The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat(). - * @param $unicode (boolean) TRUE means that the input text is unicode (default = true) - * @param $encoding (string) Charset encoding (used only when converting back html entities); default is UTF-8. - * @param $diskcache (boolean) DEPRECATED FEATURE - * @param $pdfa (integer) If not false, set the document to PDF/A mode and the good version (1 or 3). + * @param string $orientation page orientation. Possible values are (case insensitive):
        • P or Portrait (default)
        • L or Landscape
        • '' (empty string) for automatic orientation
        + * @param string $unit User measure unit. Possible values are:
        • pt: point
        • mm: millimeter (default)
        • cm: centimeter
        • in: inch

        A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This is a very common unit in typography; font sizes are expressed in that unit. + * @param mixed $format The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat(). + * @param boolean $unicode TRUE means that the input text is unicode (default = true) + * @param string $encoding Charset encoding (used only when converting back html entities); default is UTF-8. + * @param boolean $diskcache DEPRECATED FEATURE + * @param false|integer $pdfa If not false, set the document to PDF/A mode and the good version (1 or 3). * @public * @see getPageSizeFromFormat(), setPageFormat() */ public function __construct($orientation='P', $unit='mm', $format='A4', $unicode=true, $encoding='UTF-8', $diskcache=false, $pdfa=false) { - /* Set internal character encoding to ASCII */ - if (function_exists('mb_internal_encoding') AND mb_internal_encoding()) { - $this->internal_encoding = mb_internal_encoding(); - mb_internal_encoding('ASCII'); - } // set file ID for trailer $serformat = (is_array($format) ? json_encode($format) : $format); $this->file_id = md5(TCPDF_STATIC::getRandomSeed('TCPDF'.$orientation.$unit.$serformat.$encoding)); + $this->hash_key = hash_hmac('sha256', TCPDF_STATIC::getRandomSeed($this->file_id), TCPDF_STATIC::getRandomSeed('TCPDF'), false); $this->font_obj_ids = array(); $this->page_obj_id = array(); $this->form_obj_id = array(); - // set pdf/a mode if ($pdfa != false) { $this->pdfa_mode = true; @@ -1932,7 +1958,7 @@ class TCPDF { $this->setPageFormat($format, $orientation); // page margins (1 cm) $margin = 28.35 / $this->k; - $this->SetMargins($margin, $margin); + $this->setMargins($margin, $margin); $this->clMargin = $this->lMargin; $this->crMargin = $this->rMargin; // internal cell padding @@ -1947,11 +1973,11 @@ class TCPDF { $this->linestyleJoin = '0 j'; $this->linestyleDash = '[] 0 d'; // automatic page break - $this->SetAutoPageBreak(true, (2 * $margin)); + $this->setAutoPageBreak(true, (2 * $margin)); // full width display mode - $this->SetDisplayMode('fullwidth'); + $this->setDisplayMode('fullwidth'); // compression - $this->SetCompression(); + $this->setCompression(); // set default PDF version number $this->setPDFVersion(); $this->tcpdflink = true; @@ -1982,7 +2008,7 @@ class TCPDF { // initialize some settings TCPDF_FONTS::utf8Bidi(array(), '', false, $this->isunicode, $this->CurrentFont); // set default font - $this->SetFont($this->FontFamily, $this->FontStyle, $this->FontSizePt); + $this->setFont($this->FontFamily, $this->FontStyle, $this->FontSizePt); $this->setHeaderFont(array($this->FontFamily, $this->FontStyle, $this->FontSizePt)); $this->setFooterFont(array($this->FontFamily, $this->FontStyle, $this->FontSizePt)); // check if PCRE Unicode support is enabled @@ -2007,9 +2033,6 @@ class TCPDF { $this->header_xobj_autoreset = false; $this->custom_xmp = ''; $this->custom_xmp_rdf = ''; - // Call cleanup method after script execution finishes or exit() is called. - // NOTE: This will not be executed if the process is killed with a SIGTERM or SIGKILL signal. - register_shutdown_function(array($this, '_destroy'), true); } /** @@ -2024,7 +2047,7 @@ class TCPDF { /** * Set the units of measure for the document. - * @param $unit (string) User measure unit. Possible values are:
        • pt: point
        • mm: millimeter (default)
        • cm: centimeter
        • in: inch

        A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This is a very common unit in typography; font sizes are expressed in that unit. + * @param string $unit User measure unit. Possible values are:
        • pt: point
        • mm: millimeter (default)
        • cm: centimeter
        • in: inch

        A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This is a very common unit in typography; font sizes are expressed in that unit. * @public * @since 3.0.015 (2008-06-06) */ @@ -2067,7 +2090,7 @@ class TCPDF { /** * Change the format of the current page - * @param $format (mixed) The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() documentation or an array of two numbers (width, height) or an array containing the following measures and options:
          + * @param mixed $format The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() documentation or an array of two numbers (width, height) or an array containing the following measures and options:
            *
          • ['format'] = page format name (one of the above);
          • *
          • ['Rotate'] : The number of degrees by which the page shall be rotated clockwise when displayed or printed. The value shall be a multiple of 90.
          • *
          • ['PZ'] : The page's preferred zoom (magnification) factor.
          • @@ -2111,7 +2134,7 @@ class TCPDF { *
          • ['trans']['SS'] : (Fly transition style only) The starting or ending scale at which the changes shall be drawn. If M specifies an inward transition, the scale of the changes drawn shall progress from SS to 1.0 over the course of the transition. If M specifies an outward transition, the scale of the changes drawn shall progress from 1.0 to SS over the course of the transition. Default: 1.0.
          • *
          • ['trans']['B'] : (Fly transition style only) If true, the area that shall be flown in is rectangular and opaque. Default: false.
          • *
          - * @param $orientation (string) page orientation. Possible values are (case insensitive):
            + * @param string $orientation page orientation. Possible values are (case insensitive):
              *
            • P or Portrait (default)
            • *
            • L or Landscape
            • *
            • '' (empty string) for automatic orientation
            • @@ -2228,13 +2251,13 @@ class TCPDF { /** * Set page orientation. - * @param $orientation (string) page orientation. Possible values are (case insensitive):
              • P or Portrait (default)
              • L or Landscape
              • '' (empty string) for automatic orientation
              - * @param $autopagebreak (boolean) Boolean indicating if auto-page-break mode should be on or off. - * @param $bottommargin (float) bottom margin of the page. + * @param string $orientation page orientation. Possible values are (case insensitive):
              • P or Portrait (default)
              • L or Landscape
              • '' (empty string) for automatic orientation
              + * @param boolean|null $autopagebreak Boolean indicating if auto-page-break mode should be on or off. + * @param float|null $bottommargin bottom margin of the page. * @public * @since 3.0.015 (2008-06-06) */ - public function setPageOrientation($orientation, $autopagebreak='', $bottommargin='') { + public function setPageOrientation($orientation, $autopagebreak=null, $bottommargin=null) { if (!isset($this->pagedim[$this->page]['MediaBox'])) { // the boundaries of the physical medium on which the page shall be displayed or printed $this->pagedim = TCPDF_STATIC::setPageBoxes($this->page, 'MediaBox', 0, 0, $this->fwPt, $this->fhPt, true, $this->k, $this->pagedim); @@ -2306,7 +2329,7 @@ class TCPDF { $bottommargin = 2 * 28.35 / $this->k; } } - $this->SetAutoPageBreak($autopagebreak, $bottommargin); + $this->setAutoPageBreak($autopagebreak, $bottommargin); // store page dimensions $this->pagedim[$this->page]['w'] = $this->wPt; $this->pagedim[$this->page]['h'] = $this->hPt; @@ -2336,7 +2359,7 @@ class TCPDF { * \p{Lo} : Unicode letter or ideograph that does not have lowercase and uppercase variants. Is used to chunk chinese words. * \xa0 : Unicode Character 'NO-BREAK SPACE' (U+00A0) * - * @param $re (string) regular expression (leave empty for default). + * @param string $re regular expression (leave empty for default). * @public * @since 4.6.016 (2009-06-15) */ @@ -2360,8 +2383,8 @@ class TCPDF { /** * Enable or disable Right-To-Left language mode - * @param $enable (Boolean) if true enable Right-To-Left language mode. - * @param $resetx (Boolean) if true reset the X position on direction change. + * @param boolean $enable if true enable Right-To-Left language mode. + * @param boolean $resetx if true reset the X position on direction change. * @public * @since 2.0.000 (2008-01-03) */ @@ -2377,7 +2400,7 @@ class TCPDF { /** * Return the RTL status - * @return boolean + * @return bool * @public * @since 4.0.012 (2008-07-24) */ @@ -2387,7 +2410,7 @@ class TCPDF { /** * Force temporary RTL language direction - * @param $mode (mixed) can be false, 'L' for LTR or 'R' for RTL + * @param false|string $mode can be false, 'L' for LTR or 'R' for RTL * @public * @since 2.1.000 (2008-01-09) */ @@ -2419,7 +2442,7 @@ class TCPDF { /** * Return the current temporary RTL status - * @return boolean + * @return bool * @public * @since 4.8.014 (2009-11-04) */ @@ -2429,7 +2452,7 @@ class TCPDF { /** * Set the last cell height. - * @param $h (float) cell height. + * @param float $h cell height. * @author Nicola Asuni * @public * @since 1.53.0.TC034 @@ -2440,13 +2463,14 @@ class TCPDF { /** * Return the cell height - * @param $fontsize (int) Font size in internal units - * @param $padding (boolean) If true add cell padding + * @param int $fontsize Font size in internal units + * @param boolean $padding If true add cell padding * @public + * @return float */ public function getCellHeight($fontsize, $padding=TRUE) { $height = ($fontsize * $this->cell_height_ratio); - if ($padding) { + if ($padding && !empty($this->cell_padding)) { $height += ($this->cell_padding['T'] + $this->cell_padding['B']); } return round($height, 6); @@ -2463,7 +2487,7 @@ class TCPDF { /** * Get the last cell height. - * @return last cell height + * @return float last cell height * @public * @since 4.0.017 (2008-08-05) */ @@ -2473,7 +2497,7 @@ class TCPDF { /** * Set the adjusting factor to convert pixels to user units. - * @param $scale (float) adjusting factor to convert pixels to user units. + * @param float $scale adjusting factor to convert pixels to user units. * @author Nicola Asuni * @public * @since 1.5.2 @@ -2496,13 +2520,13 @@ class TCPDF { /** * Returns an array of page dimensions: *
              • $this->pagedim[$this->page]['w'] = page width in points
              • $this->pagedim[$this->page]['h'] = height in points
              • $this->pagedim[$this->page]['wk'] = page width in user units
              • $this->pagedim[$this->page]['hk'] = page height in user units
              • $this->pagedim[$this->page]['tm'] = top margin
              • $this->pagedim[$this->page]['bm'] = bottom margin
              • $this->pagedim[$this->page]['lm'] = left margin
              • $this->pagedim[$this->page]['rm'] = right margin
              • $this->pagedim[$this->page]['pb'] = auto page break
              • $this->pagedim[$this->page]['or'] = page orientation
              • $this->pagedim[$this->page]['olm'] = original left margin
              • $this->pagedim[$this->page]['orm'] = original right margin
              • $this->pagedim[$this->page]['Rotate'] = The number of degrees by which the page shall be rotated clockwise when displayed or printed. The value shall be a multiple of 90.
              • $this->pagedim[$this->page]['PZ'] = The page's preferred zoom (magnification) factor.
              • $this->pagedim[$this->page]['trans'] : the style and duration of the visual transition to use when moving from another page to the given page during a presentation
                • $this->pagedim[$this->page]['trans']['Dur'] = The page's display duration (also called its advance timing): the maximum length of time, in seconds, that the page shall be displayed during presentations before the viewer application shall automatically advance to the next page.
                • $this->pagedim[$this->page]['trans']['S'] = transition style : Split, Blinds, Box, Wipe, Dissolve, Glitter, R, Fly, Push, Cover, Uncover, Fade
                • $this->pagedim[$this->page]['trans']['D'] = The duration of the transition effect, in seconds.
                • $this->pagedim[$this->page]['trans']['Dm'] = (Split and Blinds transition styles only) The dimension in which the specified transition effect shall occur: H = Horizontal, V = Vertical. Default value: H.
                • $this->pagedim[$this->page]['trans']['M'] = (Split, Box and Fly transition styles only) The direction of motion for the specified transition effect: I = Inward from the edges of the page, O = Outward from the center of the pageDefault value: I.
                • $this->pagedim[$this->page]['trans']['Di'] = (Wipe, Glitter, Fly, Cover, Uncover and Push transition styles only) The direction in which the specified transition effect shall moves, expressed in degrees counterclockwise starting from a left-to-right direction. If the value is a number, it shall be one of: 0 = Left to right, 90 = Bottom to top (Wipe only), 180 = Right to left (Wipe only), 270 = Top to bottom, 315 = Top-left to bottom-right (Glitter only). If the value is a name, it shall be None, which is relevant only for the Fly transition when the value of SS is not 1.0. Default value: 0.
                • $this->pagedim[$this->page]['trans']['SS'] = (Fly transition style only) The starting or ending scale at which the changes shall be drawn. If M specifies an inward transition, the scale of the changes drawn shall progress from SS to 1.0 over the course of the transition. If M specifies an outward transition, the scale of the changes drawn shall progress from 1.0 to SS over the course of the transition. Default: 1.0.
                • $this->pagedim[$this->page]['trans']['B'] = (Fly transition style only) If true, the area that shall be flown in is rectangular and opaque. Default: false.
              • $this->pagedim[$this->page]['MediaBox'] : the boundaries of the physical medium on which the page shall be displayed or printed
                • $this->pagedim[$this->page]['MediaBox']['llx'] = lower-left x coordinate in points
                • $this->pagedim[$this->page]['MediaBox']['lly'] = lower-left y coordinate in points
                • $this->pagedim[$this->page]['MediaBox']['urx'] = upper-right x coordinate in points
                • $this->pagedim[$this->page]['MediaBox']['ury'] = upper-right y coordinate in points
              • $this->pagedim[$this->page]['CropBox'] : the visible region of default user space
                • $this->pagedim[$this->page]['CropBox']['llx'] = lower-left x coordinate in points
                • $this->pagedim[$this->page]['CropBox']['lly'] = lower-left y coordinate in points
                • $this->pagedim[$this->page]['CropBox']['urx'] = upper-right x coordinate in points
                • $this->pagedim[$this->page]['CropBox']['ury'] = upper-right y coordinate in points
              • $this->pagedim[$this->page]['BleedBox'] : the region to which the contents of the page shall be clipped when output in a production environment
                • $this->pagedim[$this->page]['BleedBox']['llx'] = lower-left x coordinate in points
                • $this->pagedim[$this->page]['BleedBox']['lly'] = lower-left y coordinate in points
                • $this->pagedim[$this->page]['BleedBox']['urx'] = upper-right x coordinate in points
                • $this->pagedim[$this->page]['BleedBox']['ury'] = upper-right y coordinate in points
              • $this->pagedim[$this->page]['TrimBox'] : the intended dimensions of the finished page after trimming
                • $this->pagedim[$this->page]['TrimBox']['llx'] = lower-left x coordinate in points
                • $this->pagedim[$this->page]['TrimBox']['lly'] = lower-left y coordinate in points
                • $this->pagedim[$this->page]['TrimBox']['urx'] = upper-right x coordinate in points
                • $this->pagedim[$this->page]['TrimBox']['ury'] = upper-right y coordinate in points
              • $this->pagedim[$this->page]['ArtBox'] : the extent of the page's meaningful content
                • $this->pagedim[$this->page]['ArtBox']['llx'] = lower-left x coordinate in points
                • $this->pagedim[$this->page]['ArtBox']['lly'] = lower-left y coordinate in points
                • $this->pagedim[$this->page]['ArtBox']['urx'] = upper-right x coordinate in points
                • $this->pagedim[$this->page]['ArtBox']['ury'] = upper-right y coordinate in points
              - * @param $pagenum (int) page number (empty = current page) + * @param int|null $pagenum page number (empty = current page) * @return array of page dimensions. * @author Nicola Asuni * @public * @since 4.5.027 (2009-03-16) */ - public function getPageDimensions($pagenum='') { + public function getPageDimensions($pagenum=null) { if (empty($pagenum)) { $pagenum = $this->page; } @@ -2511,14 +2535,14 @@ class TCPDF { /** * Returns the page width in units. - * @param $pagenum (int) page number (empty = current page) - * @return int page width. + * @param int|null $pagenum page number (empty = current page) + * @return int|float page width. * @author Nicola Asuni * @public * @since 1.5.2 * @see getPageDimensions() */ - public function getPageWidth($pagenum='') { + public function getPageWidth($pagenum=null) { if (empty($pagenum)) { return $this->w; } @@ -2527,14 +2551,14 @@ class TCPDF { /** * Returns the page height in units. - * @param $pagenum (int) page number (empty = current page) - * @return int page height. + * @param int|null $pagenum page number (empty = current page) + * @return int|float page height. * @author Nicola Asuni * @public * @since 1.5.2 * @see getPageDimensions() */ - public function getPageHeight($pagenum='') { + public function getPageHeight($pagenum=null) { if (empty($pagenum)) { return $this->h; } @@ -2543,14 +2567,14 @@ class TCPDF { /** * Returns the page break margin. - * @param $pagenum (int) page number (empty = current page) - * @return int page break margin. + * @param int|null $pagenum page number (empty = current page) + * @return int|float page break margin. * @author Nicola Asuni * @public * @since 1.5.2 * @see getPageDimensions() */ - public function getBreakMargin($pagenum='') { + public function getBreakMargin($pagenum=null) { if (empty($pagenum)) { return $this->bMargin; } @@ -2570,19 +2594,19 @@ class TCPDF { /** * Defines the left, top and right margins. - * @param $left (float) Left margin. - * @param $top (float) Top margin. - * @param $right (float) Right margin. Default value is the left one. - * @param $keepmargins (boolean) if true overwrites the default page margins + * @param int|float $left Left margin. + * @param int|float $top Top margin. + * @param int|float|null $right Right margin. Default value is the left one. + * @param boolean $keepmargins if true overwrites the default page margins * @public * @since 1.0 * @see SetLeftMargin(), SetTopMargin(), SetRightMargin(), SetAutoPageBreak() */ - public function SetMargins($left, $top, $right=-1, $keepmargins=false) { + public function setMargins($left, $top, $right=null, $keepmargins=false) { //Set left, top and right margins $this->lMargin = $left; $this->tMargin = $top; - if ($right == -1) { + if ($right == -1 OR $right === null) { $right = $left; } $this->rMargin = $right; @@ -2595,12 +2619,12 @@ class TCPDF { /** * Defines the left margin. The method can be called before creating the first page. If the current abscissa gets out of page, it is brought back to the margin. - * @param $margin (float) The margin. + * @param int|float $margin The margin. * @public * @since 1.4 * @see SetTopMargin(), SetRightMargin(), SetAutoPageBreak(), SetMargins() */ - public function SetLeftMargin($margin) { + public function setLeftMargin($margin) { //Set left margin $this->lMargin = $margin; if (($this->page > 0) AND ($this->x < $margin)) { @@ -2610,12 +2634,12 @@ class TCPDF { /** * Defines the top margin. The method can be called before creating the first page. - * @param $margin (float) The margin. + * @param int|float $margin The margin. * @public * @since 1.5 * @see SetLeftMargin(), SetRightMargin(), SetAutoPageBreak(), SetMargins() */ - public function SetTopMargin($margin) { + public function setTopMargin($margin) { //Set top margin $this->tMargin = $margin; if (($this->page > 0) AND ($this->y < $margin)) { @@ -2625,12 +2649,12 @@ class TCPDF { /** * Defines the right margin. The method can be called before creating the first page. - * @param $margin (float) The margin. + * @param int|float $margin The margin. * @public * @since 1.5 * @see SetLeftMargin(), SetTopMargin(), SetAutoPageBreak(), SetMargins() */ - public function SetRightMargin($margin) { + public function setRightMargin($margin) { $this->rMargin = $margin; if (($this->page > 0) AND ($this->x > ($this->w - $margin))) { $this->x = $this->w - $margin; @@ -2639,12 +2663,12 @@ class TCPDF { /** * Set the same internal Cell padding for top, right, bottom, left- - * @param $pad (float) internal padding. + * @param int|float $pad internal padding. * @public * @since 2.1.000 (2008-01-09) * @see getCellPaddings(), setCellPaddings() */ - public function SetCellPadding($pad) { + public function setCellPadding($pad) { if ($pad >= 0) { $this->cell_padding['L'] = $pad; $this->cell_padding['T'] = $pad; @@ -2655,25 +2679,25 @@ class TCPDF { /** * Set the internal Cell paddings. - * @param $left (float) left padding - * @param $top (float) top padding - * @param $right (float) right padding - * @param $bottom (float) bottom padding + * @param int|float|null $left left padding + * @param int|float|null $top top padding + * @param int|float|null $right right padding + * @param int|float|null $bottom bottom padding * @public * @since 5.9.000 (2010-10-03) * @see getCellPaddings(), SetCellPadding() */ - public function setCellPaddings($left='', $top='', $right='', $bottom='') { - if (($left !== '') AND ($left >= 0)) { + public function setCellPaddings($left=null, $top=null, $right=null, $bottom=null) { + if (!TCPDF_STATIC::empty_string($left) AND ($left >= 0)) { $this->cell_padding['L'] = $left; } - if (($top !== '') AND ($top >= 0)) { + if (!TCPDF_STATIC::empty_string($top) AND ($top >= 0)) { $this->cell_padding['T'] = $top; } - if (($right !== '') AND ($right >= 0)) { + if (!TCPDF_STATIC::empty_string($right) AND ($right >= 0)) { $this->cell_padding['R'] = $right; } - if (($bottom !== '') AND ($bottom >= 0)) { + if (!TCPDF_STATIC::empty_string($bottom) AND ($bottom >= 0)) { $this->cell_padding['B'] = $bottom; } } @@ -2691,25 +2715,25 @@ class TCPDF { /** * Set the internal Cell margins. - * @param $left (float) left margin - * @param $top (float) top margin - * @param $right (float) right margin - * @param $bottom (float) bottom margin + * @param int|float|null $left left margin + * @param int|float|null $top top margin + * @param int|float|null $right right margin + * @param int|float|null $bottom bottom margin * @public * @since 5.9.000 (2010-10-03) * @see getCellMargins() */ - public function setCellMargins($left='', $top='', $right='', $bottom='') { - if (($left !== '') AND ($left >= 0)) { + public function setCellMargins($left=null, $top=null, $right=null, $bottom=null) { + if (!TCPDF_STATIC::empty_string($left) AND ($left >= 0)) { $this->cell_margin['L'] = $left; } - if (($top !== '') AND ($top >= 0)) { + if (!TCPDF_STATIC::empty_string($top) AND ($top >= 0)) { $this->cell_margin['T'] = $top; } - if (($right !== '') AND ($right >= 0)) { + if (!TCPDF_STATIC::empty_string($right) AND ($right >= 0)) { $this->cell_margin['R'] = $right; } - if (($bottom !== '') AND ($bottom >= 0)) { + if (!TCPDF_STATIC::empty_string($bottom) AND ($bottom >= 0)) { $this->cell_margin['B'] = $bottom; } } @@ -2727,8 +2751,8 @@ class TCPDF { /** * Adjust the internal Cell padding array to take account of the line width. - * @param $brd (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) - * @return array of adjustments + * @param string|array|int|bool $brd Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) + * @return void|array array of adjustments * @public * @since 5.9.000 (2010-10-03) */ @@ -2744,7 +2768,11 @@ class TCPDF { $newbrd[$brd[$i]] = true; } $brd = $newbrd; - } elseif (($brd === 1) OR ($brd === true) OR (is_numeric($brd) AND (intval($brd) > 0))) { + } elseif ( + ($brd === 1) + || ($brd === true) + || (is_numeric($brd) && ((int)$brd > 0)) + ) { $brd = array('LRTB' => true); } if (!is_array($brd)) { @@ -2762,7 +2790,7 @@ class TCPDF { // process borders foreach ($brd as $border => $style) { $line_width = $this->LineWidth; - if (is_array($style) AND isset($style['width'])) { + if (is_array($style) && isset($style['width'])) { // get border width $line_width = $style['width']; } @@ -2783,31 +2811,54 @@ class TCPDF { } } // correct internal cell padding if required to avoid overlap between text and lines - if ((strpos($border,'T') !== false) AND ($this->cell_padding['T'] < $adj)) { + if ( + is_numeric($this->cell_padding['T']) + && ($this->cell_padding['T'] < $adj) + && (strpos($border, 'T') !== false) + ) { $this->cell_padding['T'] = $adj; } - if ((strpos($border,'R') !== false) AND ($this->cell_padding['R'] < $adj)) { + if ( + is_numeric($this->cell_padding['R']) + && ($this->cell_padding['R'] < $adj) + && (strpos($border, 'R') !== false) + ) { $this->cell_padding['R'] = $adj; } - if ((strpos($border,'B') !== false) AND ($this->cell_padding['B'] < $adj)) { + if ( + is_numeric($this->cell_padding['B']) + && ($this->cell_padding['B'] < $adj) + && (strpos($border, 'B') !== false) + ) { $this->cell_padding['B'] = $adj; } - if ((strpos($border,'L') !== false) AND ($this->cell_padding['L'] < $adj)) { + if ( + is_numeric($this->cell_padding['L']) + && ($this->cell_padding['L'] < $adj) + && (strpos($border, 'L') !== false) + ) { $this->cell_padding['L'] = $adj; } + } - return array('T' => ($this->cell_padding['T'] - $cp['T']), 'R' => ($this->cell_padding['R'] - $cp['R']), 'B' => ($this->cell_padding['B'] - $cp['B']), 'L' => ($this->cell_padding['L'] - $cp['L'])); + + return array( + 'T' => ($this->cell_padding['T'] - $cp['T']), + 'R' => ($this->cell_padding['R'] - $cp['R']), + 'B' => ($this->cell_padding['B'] - $cp['B']), + 'L' => ($this->cell_padding['L'] - $cp['L']), + ); } /** * Enables or disables the automatic page breaking mode. When enabling, the second parameter is the distance from the bottom of the page that defines the triggering limit. By default, the mode is on and the margin is 2 cm. - * @param $auto (boolean) Boolean indicating if mode should be on or off. - * @param $margin (float) Distance from the bottom of the page. + * @param boolean $auto Boolean indicating if mode should be on or off. + * @param float $margin Distance from the bottom of the page. * @public * @since 1.0 * @see Cell(), MultiCell(), AcceptPageBreak() */ - public function SetAutoPageBreak($auto, $margin=0) { + public function setAutoPageBreak($auto, $margin=0) { $this->AutoPageBreak = $auto ? true : false; $this->bMargin = $margin; $this->PageBreakTrigger = $this->h - $margin; @@ -2815,7 +2866,7 @@ class TCPDF { /** * Return the auto-page-break mode (true or false). - * @return boolean auto-page-break mode + * @return bool auto-page-break mode * @public * @since 5.9.088 */ @@ -2825,13 +2876,13 @@ class TCPDF { /** * Defines the way the document is to be displayed by the viewer. - * @param $zoom (mixed) The zoom to use. It can be one of the following string values or a number indicating the zooming factor to use.
              • fullpage: displays the entire page on screen
              • fullwidth: uses maximum width of window
              • real: uses real size (equivalent to 100% zoom)
              • default: uses viewer default mode
              - * @param $layout (string) The page layout. Possible values are:
              • SinglePage Display one page at a time
              • OneColumn Display the pages in one column
              • TwoColumnLeft Display the pages in two columns, with odd-numbered pages on the left
              • TwoColumnRight Display the pages in two columns, with odd-numbered pages on the right
              • TwoPageLeft (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the left
              • TwoPageRight (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the right
              - * @param $mode (string) A name object specifying how the document should be displayed when opened:
              • UseNone Neither document outline nor thumbnail images visible
              • UseOutlines Document outline visible
              • UseThumbs Thumbnail images visible
              • FullScreen Full-screen mode, with no menu bar, window controls, or any other window visible
              • UseOC (PDF 1.5) Optional content group panel visible
              • UseAttachments (PDF 1.6) Attachments panel visible
              + * @param mixed $zoom The zoom to use. It can be one of the following string values or a number indicating the zooming factor to use.
              • fullpage: displays the entire page on screen
              • fullwidth: uses maximum width of window
              • real: uses real size (equivalent to 100% zoom)
              • default: uses viewer default mode
              + * @param string $layout The page layout. Possible values are:
              • SinglePage Display one page at a time
              • OneColumn Display the pages in one column
              • TwoColumnLeft Display the pages in two columns, with odd-numbered pages on the left
              • TwoColumnRight Display the pages in two columns, with odd-numbered pages on the right
              • TwoPageLeft (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the left
              • TwoPageRight (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the right
              + * @param string $mode A name object specifying how the document should be displayed when opened:
              • UseNone Neither document outline nor thumbnail images visible
              • UseOutlines Document outline visible
              • UseThumbs Thumbnail images visible
              • FullScreen Full-screen mode, with no menu bar, window controls, or any other window visible
              • UseOC (PDF 1.5) Optional content group panel visible
              • UseAttachments (PDF 1.6) Attachments panel visible
              * @public * @since 1.2 */ - public function SetDisplayMode($zoom, $layout='SinglePage', $mode='UseNone') { + public function setDisplayMode($zoom, $layout='SinglePage', $mode='UseNone') { if (($zoom == 'fullpage') OR ($zoom == 'fullwidth') OR ($zoom == 'real') OR ($zoom == 'default') OR (!is_string($zoom))) { $this->ZoomMode = $zoom; } else { @@ -2844,11 +2895,11 @@ class TCPDF { /** * Activates or deactivates page compression. When activated, the internal representation of each page is compressed, which leads to a compression ratio of about 2 for the resulting document. Compression is on by default. * Note: the Zlib extension is required for this feature. If not present, compression will be turned off. - * @param $compress (boolean) Boolean indicating if compression must be enabled. + * @param boolean $compress Boolean indicating if compression must be enabled. * @public * @since 1.4 */ - public function SetCompression($compress=true) { + public function setCompression($compress=true) { $this->compress = false; if (function_exists('gzcompress')) { if ($compress) { @@ -2861,7 +2912,7 @@ class TCPDF { /** * Set flag to force sRGB_IEC61966-2.1 black scaled ICC color profile for the whole document. - * @param $mode (boolean) If true force sRGB output intent. + * @param boolean $mode If true force sRGB output intent. * @public * @since 5.9.121 (2011-09-28) */ @@ -2872,72 +2923,84 @@ class TCPDF { /** * Turn on/off Unicode mode for document information dictionary (meta tags). * This has effect only when unicode mode is set to false. - * @param $unicode (boolean) if true set the meta information in Unicode + * @param boolean $unicode if true set the meta information in Unicode * @since 5.9.027 (2010-12-01) * @public */ - public function SetDocInfoUnicode($unicode=true) { + public function setDocInfoUnicode($unicode=true) { $this->docinfounicode = $unicode ? true : false; } /** * Defines the title of the document. - * @param $title (string) The title. + * @param string $title The title. * @public * @since 1.2 * @see SetAuthor(), SetCreator(), SetKeywords(), SetSubject() */ - public function SetTitle($title) { + public function setTitle($title) { $this->title = $title; } /** * Defines the subject of the document. - * @param $subject (string) The subject. + * @param string $subject The subject. * @public * @since 1.2 * @see SetAuthor(), SetCreator(), SetKeywords(), SetTitle() */ - public function SetSubject($subject) { + public function setSubject($subject) { $this->subject = $subject; } /** * Defines the author of the document. - * @param $author (string) The name of the author. + * @param string $author The name of the author. * @public * @since 1.2 * @see SetCreator(), SetKeywords(), SetSubject(), SetTitle() */ - public function SetAuthor($author) { + public function setAuthor($author) { $this->author = $author; } /** * Associates keywords with the document, generally in the form 'keyword1 keyword2 ...'. - * @param $keywords (string) The list of keywords. + * @param string $keywords The list of keywords. * @public * @since 1.2 * @see SetAuthor(), SetCreator(), SetSubject(), SetTitle() */ - public function SetKeywords($keywords) { + public function setKeywords($keywords) { $this->keywords = $keywords; } /** * Defines the creator of the document. This is typically the name of the application that generates the PDF. - * @param $creator (string) The name of the creator. + * @param string $creator The name of the creator. * @public * @since 1.2 * @see SetAuthor(), SetKeywords(), SetSubject(), SetTitle() */ - public function SetCreator($creator) { + public function setCreator($creator) { $this->creator = $creator; } + /** + * Whether to allow local file path in image html tags, when prefixed with file:// + * + * @param bool $allowLocalFiles true, when local files should be allowed. Otherwise false. + * @public + * @since 6.4 + */ + public function setAllowLocalFiles($allowLocalFiles) { + $this->allowLocalFiles = (bool) $allowLocalFiles; + } + + /** * Throw an exception or print an error message and die if the K_TCPDF_PARSER_THROW_EXCEPTION_ERROR constant is set to true. - * @param $msg (string) The error message + * @param string $msg The error message * @public * @since 1.0 */ @@ -2984,13 +3047,13 @@ class TCPDF { $gvars = $this->getGraphicVars(); $this->setEqualColumns(); $this->lastpage(true); - $this->SetAutoPageBreak(false); + $this->setAutoPageBreak(false); $this->x = 0; $this->y = $this->h - (1 / $this->k); $this->lMargin = 0; $this->_outSaveGraphicsState(); $font = defined('PDF_FONT_NAME_MAIN')?PDF_FONT_NAME_MAIN:'helvetica'; - $this->SetFont($font, '', 1); + $this->setFont($font, '', 1); $this->setTextRenderingMode(0, false, false); $msg = "\x50\x6f\x77\x65\x72\x65\x64\x20\x62\x79\x20\x54\x43\x50\x44\x46\x20\x28\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67\x29"; $lnk = "\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67"; @@ -3009,8 +3072,8 @@ class TCPDF { /** * Move pointer at the specified document page and update page dimensions. - * @param $pnum (int) page number (1 ... numpages) - * @param $resetmargins (boolean) if true reset left, right, top margins and Y position. + * @param int $pnum page number (1 ... numpages) + * @param boolean $resetmargins if true reset left, right, top margins and Y position. * @public * @since 2.1.000 (2008-01-07) * @see getPage(), lastpage(), getNumPages() @@ -3035,13 +3098,13 @@ class TCPDF { $this->original_rMargin = $this->pagedim[$this->page]['orm']; $this->AutoPageBreak = $this->pagedim[$this->page]['pb']; $this->CurOrientation = $this->pagedim[$this->page]['or']; - $this->SetAutoPageBreak($this->AutoPageBreak, $this->bMargin); + $this->setAutoPageBreak($this->AutoPageBreak, $this->bMargin); // restore graphic settings //$this->setGraphicVars($gvars); if ($resetmargins) { $this->lMargin = $this->pagedim[$this->page]['olm']; $this->rMargin = $this->pagedim[$this->page]['orm']; - $this->SetY($this->tMargin); + $this->setY($this->tMargin); } else { // account for booklet mode if ($this->pagedim[$this->page]['olm'] != $this->pagedim[$oldpage]['olm']) { @@ -3057,7 +3120,7 @@ class TCPDF { /** * Reset pointer to the last document page. - * @param $resetmargins (boolean) if true reset left, right, top margins and Y position. + * @param boolean $resetmargins if true reset left, right, top margins and Y position. * @public * @since 2.0.000 (2008-01-04) * @see setPage(), getPage(), getNumPages() @@ -3090,9 +3153,9 @@ class TCPDF { /** * Adds a new TOC (Table Of Content) page to the document. - * @param $orientation (string) page orientation. - * @param $format (mixed) The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat(). - * @param $keepmargins (boolean) if true overwrites the default page margins with the current margins + * @param string $orientation page orientation. + * @param mixed $format The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat(). + * @param boolean $keepmargins if true overwrites the default page margins with the current margins * @public * @since 5.0.001 (2010-05-06) * @see AddPage(), startPage(), endPage(), endTOCPage() @@ -3114,10 +3177,10 @@ class TCPDF { /** * Adds a new page to the document. If a page is already present, the Footer() method is called first to output the footer (if enabled). Then the page is added, the current position set to the top-left corner according to the left and top margins (or top-right if in RTL mode), and Header() is called to display the header (if enabled). * The origin of the coordinate system is at the top-left corner (or top-right for RTL) and increasing ordinates go downwards. - * @param $orientation (string) page orientation. Possible values are (case insensitive):
              • P or PORTRAIT (default)
              • L or LANDSCAPE
              - * @param $format (mixed) The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat(). - * @param $keepmargins (boolean) if true overwrites the default page margins with the current margins - * @param $tocpage (boolean) if true set the tocpage state to true (the added page will be used to display Table Of Content). + * @param string $orientation page orientation. Possible values are (case insensitive):
              • P or PORTRAIT (default)
              • L or LANDSCAPE
              + * @param mixed $format The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat(). + * @param boolean $keepmargins if true overwrites the default page margins with the current margins + * @param boolean $tocpage if true set the tocpage state to true (the added page will be used to display Table Of Content). * @public * @since 1.0 * @see startPage(), endPage(), addTOCPage(), endTOCPage(), getPageSizeFromFormat(), setPageFormat() @@ -3141,7 +3204,7 @@ class TCPDF { /** * Terminate the current page - * @param $tocpage (boolean) if true set the tocpage state to false (end the page used to display Table Of Content). + * @param boolean $tocpage if true set the tocpage state to false (end the page used to display Table Of Content). * @public * @since 4.2.010 (2008-11-14) * @see AddPage(), startPage(), addTOCPage(), endTOCPage() @@ -3165,9 +3228,9 @@ class TCPDF { /** * Starts a new page to the document. The page must be closed using the endPage() function. * The origin of the coordinate system is at the top-left corner and increasing ordinates go downwards. - * @param $orientation (string) page orientation. Possible values are (case insensitive):
              • P or PORTRAIT (default)
              • L or LANDSCAPE
              - * @param $format (mixed) The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat(). - * @param $tocpage (boolean) if true the page is designated to contain the Table-Of-Content. + * @param string $orientation page orientation. Possible values are (case insensitive):
              • P or PORTRAIT (default)
              • L or LANDSCAPE
              + * @param mixed $format The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat(). + * @param boolean $tocpage if true the page is designated to contain the Table-Of-Content. * @since 4.2.010 (2008-11-14) * @see AddPage(), endPage(), addTOCPage(), endTOCPage(), getPageSizeFromFormat(), setPageFormat() * @public @@ -3204,7 +3267,7 @@ class TCPDF { if ($this->numpages > $this->page) { // this page has been already added $this->setPage($this->page + 1); - $this->SetY($this->tMargin); + $this->setY($this->tMargin); return; } // start a new page @@ -3252,7 +3315,7 @@ class TCPDF { /** * Set start-writing mark on selected page. * Borders and fills are always created after content and inserted on the position marked by this method. - * @param $page (int) page number (default is the current page) + * @param int $page page number (default is the current page) * @protected * @since 4.6.021 (2009-07-20) */ @@ -3269,12 +3332,12 @@ class TCPDF { /** * Set header data. - * @param $ln (string) header image logo - * @param $lw (string) header image logo width in mm - * @param $ht (string) string to print as title on document header - * @param $hs (string) string to print on document header - * @param $tc (array) RGB array color for text. - * @param $lc (array) RGB array color for line. + * @param string $ln header image logo + * @param int $lw header image logo width in mm + * @param string $ht string to print as title on document header + * @param string $hs string to print on document header + * @param int[] $tc RGB array color for text. + * @param int[] $lc RGB array color for line. * @public */ public function setHeaderData($ln='', $lw=0, $ht='', $hs='', $tc=array(0,0,0), $lc=array(0,0,0)) { @@ -3288,8 +3351,8 @@ class TCPDF { /** * Set footer data. - * @param $tc (array) RGB array color for text. - * @param $lc (array) RGB array color for line. + * @param int[] $tc RGB array color for text. + * @param int[] $lc RGB array color for line. * @public */ public function setFooterData($tc=array(0,0,0), $lc=array(0,0,0)) { @@ -3300,7 +3363,7 @@ class TCPDF { /** * Returns header data: *
              • $ret['logo'] = logo image
              • $ret['logo_width'] = width of the image logo in user units
              • $ret['title'] = header title
              • $ret['string'] = header description string
              - * @return array() + * @return array * @public * @since 4.0.012 (2008-07-24) */ @@ -3318,7 +3381,7 @@ class TCPDF { /** * Set header margin. * (minimum distance between header and top page margin) - * @param $hm (int) distance in user units + * @param float $hm distance in user units * @public */ public function setHeaderMargin($hm=10) { @@ -3338,7 +3401,7 @@ class TCPDF { /** * Set footer margin. * (minimum distance between footer and bottom page margin) - * @param $fm (int) distance in user units + * @param float $fm distance in user units * @public */ public function setFooterMargin($fm=10) { @@ -3356,7 +3419,7 @@ class TCPDF { } /** * Set a flag to print page header. - * @param $val (boolean) set to true to print the page header (default), false otherwise. + * @param boolean $val set to true to print the page header (default), false otherwise. * @public */ public function setPrintHeader($val=true) { @@ -3365,7 +3428,7 @@ class TCPDF { /** * Set a flag to print page footer. - * @param $val (boolean) set to true to print the page footer (default), false otherwise. + * @param boolean $val set to true to print the page footer (default), false otherwise. * @public */ public function setPrintFooter($val=true) { @@ -3400,7 +3463,7 @@ class TCPDF { /** * Set a flag to automatically reset the xobject template used by Header() method at each page. - * @param $val (boolean) set to true to reset Header xobject template at each page, false otherwise. + * @param boolean $val set to true to reset Header xobject template at each page, false otherwise. * @public */ public function setHeaderTemplateAutoreset($val=true) { @@ -3445,22 +3508,22 @@ class TCPDF { $header_x = $this->original_lMargin + ($headerdata['logo_width'] * 1.1); } $cw = $this->w - $this->original_lMargin - $this->original_rMargin - ($headerdata['logo_width'] * 1.1); - $this->SetTextColorArray($this->header_text_color); + $this->setTextColorArray($this->header_text_color); // header title - $this->SetFont($headerfont[0], 'B', $headerfont[2] + 1); - $this->SetX($header_x); + $this->setFont($headerfont[0], 'B', $headerfont[2] + 1); + $this->setX($header_x); $this->Cell($cw, $cell_height, $headerdata['title'], 0, 1, '', 0, '', 0); // header string - $this->SetFont($headerfont[0], $headerfont[1], $headerfont[2]); - $this->SetX($header_x); + $this->setFont($headerfont[0], $headerfont[1], $headerfont[2]); + $this->setX($header_x); $this->MultiCell($cw, $cell_height, $headerdata['string'], 0, '', 0, 1, '', '', true, 0, false, true, 0, 'T', false); // print an ending header line - $this->SetLineStyle(array('width' => 0.85 / $this->k, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $headerdata['line_color'])); - $this->SetY((2.835 / $this->k) + max($imgy, $this->y)); + $this->setLineStyle(array('width' => 0.85 / $this->k, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $headerdata['line_color'])); + $this->setY((2.835 / $this->k) + max($imgy, $this->y)); if ($this->rtl) { - $this->SetX($this->original_rMargin); + $this->setX($this->original_rMargin); } else { - $this->SetX($this->original_lMargin); + $this->setX($this->original_lMargin); } $this->Cell(($this->w - $this->original_lMargin - $this->original_rMargin), 0, '', 'T', 0, 'C'); $this->endTemplate(); @@ -3491,10 +3554,10 @@ class TCPDF { */ public function Footer() { $cur_y = $this->y; - $this->SetTextColorArray($this->footer_text_color); + $this->setTextColorArray($this->footer_text_color); //set style for cell border $line_width = (0.85 / $this->k); - $this->SetLineStyle(array('width' => $line_width, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $this->footer_line_color)); + $this->setLineStyle(array('width' => $line_width, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $this->footer_line_color)); //print document barcode $barcode = $this->getBarcode(); if (!empty($barcode)) { @@ -3520,13 +3583,13 @@ class TCPDF { } else { $pagenumtxt = $w_page.$this->getPageNumGroupAlias().' / '.$this->getPageGroupAlias(); } - $this->SetY($cur_y); + $this->setY($cur_y); //Print page number if ($this->getRTL()) { - $this->SetX($this->original_rMargin); + $this->setX($this->original_rMargin); $this->Cell(0, 0, $pagenumtxt, 'T', 0, 'L'); } else { - $this->SetX($this->original_lMargin); + $this->setX($this->original_lMargin); $this->Cell(0, 0, $this->getAliasRightShift().$pagenumtxt, 'T', 0, 'R'); } } @@ -3549,20 +3612,20 @@ class TCPDF { $this->_outSaveGraphicsState(); $this->rMargin = $this->original_rMargin; $this->lMargin = $this->original_lMargin; - $this->SetCellPadding(0); + $this->setCellPadding(0); //set current position if ($this->rtl) { - $this->SetXY($this->original_rMargin, $this->header_margin); + $this->setXY($this->original_rMargin, $this->header_margin); } else { - $this->SetXY($this->original_lMargin, $this->header_margin); + $this->setXY($this->original_lMargin, $this->header_margin); } - $this->SetFont($this->header_font[0], $this->header_font[1], $this->header_font[2]); + $this->setFont($this->header_font[0], $this->header_font[1], $this->header_font[2]); $this->Header(); //restore position if ($this->rtl) { - $this->SetXY($this->original_rMargin, $this->tMargin); + $this->setXY($this->original_rMargin, $this->tMargin); } else { - $this->SetXY($this->original_lMargin, $this->tMargin); + $this->setXY($this->original_lMargin, $this->tMargin); } $this->_outRestoreGraphicsState(); $this->lasth = $lasth; @@ -3597,21 +3660,21 @@ class TCPDF { $this->_outSaveGraphicsState(); $this->rMargin = $this->original_rMargin; $this->lMargin = $this->original_lMargin; - $this->SetCellPadding(0); + $this->setCellPadding(0); //set current position $footer_y = $this->h - $this->footer_margin; if ($this->rtl) { - $this->SetXY($this->original_rMargin, $footer_y); + $this->setXY($this->original_rMargin, $footer_y); } else { - $this->SetXY($this->original_lMargin, $footer_y); + $this->setXY($this->original_lMargin, $footer_y); } - $this->SetFont($this->footer_font[0], $this->footer_font[1], $this->footer_font[2]); + $this->setFont($this->footer_font[0], $this->footer_font[1], $this->footer_font[2]); $this->Footer(); //restore position if ($this->rtl) { - $this->SetXY($this->original_rMargin, $this->tMargin); + $this->setXY($this->original_rMargin, $this->tMargin); } else { - $this->SetXY($this->original_lMargin, $this->tMargin); + $this->setXY($this->original_lMargin, $this->tMargin); } $this->_outRestoreGraphicsState(); $this->lasth = $lasth; @@ -3629,7 +3692,7 @@ class TCPDF { /** * Check if we are on the page body (excluding page header and footer). - * @return true if we are not in page header nor in page footer, false otherwise. + * @return bool true if we are not in page header nor in page footer, false otherwise. * @protected * @since 5.9.091 (2011-06-15) */ @@ -3715,7 +3778,7 @@ class TCPDF { /** * Returns the array of spot colors. - * @return (array) Spot colors array. + * @return array Spot colors array. * @public * @since 6.0.038 (2013-09-30) */ @@ -3727,11 +3790,11 @@ class TCPDF { * Defines a new spot color. * It can be expressed in RGB components or gray scale. * The method can be called before the first page is created and the value is retained from page to page. - * @param $name (string) Full name of the spot color. - * @param $c (float) Cyan color for CMYK. Value between 0 and 100. - * @param $m (float) Magenta color for CMYK. Value between 0 and 100. - * @param $y (float) Yellow color for CMYK. Value between 0 and 100. - * @param $k (float) Key (Black) color for CMYK. Value between 0 and 100. + * @param string $name Full name of the spot color. + * @param float $c Cyan color for CMYK. Value between 0 and 100. + * @param float $m Magenta color for CMYK. Value between 0 and 100. + * @param float $y Yellow color for CMYK. Value between 0 and 100. + * @param float $k Key (Black) color for CMYK. Value between 0 and 100. * @public * @since 4.0.024 (2008-09-12) * @see SetDrawSpotColor(), SetFillSpotColor(), SetTextSpotColor() @@ -3745,10 +3808,10 @@ class TCPDF { /** * Set the spot color for the specified type ('draw', 'fill', 'text'). - * @param $type (string) Type of object affected by this color: ('draw', 'fill', 'text'). - * @param $name (string) Name of the spot color. - * @param $tint (float) Intensity of the color (from 0 to 100 ; 100 = full intensity by default). - * @return (string) PDF color command. + * @param string $type Type of object affected by this color: ('draw', 'fill', 'text'). + * @param string $name Name of the spot color. + * @param float $tint Intensity of the color (from 0 to 100 ; 100 = full intensity by default). + * @return string PDF color command. * @public * @since 5.9.125 (2011-10-03) */ @@ -3792,37 +3855,37 @@ class TCPDF { /** * Defines the spot color used for all drawing operations (lines, rectangles and cell borders). - * @param $name (string) Name of the spot color. - * @param $tint (float) Intensity of the color (from 0 to 100 ; 100 = full intensity by default). + * @param string $name Name of the spot color. + * @param float $tint Intensity of the color (from 0 to 100 ; 100 = full intensity by default). * @public * @since 4.0.024 (2008-09-12) * @see AddSpotColor(), SetFillSpotColor(), SetTextSpotColor() */ - public function SetDrawSpotColor($name, $tint=100) { + public function setDrawSpotColor($name, $tint=100) { $this->setSpotColor('draw', $name, $tint); } /** * Defines the spot color used for all filling operations (filled rectangles and cell backgrounds). - * @param $name (string) Name of the spot color. - * @param $tint (float) Intensity of the color (from 0 to 100 ; 100 = full intensity by default). + * @param string $name Name of the spot color. + * @param float $tint Intensity of the color (from 0 to 100 ; 100 = full intensity by default). * @public * @since 4.0.024 (2008-09-12) * @see AddSpotColor(), SetDrawSpotColor(), SetTextSpotColor() */ - public function SetFillSpotColor($name, $tint=100) { + public function setFillSpotColor($name, $tint=100) { $this->setSpotColor('fill', $name, $tint); } /** * Defines the spot color used for text. - * @param $name (string) Name of the spot color. - * @param $tint (int) Intensity of the color (from 0 to 100 ; 100 = full intensity by default). + * @param string $name Name of the spot color. + * @param int $tint Intensity of the color (from 0 to 100 ; 100 = full intensity by default). * @public * @since 4.0.024 (2008-09-12) * @see AddSpotColor(), SetDrawSpotColor(), SetFillSpotColor() */ - public function SetTextSpotColor($name, $tint=100) { + public function setTextSpotColor($name, $tint=100) { $this->setSpotColor('text', $name, $tint); } @@ -3830,10 +3893,10 @@ class TCPDF { * Set the color array for the specified type ('draw', 'fill', 'text'). * It can be expressed in RGB, CMYK or GRAY SCALE components. * The method can be called before the first page is created and the value is retained from page to page. - * @param $type (string) Type of object affected by this color: ('draw', 'fill', 'text'). - * @param $color (array) Array of colors (1=gray, 3=RGB, 4=CMYK or 5=spotcolor=CMYK+name values). - * @param $ret (boolean) If true do not send the PDF command. - * @return (string) The PDF command or empty string. + * @param string $type Type of object affected by this color: ('draw', 'fill', 'text'). + * @param array $color Array of colors (1=gray, 3=RGB, 4=CMYK or 5=spotcolor=CMYK+name values). + * @param boolean $ret If true do not send the PDF command. + * @return string The PDF command or empty string. * @public * @since 3.1.000 (2008-06-11) */ @@ -3861,14 +3924,14 @@ class TCPDF { * Defines the color used for all drawing operations (lines, rectangles and cell borders). * It can be expressed in RGB, CMYK or GRAY SCALE components. * The method can be called before the first page is created and the value is retained from page to page. - * @param $color (array) Array of colors (1, 3 or 4 values). - * @param $ret (boolean) If true do not send the PDF command. + * @param array $color Array of colors (1, 3 or 4 values). + * @param boolean $ret If true do not send the PDF command. * @return string the PDF command * @public * @since 3.1.000 (2008-06-11) * @see SetDrawColor() */ - public function SetDrawColorArray($color, $ret=false) { + public function setDrawColorArray($color, $ret=false) { return $this->setColorArray('draw', $color, $ret); } @@ -3876,39 +3939,39 @@ class TCPDF { * Defines the color used for all filling operations (filled rectangles and cell backgrounds). * It can be expressed in RGB, CMYK or GRAY SCALE components. * The method can be called before the first page is created and the value is retained from page to page. - * @param $color (array) Array of colors (1, 3 or 4 values). - * @param $ret (boolean) If true do not send the PDF command. + * @param array $color Array of colors (1, 3 or 4 values). + * @param boolean $ret If true do not send the PDF command. * @public * @since 3.1.000 (2008-6-11) * @see SetFillColor() */ - public function SetFillColorArray($color, $ret=false) { + public function setFillColorArray($color, $ret=false) { return $this->setColorArray('fill', $color, $ret); } /** * Defines the color used for text. It can be expressed in RGB components or gray scale. * The method can be called before the first page is created and the value is retained from page to page. - * @param $color (array) Array of colors (1, 3 or 4 values). - * @param $ret (boolean) If true do not send the PDF command. + * @param array $color Array of colors (1, 3 or 4 values). + * @param boolean $ret If true do not send the PDF command. * @public * @since 3.1.000 (2008-6-11) * @see SetFillColor() */ - public function SetTextColorArray($color, $ret=false) { + public function setTextColorArray($color, $ret=false) { return $this->setColorArray('text', $color, $ret); } /** * Defines the color used by the specified type ('draw', 'fill', 'text'). - * @param $type (string) Type of object affected by this color: ('draw', 'fill', 'text'). - * @param $col1 (float) GRAY level for single color, or Red color for RGB (0-255), or CYAN color for CMYK (0-100). - * @param $col2 (float) GREEN color for RGB (0-255), or MAGENTA color for CMYK (0-100). - * @param $col3 (float) BLUE color for RGB (0-255), or YELLOW color for CMYK (0-100). - * @param $col4 (float) KEY (BLACK) color for CMYK (0-100). - * @param $ret (boolean) If true do not send the command. - * @param $name (string) spot color name (if any) - * @return (string) The PDF command or empty string. + * @param string $type Type of object affected by this color: ('draw', 'fill', 'text'). + * @param float $col1 GRAY level for single color, or Red color for RGB (0-255), or CYAN color for CMYK (0-100). + * @param float $col2 GREEN color for RGB (0-255), or MAGENTA color for CMYK (0-100). + * @param float $col3 BLUE color for RGB (0-255), or YELLOW color for CMYK (0-100). + * @param float $col4 KEY (BLACK) color for CMYK (0-100). + * @param boolean $ret If true do not send the command. + * @param string $name spot color name (if any) + * @return string The PDF command or empty string. * @public * @since 5.9.125 (2011-10-03) */ @@ -3980,7 +4043,7 @@ class TCPDF { } } $this->ColorFlag = ($this->FillColor != $this->TextColor); - if (($type != 'text') AND ($this->state == 2)) { + if (($type != 'text') AND ($this->state == 2) AND $type !== 0) { if (!$ret) { $this->_out($pdfcolor); } @@ -3991,63 +4054,64 @@ class TCPDF { /** * Defines the color used for all drawing operations (lines, rectangles and cell borders). It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page. - * @param $col1 (float) GRAY level for single color, or Red color for RGB (0-255), or CYAN color for CMYK (0-100). - * @param $col2 (float) GREEN color for RGB (0-255), or MAGENTA color for CMYK (0-100). - * @param $col3 (float) BLUE color for RGB (0-255), or YELLOW color for CMYK (0-100). - * @param $col4 (float) KEY (BLACK) color for CMYK (0-100). - * @param $ret (boolean) If true do not send the command. - * @param $name (string) spot color name (if any) + * @param float $col1 GRAY level for single color, or Red color for RGB (0-255), or CYAN color for CMYK (0-100). + * @param float $col2 GREEN color for RGB (0-255), or MAGENTA color for CMYK (0-100). + * @param float $col3 BLUE color for RGB (0-255), or YELLOW color for CMYK (0-100). + * @param float $col4 KEY (BLACK) color for CMYK (0-100). + * @param boolean $ret If true do not send the command. + * @param string $name spot color name (if any) * @return string the PDF command * @public * @since 1.3 * @see SetDrawColorArray(), SetFillColor(), SetTextColor(), Line(), Rect(), Cell(), MultiCell() */ - public function SetDrawColor($col1=0, $col2=-1, $col3=-1, $col4=-1, $ret=false, $name='') { + public function setDrawColor($col1=0, $col2=-1, $col3=-1, $col4=-1, $ret=false, $name='') { return $this->setColor('draw', $col1, $col2, $col3, $col4, $ret, $name); } /** * Defines the color used for all filling operations (filled rectangles and cell backgrounds). It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page. - * @param $col1 (float) GRAY level for single color, or Red color for RGB (0-255), or CYAN color for CMYK (0-100). - * @param $col2 (float) GREEN color for RGB (0-255), or MAGENTA color for CMYK (0-100). - * @param $col3 (float) BLUE color for RGB (0-255), or YELLOW color for CMYK (0-100). - * @param $col4 (float) KEY (BLACK) color for CMYK (0-100). - * @param $ret (boolean) If true do not send the command. - * @param $name (string) Spot color name (if any). - * @return (string) The PDF command. + * @param float $col1 GRAY level for single color, or Red color for RGB (0-255), or CYAN color for CMYK (0-100). + * @param float $col2 GREEN color for RGB (0-255), or MAGENTA color for CMYK (0-100). + * @param float $col3 BLUE color for RGB (0-255), or YELLOW color for CMYK (0-100). + * @param float $col4 KEY (BLACK) color for CMYK (0-100). + * @param boolean $ret If true do not send the command. + * @param string $name Spot color name (if any). + * @return string The PDF command. * @public * @since 1.3 * @see SetFillColorArray(), SetDrawColor(), SetTextColor(), Rect(), Cell(), MultiCell() */ - public function SetFillColor($col1=0, $col2=-1, $col3=-1, $col4=-1, $ret=false, $name='') { + public function setFillColor($col1=0, $col2=-1, $col3=-1, $col4=-1, $ret=false, $name='') { return $this->setColor('fill', $col1, $col2, $col3, $col4, $ret, $name); } /** * Defines the color used for text. It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page. - * @param $col1 (float) GRAY level for single color, or Red color for RGB (0-255), or CYAN color for CMYK (0-100). - * @param $col2 (float) GREEN color for RGB (0-255), or MAGENTA color for CMYK (0-100). - * @param $col3 (float) BLUE color for RGB (0-255), or YELLOW color for CMYK (0-100). - * @param $col4 (float) KEY (BLACK) color for CMYK (0-100). - * @param $ret (boolean) If true do not send the command. - * @param $name (string) Spot color name (if any). - * @return (string) Empty string. + * @param float $col1 GRAY level for single color, or Red color for RGB (0-255), or CYAN color for CMYK (0-100). + * @param float $col2 GREEN color for RGB (0-255), or MAGENTA color for CMYK (0-100). + * @param float $col3 BLUE color for RGB (0-255), or YELLOW color for CMYK (0-100). + * @param float $col4 KEY (BLACK) color for CMYK (0-100). + * @param boolean $ret If true do not send the command. + * @param string $name Spot color name (if any). + * @return string Empty string. * @public * @since 1.3 * @see SetTextColorArray(), SetDrawColor(), SetFillColor(), Text(), Cell(), MultiCell() */ - public function SetTextColor($col1=0, $col2=-1, $col3=-1, $col4=-1, $ret=false, $name='') { + public function setTextColor($col1=0, $col2=-1, $col3=-1, $col4=-1, $ret=false, $name='') { return $this->setColor('text', $col1, $col2, $col3, $col4, $ret, $name); } /** * Returns the length of a string in user unit. A font must be selected.
              - * @param $s (string) The string whose length is to be computed - * @param $fontname (string) Family font. It can be either a name defined by AddFont() or one of the standard families. It is also possible to pass an empty string, in that case, the current family is retained. - * @param $fontstyle (string) Font style. Possible values are (case insensitive):
              • empty string: regular
              • B: bold
              • I: italic
              • U: underline
              • D: line-through
              • O: overline
              or any combination. The default value is regular. - * @param $fontsize (float) Font size in points. The default value is the current size. - * @param $getarray (boolean) if true returns an array of characters widths, if false returns the total length. - * @return mixed int total string length or array of characted widths + * @param string $s The string whose length is to be computed + * @param string $fontname Family font. It can be either a name defined by AddFont() or one of the standard families. It is also possible to pass an empty string, in that case, the current family is retained. + * @param string $fontstyle Font style. Possible values are (case insensitive):
              • empty string: regular
              • B: bold
              • I: italic
              • U: underline
              • D: line-through
              • O: overline
              or any combination. The default value is regular. + * @param float $fontsize Font size in points. The default value is the current size. + * @param boolean $getarray if true returns an array of characters widths, if false returns the total length. + * @return float[]|float total string length or array of characted widths + * @phpstan-return ($getarray is true ? float[] : float) total string length or array of characted widths * @author Nicola Asuni * @public * @since 1.2 @@ -4058,12 +4122,13 @@ class TCPDF { /** * Returns the string length of an array of chars in user unit or an array of characters widths. A font must be selected.
              - * @param $sa (string) The array of chars whose total length is to be computed - * @param $fontname (string) Family font. It can be either a name defined by AddFont() or one of the standard families. It is also possible to pass an empty string, in that case, the current family is retained. - * @param $fontstyle (string) Font style. Possible values are (case insensitive):
              • empty string: regular
              • B: bold
              • I: italic
              • U: underline
              • D: line through
              • O: overline
              or any combination. The default value is regular. - * @param $fontsize (float) Font size in points. The default value is the current size. - * @param $getarray (boolean) if true returns an array of characters widths, if false returns the total length. - * @return mixed int total string length or array of characted widths + * @param array $sa The array of chars whose total length is to be computed + * @param string $fontname Family font. It can be either a name defined by AddFont() or one of the standard families. It is also possible to pass an empty string, in that case, the current family is retained. + * @param string $fontstyle Font style. Possible values are (case insensitive):
              • empty string: regular
              • B: bold
              • I: italic
              • U: underline
              • D: line through
              • O: overline
              or any combination. The default value is regular. + * @param float $fontsize Font size in points. The default value is the current size. + * @param boolean $getarray if true returns an array of characters widths, if false returns the total length. + * @return float[]|float total string length or array of characted widths + * @phpstan-return ($getarray is true ? float[] : float) total string length or array of characted widths * @author Nicola Asuni * @public * @since 2.4.000 (2008-03-06) @@ -4074,7 +4139,7 @@ class TCPDF { $prev_FontFamily = $this->FontFamily; $prev_FontStyle = $this->FontStyle; $prev_FontSizePt = $this->FontSizePt; - $this->SetFont($fontname, $fontstyle, $fontsize, '', 'default', false); + $this->setFont($fontname, $fontstyle, $fontsize, '', 'default', false); } // convert UTF-8 array to Latin1 if required if ($this->isunicode AND (!$this->isUnicodeFont())) { @@ -4090,7 +4155,7 @@ class TCPDF { } // restore previous values if (!TCPDF_STATIC::empty_string($fontname)) { - $this->SetFont($prev_FontFamily, $prev_FontStyle, $prev_FontSizePt, '', 'default', false); + $this->setFont($prev_FontFamily, $prev_FontStyle, $prev_FontSizePt, '', 'default', false); } if ($getarray) { return $wa; @@ -4100,8 +4165,8 @@ class TCPDF { /** * Returns the length of the char in user unit for the current font considering current stretching and spacing (tracking). - * @param $char (int) The char code whose length is to be returned - * @param $notlast (boolean) If false ignore the font-spacing. + * @param int $char The char code whose length is to be returned + * @param boolean $notlast If false ignore the font-spacing. * @return float char width * @author Nicola Asuni * @public @@ -4123,7 +4188,7 @@ class TCPDF { /** * Returns the length of the char in user unit for the current font. - * @param $char (int) The char code whose length is to be returned + * @param int $char The char code whose length is to be returned * @return float char width * @author Nicola Asuni * @public @@ -4134,8 +4199,8 @@ class TCPDF { // SHY character will not be printed return (0); } - if (isset($this->CurrentFont['cw'][$char])) { - $w = $this->CurrentFont['cw'][$char]; + if (isset($this->CurrentFont['cw'][intval($char)])) { + $w = $this->CurrentFont['cw'][intval($char)]; } elseif (isset($this->CurrentFont['dw'])) { // default width $w = $this->CurrentFont['dw']; @@ -4150,7 +4215,7 @@ class TCPDF { /** * Returns the numbero of characters in a string. - * @param $s (string) The input string. + * @param string $s The input string. * @return int number of characters * @public * @since 2.0.0001 (2008-01-07) @@ -4182,11 +4247,11 @@ class TCPDF { * Imports a TrueType, Type1, core, or CID0 font and makes it available. * It is necessary to generate a font definition file first (read /fonts/utils/README.TXT). * The definition file (and the font file itself when embedding) must be present either in the current directory or in the one indicated by K_PATH_FONTS if the constant is defined. If it could not be found, the error "Could not include font definition file" is generated. - * @param $family (string) Font family. The name can be chosen arbitrarily. If it is a standard family name, it will override the corresponding font. - * @param $style (string) Font style. Possible values are (case insensitive):
              • empty string: regular (default)
              • B: bold
              • I: italic
              • BI or IB: bold italic
              - * @param $fontfile (string) The font definition file. By default, the name is built from the family and style, in lower case with no spaces. - * @return array containing the font data, or false in case of error. - * @param $subset (mixed) if true embedd only a subset of the font (stores only the information related to the used characters); if false embedd full font; if 'default' uses the default value set using setFontSubsetting(). This option is valid only for TrueTypeUnicode fonts. If you want to enable users to change the document, set this parameter to false. If you subset the font, the person who receives your PDF would need to have your same font in order to make changes to your PDF. The file size of the PDF would also be smaller because you are embedding only part of a font. + * @param string $family Font family. The name can be chosen arbitrarily. If it is a standard family name, it will override the corresponding font. + * @param string $style Font style. Possible values are (case insensitive):
              • empty string: regular (default)
              • B: bold
              • I: italic
              • BI or IB: bold italic
              + * @param string $fontfile The font definition file. By default, the name is built from the family and style, in lower case with no spaces. + * @return array|false array containing the font data, or false in case of error. + * @param mixed $subset if true embedd only a subset of the font (stores only the information related to the used characters); if false embedd full font; if 'default' uses the default value set using setFontSubsetting(). This option is valid only for TrueTypeUnicode fonts. If you want to enable users to change the document, set this parameter to false. If you subset the font, the person who receives your PDF would need to have your same font in order to make changes to your PDF. The file size of the PDF would also be smaller because you are embedding only part of a font. * @public * @since 1.5 * @see SetFont(), setFontSubsetting() @@ -4226,7 +4291,7 @@ class TCPDF { // all fonts must be embedded $family = 'pdfa'.$family; } - $tempstyle = strtoupper($style); + $tempstyle = strtoupper($style === null ? '' : $style); $style = ''; // underline if (strpos($tempstyle, 'U') !== false) { @@ -4293,6 +4358,22 @@ class TCPDF { } // include font file if (!TCPDF_STATIC::empty_string($fontfile) AND (@TCPDF_STATIC::file_exists($fontfile))) { + $type=null; + $name=null; + $desc=null; + $up=-null; + $ut=null; + $cw=null; + $cbbox=null; + $dw=null; + $enc=null; + $cidinfo=null; + $file=null; + $ctg=null; + $diff=null; + $originalsize=null; + $size1=null; + $size2=null; include($fontfile); } else { $this->Error('Could not include font definition file: '.$family.''); @@ -4353,7 +4434,7 @@ class TCPDF { $this->Error('Unknow font type: '.$type.''); } // set name if unset - if (!isset($name) OR empty($name)) { + if (empty($name)) { $name = $fontkey; } // create artificial font style variations if missing (only works with non-embedded fonts) @@ -4396,7 +4477,7 @@ class TCPDF { // we are inside an XObject template $this->xobjects[$this->xobjid]['fonts'][$fontkey] = $this->numfonts; } - if (isset($diff) AND (!empty($diff))) { + if (!empty($diff)) { //Search existing encodings $d = 0; $nb = count($this->diffs); @@ -4436,18 +4517,18 @@ class TCPDF { * The method can be called before the first page is created and the font is retained from page to page. * If you just wish to change the current font size, it is simpler to call SetFontSize(). * Note: for the standard fonts, the font metric files must be accessible. There are three possibilities for this:
              • They are in the current directory (the one where the running script lies)
              • They are in one of the directories defined by the include_path parameter
              • They are in the directory defined by the K_PATH_FONTS constant

              - * @param $family (string) Family font. It can be either a name defined by AddFont() or one of the standard Type1 families (case insensitive):
              • times (Times-Roman)
              • timesb (Times-Bold)
              • timesi (Times-Italic)
              • timesbi (Times-BoldItalic)
              • helvetica (Helvetica)
              • helveticab (Helvetica-Bold)
              • helveticai (Helvetica-Oblique)
              • helveticabi (Helvetica-BoldOblique)
              • courier (Courier)
              • courierb (Courier-Bold)
              • courieri (Courier-Oblique)
              • courierbi (Courier-BoldOblique)
              • symbol (Symbol)
              • zapfdingbats (ZapfDingbats)
              It is also possible to pass an empty string. In that case, the current family is retained. - * @param $style (string) Font style. Possible values are (case insensitive):
              • empty string: regular
              • B: bold
              • I: italic
              • U: underline
              • D: line through
              • O: overline
              or any combination. The default value is regular. Bold and italic styles do not apply to Symbol and ZapfDingbats basic fonts or other fonts when not defined. - * @param $size (float) Font size in points. The default value is the current size. If no size has been specified since the beginning of the document, the value taken is 12 - * @param $fontfile (string) The font definition file. By default, the name is built from the family and style, in lower case with no spaces. - * @param $subset (mixed) if true embedd only a subset of the font (stores only the information related to the used characters); if false embedd full font; if 'default' uses the default value set using setFontSubsetting(). This option is valid only for TrueTypeUnicode fonts. If you want to enable users to change the document, set this parameter to false. If you subset the font, the person who receives your PDF would need to have your same font in order to make changes to your PDF. The file size of the PDF would also be smaller because you are embedding only part of a font. - * @param $out (boolean) if true output the font size command, otherwise only set the font properties. + * @param string $family Family font. It can be either a name defined by AddFont() or one of the standard Type1 families (case insensitive):
              • times (Times-Roman)
              • timesb (Times-Bold)
              • timesi (Times-Italic)
              • timesbi (Times-BoldItalic)
              • helvetica (Helvetica)
              • helveticab (Helvetica-Bold)
              • helveticai (Helvetica-Oblique)
              • helveticabi (Helvetica-BoldOblique)
              • courier (Courier)
              • courierb (Courier-Bold)
              • courieri (Courier-Oblique)
              • courierbi (Courier-BoldOblique)
              • symbol (Symbol)
              • zapfdingbats (ZapfDingbats)
              It is also possible to pass an empty string. In that case, the current family is retained. + * @param string $style Font style. Possible values are (case insensitive):
              • empty string: regular
              • B: bold
              • I: italic
              • U: underline
              • D: line through
              • O: overline
              or any combination. The default value is regular. Bold and italic styles do not apply to Symbol and ZapfDingbats basic fonts or other fonts when not defined. + * @param float|null $size Font size in points. The default value is the current size. If no size has been specified since the beginning of the document, the value taken is 12 + * @param string $fontfile The font definition file. By default, the name is built from the family and style, in lower case with no spaces. + * @param mixed $subset if true embedd only a subset of the font (stores only the information related to the used characters); if false embedd full font; if 'default' uses the default value set using setFontSubsetting(). This option is valid only for TrueTypeUnicode fonts. If you want to enable users to change the document, set this parameter to false. If you subset the font, the person who receives your PDF would need to have your same font in order to make changes to your PDF. The file size of the PDF would also be smaller because you are embedding only part of a font. + * @param boolean $out if true output the font size command, otherwise only set the font properties. * @author Nicola Asuni * @public * @since 1.0 * @see AddFont(), SetFontSize() */ - public function SetFont($family, $style='', $size=null, $fontfile='', $subset='default', $out=true) { + public function setFont($family, $style='', $size=null, $fontfile='', $subset='default', $out=true) { //Select a font; size given in points if ($size === null) { $size = $this->FontSizePt; @@ -4464,18 +4545,18 @@ class TCPDF { $this->setFontSubBuffer($this->CurrentFont['fontkey'], 'subsetchars', $this->CurrentFont['subsetchars']); } $this->CurrentFont = $this->getFontBuffer($fontdata['fontkey']); - $this->SetFontSize($size, $out); + $this->setFontSize($size, $out); } /** * Defines the size of the current font. - * @param $size (float) The font size in points. - * @param $out (boolean) if true output the font size command, otherwise only set the font properties. + * @param float $size The font size in points. + * @param boolean $out if true output the font size command, otherwise only set the font properties. * @public * @since 1.0 * @see SetFont() */ - public function SetFontSize($size, $out=true) { + public function setFontSize($size, $out=true) { $size = (float)$size; // font size in points $this->FontSizePt = $size; @@ -4551,7 +4632,7 @@ class TCPDF { /** * Convert a relative font measure into absolute value. - * @param $s (int) Font measure. + * @param int $s Font measure. * @return float Absolute measure. * @since 5.9.186 (2012-09-13) */ @@ -4561,8 +4642,8 @@ class TCPDF { /** * Returns the glyph bounding box of the specified character in the current font in user units. - * @param $char (int) Input character code. - * @return mixed array(xMin, yMin, xMax, yMax) or FALSE if not defined. + * @param int $char Input character code. + * @return false|array array(xMin, yMin, xMax, yMax) or FALSE if not defined. * @since 5.9.186 (2012-09-13) */ public function getCharBBox($char) { @@ -4580,9 +4661,9 @@ class TCPDF { /** * Return the font descent value - * @param $font (string) font name - * @param $style (string) font style - * @param $size (float) The size (in points) + * @param string $font font name + * @param string $style font style + * @param float $size The size (in points) * @return int font descent * @public * @author Nicola Asuni @@ -4601,9 +4682,9 @@ class TCPDF { /** * Return the font ascent value. - * @param $font (string) font name - * @param $style (string) font style - * @param $size (float) The size (in points) + * @param string $font font name + * @param string $style font style + * @param float $size The size (in points) * @return int font ascent * @public * @author Nicola Asuni @@ -4622,10 +4703,10 @@ class TCPDF { /** * Return true in the character is present in the specified font. - * @param $char (mixed) Character to check (integer value or string) - * @param $font (string) Font name (family name). - * @param $style (string) Font style. - * @return (boolean) true if the char is defined, false otherwise. + * @param mixed $char Character to check (integer value or string) + * @param string $font Font name (family name). + * @param string $style Font style. + * @return bool true if the char is defined, false otherwise. * @public * @since 5.9.153 (2012-03-28) */ @@ -4648,11 +4729,11 @@ class TCPDF { /** * Replace missing font characters on selected font with specified substitutions. - * @param $text (string) Text to process. - * @param $font (string) Font name (family name). - * @param $style (string) Font style. - * @param $subs (array) Array of possible character substitutions. The key is the character to check (integer value) and the value is a single intege value or an array of possible substitutes. - * @return (string) Processed text. + * @param string $text Text to process. + * @param string $font Font name (family name). + * @param string $style Font style. + * @param array $subs Array of possible character substitutions. The key is the character to check (integer value) and the value is a single intege value or an array of possible substitutes. + * @return string Processed text. * @public * @since 5.9.153 (2012-03-28) */ @@ -4689,11 +4770,11 @@ class TCPDF { /** * Defines the default monospaced font. - * @param $font (string) Font name. + * @param string $font Font name. * @public * @since 4.5.025 */ - public function SetDefaultMonospacedFont($font) { + public function setDefaultMonospacedFont($font) { $this->default_monospaced_font = $font; } @@ -4713,14 +4794,14 @@ class TCPDF { /** * Defines the page and position a link points to. - * @param $link (int) The link identifier returned by AddLink() - * @param $y (float) Ordinate of target position; -1 indicates the current position. The default value is 0 (top of page) - * @param $page (int|string) Number of target page; -1 indicates the current page (default value). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages. + * @param int $link The link identifier returned by AddLink() + * @param float $y Ordinate of target position; -1 indicates the current position. The default value is 0 (top of page) + * @param int|string $page Number of target page; -1 indicates the current page (default value). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages. * @public * @since 1.5 * @see AddLink() */ - public function SetLink($link, $y=0, $page=-1) { + public function setLink($link, $y=0, $page=-1) { $fixed = false; if (!empty($page) AND (substr($page, 0, 1) == '*')) { $page = intval(substr($page, 1)); @@ -4739,12 +4820,12 @@ class TCPDF { /** * Puts a link on a rectangular area of the page. * Text or image links are generally put via Cell(), Write() or Image(), but this method can be useful for instance to define a clickable area inside an image. - * @param $x (float) Abscissa of the upper-left corner of the rectangle - * @param $y (float) Ordinate of the upper-left corner of the rectangle - * @param $w (float) Width of the rectangle - * @param $h (float) Height of the rectangle - * @param $link (mixed) URL or identifier returned by AddLink() - * @param $spaces (int) number of spaces on the text to link + * @param float $x Abscissa of the upper-left corner of the rectangle + * @param float $y Ordinate of the upper-left corner of the rectangle + * @param float $w Width of the rectangle + * @param float $h Height of the rectangle + * @param mixed $link URL or identifier returned by AddLink() + * @param int $spaces number of spaces on the text to link * @public * @since 1.5 * @see AddLink(), Annotation(), Cell(), Write(), Image() @@ -4756,13 +4837,13 @@ class TCPDF { /** * Puts a markup annotation on a rectangular area of the page. * !!!!THE ANNOTATION SUPPORT IS NOT YET FULLY IMPLEMENTED !!!! - * @param $x (float) Abscissa of the upper-left corner of the rectangle - * @param $y (float) Ordinate of the upper-left corner of the rectangle - * @param $w (float) Width of the rectangle - * @param $h (float) Height of the rectangle - * @param $text (string) annotation text or alternate content - * @param $opt (array) array of options (see section 8.4 of PDF reference 1.7). - * @param $spaces (int) number of spaces on the text to link + * @param float $x Abscissa of the upper-left corner of the rectangle + * @param float $y Ordinate of the upper-left corner of the rectangle + * @param float $w Width of the rectangle + * @param float $h Height of the rectangle + * @param string $text annotation text or alternate content + * @param array $opt array of options (see section 8.4 of PDF reference 1.7). + * @param int $spaces number of spaces on the text to link * @public * @since 4.0.018 (2008-08-06) */ @@ -4863,7 +4944,7 @@ class TCPDF { } reset($this->embeddedfiles); foreach ($this->embeddedfiles as $filename => $filedata) { - $data = TCPDF_STATIC::fileGetContents($filedata['file']); + $data = $this->getCachedFileContents($filedata['file']); if ($data !== FALSE) { $rawsize = strlen($data); if ($rawsize > 0) { @@ -4902,31 +4983,31 @@ class TCPDF { /** * Prints a text cell at the specified position. * This method allows to place a string precisely on the page. - * @param $x (float) Abscissa of the cell origin - * @param $y (float) Ordinate of the cell origin - * @param $txt (string) String to print - * @param $fstroke (int) outline size in user units (false = disable) - * @param $fclip (boolean) if true activate clipping mode (you must call StartTransform() before this function and StopTransform() to stop the clipping tranformation). - * @param $ffill (boolean) if true fills the text - * @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) - * @param $ln (int) Indicates where the current position should go after the call. Possible values are:
              • 0: to the right (or left for RTL languages)
              • 1: to the beginning of the next line
              • 2: below
              Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. - * @param $align (string) Allows to center or align the text. Possible values are:
              • L or empty string: left align (default value)
              • C: center
              • R: right align
              • J: justify
              - * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false). - * @param $link (mixed) URL or identifier returned by AddLink(). - * @param $stretch (int) font stretch mode:
              • 0 = disabled
              • 1 = horizontal scaling only if text is larger than cell width
              • 2 = forced horizontal scaling to fit cell width
              • 3 = character spacing only if text is larger than cell width
              • 4 = forced character spacing to fit cell width
              General font stretching and scaling values will be preserved when possible. - * @param $ignore_min_height (boolean) if true ignore automatic minimum height value. - * @param $calign (string) cell vertical alignment relative to the specified Y value. Possible values are:
              • T : cell top
              • A : font top
              • L : font baseline
              • D : font bottom
              • B : cell bottom
              - * @param $valign (string) text vertical alignment inside the cell. Possible values are:
              • T : top
              • C : center
              • B : bottom
              - * @param $rtloff (boolean) if true uses the page top-left corner as origin of axis for $x and $y initial position. + * @param float $x Abscissa of the cell origin + * @param float $y Ordinate of the cell origin + * @param string $txt String to print + * @param int $fstroke outline size in user units (0 = disable) + * @param boolean $fclip if true activate clipping mode (you must call StartTransform() before this function and StopTransform() to stop the clipping tranformation). + * @param boolean $ffill if true fills the text + * @param mixed $border Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) + * @param int $ln Indicates where the current position should go after the call. Possible values are:
              • 0: to the right (or left for RTL languages)
              • 1: to the beginning of the next line
              • 2: below
              Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. + * @param string $align Allows to center or align the text. Possible values are:
              • L or empty string: left align (default value)
              • C: center
              • R: right align
              • J: justify
              + * @param boolean $fill Indicates if the cell background must be painted (true) or transparent (false). + * @param mixed $link URL or identifier returned by AddLink(). + * @param int $stretch font stretch mode:
              • 0 = disabled
              • 1 = horizontal scaling only if text is larger than cell width
              • 2 = forced horizontal scaling to fit cell width
              • 3 = character spacing only if text is larger than cell width
              • 4 = forced character spacing to fit cell width
              General font stretching and scaling values will be preserved when possible. + * @param boolean $ignore_min_height if true ignore automatic minimum height value. + * @param string $calign cell vertical alignment relative to the specified Y value. Possible values are:
              • T : cell top
              • A : font top
              • L : font baseline
              • D : font bottom
              • B : cell bottom
              + * @param string $valign text vertical alignment inside the cell. Possible values are:
              • T : top
              • C : center
              • B : bottom
              + * @param boolean $rtloff if true uses the page top-left corner as origin of axis for $x and $y initial position. * @public * @since 1.0 * @see Cell(), Write(), MultiCell(), WriteHTML(), WriteHTMLCell() */ - public function Text($x, $y, $txt, $fstroke=false, $fclip=false, $ffill=true, $border=0, $ln=0, $align='', $fill=false, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='M', $rtloff=false) { + public function Text($x, $y, $txt, $fstroke=0, $fclip=false, $ffill=true, $border=0, $ln=0, $align='', $fill=false, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='M', $rtloff=false) { $textrendermode = $this->textrendermode; $textstrokewidth = $this->textstrokewidth; $this->setTextRenderingMode($fstroke, $ffill, $fclip); - $this->SetXY($x, $y, $rtloff); + $this->setXY($x, $y, $rtloff); $this->Cell(0, 0, $txt, $border, $ln, $align, $fill, $link, $stretch, $ignore_min_height, $calign, $valign); // restore previous rendering mode $this->textrendermode = $textrendermode; @@ -4937,7 +5018,7 @@ class TCPDF { * Whenever a page break condition is met, the method is called, and the break is issued or not depending on the returned value. * The default implementation returns a value according to the mode selected by SetAutoPageBreak().
              * This method is called automatically and should not be called directly by the application. - * @return boolean + * @return bool * @public * @since 1.4 * @see SetAutoPageBreak() @@ -4962,14 +5043,14 @@ class TCPDF { /** * Add page if needed. - * @param $h (float) Cell height. Default value: 0. - * @param $y (mixed) starting y position, leave empty for current position. - * @param $addpage (boolean) if true add a page, otherwise only return the true/false state - * @return boolean true in case of page break, false otherwise. + * @param float $h Cell height. Default value: 0. + * @param float|null $y starting y position, leave empty for current position. + * @param bool $addpage if true add a page, otherwise only return the true/false state + * @return bool true in case of page break, false otherwise. * @since 3.2.000 (2008-07-01) * @protected */ - protected function checkPageBreak($h=0, $y='', $addpage=true) { + protected function checkPageBreak($h=0, $y=null, $addpage=true) { if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } @@ -5007,18 +5088,18 @@ class TCPDF { /** * Prints a cell (rectangular area) with optional borders, background color and character string. The upper-left corner of the cell corresponds to the current position. The text can be aligned or centered. After the call, the current position moves to the right or to the next line. It is possible to put a link on the text.
              * If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting. - * @param $w (float) Cell width. If 0, the cell extends up to the right margin. - * @param $h (float) Cell height. Default value: 0. - * @param $txt (string) String to print. Default value: empty string. - * @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) - * @param $ln (int) Indicates where the current position should go after the call. Possible values are:
              • 0: to the right (or left for RTL languages)
              • 1: to the beginning of the next line
              • 2: below
              Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. - * @param $align (string) Allows to center or align the text. Possible values are:
              • L or empty string: left align (default value)
              • C: center
              • R: right align
              • J: justify
              - * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false). - * @param $link (mixed) URL or identifier returned by AddLink(). - * @param $stretch (int) font stretch mode:
              • 0 = disabled
              • 1 = horizontal scaling only if text is larger than cell width
              • 2 = forced horizontal scaling to fit cell width
              • 3 = character spacing only if text is larger than cell width
              • 4 = forced character spacing to fit cell width
              General font stretching and scaling values will be preserved when possible. - * @param $ignore_min_height (boolean) if true ignore automatic minimum height value. - * @param $calign (string) cell vertical alignment relative to the specified Y value. Possible values are:
              • T : cell top
              • C : center
              • B : cell bottom
              • A : font top
              • L : font baseline
              • D : font bottom
              - * @param $valign (string) text vertical alignment inside the cell. Possible values are:
              • T : top
              • C : center
              • B : bottom
              + * @param float $w Cell width. If 0, the cell extends up to the right margin. + * @param float $h Cell height. Default value: 0. + * @param string $txt String to print. Default value: empty string. + * @param mixed $border Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) + * @param int $ln Indicates where the current position should go after the call. Possible values are:
              • 0: to the right (or left for RTL languages)
              • 1: to the beginning of the next line
              • 2: below
              Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. + * @param string $align Allows to center or align the text. Possible values are:
              • L or empty string: left align (default value)
              • C: center
              • R: right align
              • J: justify
              + * @param boolean $fill Indicates if the cell background must be painted (true) or transparent (false). + * @param mixed $link URL or identifier returned by AddLink(). + * @param int $stretch font stretch mode:
              • 0 = disabled
              • 1 = horizontal scaling only if text is larger than cell width
              • 2 = forced horizontal scaling to fit cell width
              • 3 = character spacing only if text is larger than cell width
              • 4 = forced character spacing to fit cell width
              General font stretching and scaling values will be preserved when possible. + * @param boolean $ignore_min_height if true ignore automatic minimum height value. + * @param string $calign cell vertical alignment relative to the specified Y value. Possible values are:
              • T : cell top
              • C : center
              • B : cell bottom
              • A : font top
              • L : font baseline
              • D : font bottom
              + * @param string $valign text vertical alignment inside the cell. Possible values are:
              • T : top
              • C : center
              • B : bottom
              * @public * @since 1.0 * @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), AddLink(), Ln(), MultiCell(), Write(), SetAutoPageBreak() @@ -5046,9 +5127,9 @@ class TCPDF { // print shadow $this->x += $this->txtshadow['depth_w']; $this->y += $this->txtshadow['depth_h']; - $this->SetFillColorArray($this->txtshadow['color']); - $this->SetTextColorArray($this->txtshadow['color']); - $this->SetDrawColorArray($this->txtshadow['color']); + $this->setFillColorArray($this->txtshadow['color']); + $this->setTextColorArray($this->txtshadow['color']); + $this->setDrawColorArray($this->txtshadow['color']); if ($this->txtshadow['opacity'] != $alpha['CA']) { $this->setAlpha($this->txtshadow['opacity'], $this->txtshadow['blend_mode']); } @@ -5058,9 +5139,9 @@ class TCPDF { //restore data $this->x = $x; $this->y = $y; - $this->SetFillColorArray($bc); - $this->SetTextColorArray($fc); - $this->SetDrawColorArray($sc); + $this->setFillColorArray($bc); + $this->setTextColorArray($fc); + $this->setDrawColorArray($sc); if ($this->txtshadow['opacity'] != $alpha['CA']) { $this->setAlpha($alpha['CA'], $alpha['BM'], $alpha['ca'], $alpha['AIS']); } @@ -5075,18 +5156,18 @@ class TCPDF { /** * Returns the PDF string code to print a cell (rectangular area) with optional borders, background color and character string. The upper-left corner of the cell corresponds to the current position. The text can be aligned or centered. After the call, the current position moves to the right or to the next line. It is possible to put a link on the text.
              * If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting. - * @param $w (float) Cell width. If 0, the cell extends up to the right margin. - * @param $h (float) Cell height. Default value: 0. - * @param $txt (string) String to print. Default value: empty string. - * @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) - * @param $ln (int) Indicates where the current position should go after the call. Possible values are:
              • 0: to the right (or left for RTL languages)
              • 1: to the beginning of the next line
              • 2: below
              Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. - * @param $align (string) Allows to center or align the text. Possible values are:
              • L or empty string: left align (default value)
              • C: center
              • R: right align
              • J: justify
              - * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false). - * @param $link (mixed) URL or identifier returned by AddLink(). - * @param $stretch (int) font stretch mode:
              • 0 = disabled
              • 1 = horizontal scaling only if text is larger than cell width
              • 2 = forced horizontal scaling to fit cell width
              • 3 = character spacing only if text is larger than cell width
              • 4 = forced character spacing to fit cell width
              General font stretching and scaling values will be preserved when possible. - * @param $ignore_min_height (boolean) if true ignore automatic minimum height value. - * @param $calign (string) cell vertical alignment relative to the specified Y value. Possible values are:
              • T : cell top
              • C : center
              • B : cell bottom
              • A : font top
              • L : font baseline
              • D : font bottom
              - * @param $valign (string) text vertical alignment inside the cell. Possible values are:
              • T : top
              • M : middle
              • B : bottom
              + * @param float $w Cell width. If 0, the cell extends up to the right margin. + * @param float $h Cell height. Default value: 0. + * @param string $txt String to print. Default value: empty string. + * @param mixed $border Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) + * @param int $ln Indicates where the current position should go after the call. Possible values are:
              • 0: to the right (or left for RTL languages)
              • 1: to the beginning of the next line
              • 2: below
              Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. + * @param string $align Allows to center or align the text. Possible values are:
              • L or empty string: left align (default value)
              • C: center
              • R: right align
              • J: justify
              + * @param boolean $fill Indicates if the cell background must be painted (true) or transparent (false). + * @param mixed $link URL or identifier returned by AddLink(). + * @param int $stretch font stretch mode:
              • 0 = disabled
              • 1 = horizontal scaling only if text is larger than cell width
              • 2 = forced horizontal scaling to fit cell width
              • 3 = character spacing only if text is larger than cell width
              • 4 = forced character spacing to fit cell width
              General font stretching and scaling values will be preserved when possible. + * @param boolean $ignore_min_height if true ignore automatic minimum height value. + * @param string $calign cell vertical alignment relative to the specified Y value. Possible values are:
              • T : cell top
              • C : center
              • B : cell bottom
              • A : font top
              • L : font baseline
              • D : font bottom
              + * @param string $valign text vertical alignment inside the cell. Possible values are:
              • T : top
              • M : middle
              • B : bottom
              * @return string containing cell code * @protected * @since 1.0 @@ -5094,6 +5175,7 @@ class TCPDF { */ protected function getCellCode($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='M') { // replace 'NO-BREAK SPACE' (U+00A0) character with a simple space + $txt = is_null($txt) ? '' : $txt; $txt = str_replace(TCPDF_FONTS::unichr(160, $this->isunicode), ' ', $txt); $prev_cell_margin = $this->cell_margin; $prev_cell_padding = $this->cell_padding; @@ -5469,12 +5551,12 @@ class TCPDF { $xdk = $xdx * $k; // print text $s .= sprintf('BT %F %F Td [(%s)] TJ ET', $xdk, (($this->h - $basefonty) * $k), $txt2); - if (isset($uniblock)) { + if (isset($uniblock)) { // @phpstan-ignore-line // print overlapping characters as separate string $xshift = 0; // horizontal shift $ty = (($this->h - $basefonty + (0.2 * $this->FontSize)) * $k); $spw = (($w - $txwidth - $this->cell_padding['L'] - $this->cell_padding['R']) / ($ns?$ns:1)); - foreach ($uniblock as $uk => $uniarr) { + foreach ($uniblock as $uk => $uniarr) { // @phpstan-ignore-line if (($uk % 2) == 0) { // x space to skip if ($spacewidth != 0) { @@ -5554,8 +5636,8 @@ class TCPDF { /** * Replace a char if is defined on the current font. - * @param $oldchar (int) Integer code (unicode) of the character to replace. - * @param $newchar (int) Integer code (unicode) of the new character. + * @param int $oldchar Integer code (unicode) of the character to replace. + * @param int $newchar Integer code (unicode) of the new character. * @return int the replaced char or the old char in case the new char i not defined * @protected * @since 5.9.167 (2012-06-22) @@ -5573,11 +5655,11 @@ class TCPDF { /** * Returns the code to draw the cell border - * @param $x (float) X coordinate. - * @param $y (float) Y coordinate. - * @param $w (float) Cell width. - * @param $h (float) Cell height. - * @param $brd (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) + * @param float $x X coordinate. + * @param float $y Y coordinate. + * @param float $w Cell width. + * @param float $h Cell height. + * @param string|array|int $brd Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) * @return string containing cell border code * @protected * @see SetLineStyle() @@ -5625,7 +5707,7 @@ class TCPDF { if (is_array($style) AND !empty($style)) { // apply border style $prev_style = $this->linestyleWidth.' '.$this->linestyleCap.' '.$this->linestyleJoin.' '.$this->linestyleDash.' '.$this->DrawColor.' '; - $s .= $this->SetLineStyle($style, true)."\n"; + $s .= $this->setLineStyle($style, true)."\n"; } switch ($mode) { case 'ext': { @@ -5765,28 +5847,28 @@ class TCPDF { * This method allows printing text with line breaks. * They can be automatic (as soon as the text reaches the right border of the cell) or explicit (via the \n character). As many cells as necessary are output, one below the other.
              * Text can be aligned, centered or justified. The cell block can be framed and the background painted. - * @param $w (float) Width of cells. If 0, they extend up to the right margin of the page. - * @param $h (float) Cell minimum height. The cell extends automatically if needed. - * @param $txt (string) String to print - * @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) - * @param $align (string) Allows to center or align the text. Possible values are:
              • L or empty string: left align
              • C: center
              • R: right align
              • J: justification (default value when $ishtml=false)
              - * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false). - * @param $ln (int) Indicates where the current position should go after the call. Possible values are:
              • 0: to the right
              • 1: to the beginning of the next line [DEFAULT]
              • 2: below
              - * @param $x (float) x position in user units - * @param $y (float) y position in user units - * @param $reseth (boolean) if true reset the last cell height (default true). - * @param $stretch (int) font stretch mode:
              • 0 = disabled
              • 1 = horizontal scaling only if text is larger than cell width
              • 2 = forced horizontal scaling to fit cell width
              • 3 = character spacing only if text is larger than cell width
              • 4 = forced character spacing to fit cell width
              General font stretching and scaling values will be preserved when possible. - * @param $ishtml (boolean) INTERNAL USE ONLY -- set to true if $txt is HTML content (default = false). Never set this parameter to true, use instead writeHTMLCell() or writeHTML() methods. - * @param $autopadding (boolean) if true, uses internal padding and automatically adjust it to account for line width. - * @param $maxh (float) maximum height. It should be >= $h and less then remaining space to the bottom of the page, or 0 for disable this feature. This feature works only when $ishtml=false. - * @param $valign (string) Vertical alignment of text (requires $maxh = $h > 0). Possible values are:
              • T: TOP
              • M: middle
              • B: bottom
              . This feature works only when $ishtml=false and the cell must fit in a single page. - * @param $fitcell (boolean) if true attempt to fit all the text within the cell by reducing the font size (do not work in HTML mode). $maxh must be greater than 0 and equal to $h. + * @param float $w Width of cells. If 0, they extend up to the right margin of the page. + * @param float $h Cell minimum height. The cell extends automatically if needed. + * @param string $txt String to print + * @param mixed $border Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) + * @param string $align Allows to center or align the text. Possible values are:
              • L or empty string: left align
              • C: center
              • R: right align
              • J: justification (default value when $ishtml=false)
              + * @param boolean $fill Indicates if the cell background must be painted (true) or transparent (false). + * @param int $ln Indicates where the current position should go after the call. Possible values are:
              • 0: to the right
              • 1: to the beginning of the next line [DEFAULT]
              • 2: below
              + * @param float|null $x x position in user units + * @param float|null $y y position in user units + * @param boolean $reseth if true reset the last cell height (default true). + * @param int $stretch font stretch mode:
              • 0 = disabled
              • 1 = horizontal scaling only if text is larger than cell width
              • 2 = forced horizontal scaling to fit cell width
              • 3 = character spacing only if text is larger than cell width
              • 4 = forced character spacing to fit cell width
              General font stretching and scaling values will be preserved when possible. + * @param boolean $ishtml INTERNAL USE ONLY -- set to true if $txt is HTML content (default = false). Never set this parameter to true, use instead writeHTMLCell() or writeHTML() methods. + * @param boolean $autopadding if true, uses internal padding and automatically adjust it to account for line width. + * @param float $maxh maximum height. It should be >= $h and less then remaining space to the bottom of the page, or 0 for disable this feature. This feature works only when $ishtml=false. + * @param string $valign Vertical alignment of text (requires $maxh = $h > 0). Possible values are:
              • T: TOP
              • M: middle
              • B: bottom
              . This feature works only when $ishtml=false and the cell must fit in a single page. + * @param boolean $fitcell if true attempt to fit all the text within the cell by reducing the font size (do not work in HTML mode). $maxh must be greater than 0 and equal to $h. * @return int Return the number of cells or 1 for html mode. * @public * @since 1.3 * @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), Cell(), Write(), SetAutoPageBreak() */ - public function MultiCell($w, $h, $txt, $border=0, $align='J', $fill=false, $ln=1, $x='', $y='', $reseth=true, $stretch=0, $ishtml=false, $autopadding=true, $maxh=0, $valign='T', $fitcell=false) { + public function MultiCell($w, $h, $txt, $border=0, $align='J', $fill=false, $ln=1, $x=null, $y=null, $reseth=true, $stretch=0, $ishtml=false, $autopadding=true, $maxh=0, $valign='T', $fitcell=false) { $prev_cell_margin = $this->cell_margin; $prev_cell_padding = $this->cell_padding; // adjust internal padding @@ -5801,7 +5883,7 @@ class TCPDF { $this->resetLastH(); } if (!TCPDF_STATIC::empty_string($y)) { - $this->SetY($y); // set y in order to convert negative y values to positive ones + $this->setY($y); // set y in order to convert negative y values to positive ones } $y = $this->GetY(); $resth = 0; @@ -5816,7 +5898,7 @@ class TCPDF { // get current column $startcolumn = $this->current_column; if (!TCPDF_STATIC::empty_string($x)) { - $this->SetX($x); + $this->setX($x); } else { $x = $this->GetX(); } @@ -5877,7 +5959,7 @@ class TCPDF { $maxit = (2 * min(100, max(10, intval($fmax)))); // max number of iterations while ($maxit >= 0) { $fmid = (($fmax + $fmin) / 2); - $this->SetFontSize($fmid, false); + $this->setFontSize($fmid, false); $this->resetLastH(); $text_height = $this->getStringHeight($w, $txt, $reseth, $autopadding, $mc_padding, $border); $diff = ($maxh - $text_height); @@ -5893,11 +5975,11 @@ class TCPDF { } if ($maxit < 0) { // premature exit, we get the minimum font value to fit the cell - $this->SetFontSize($fmin); + $this->setFontSize($fmin); $this->resetLastH(); $text_height = $this->getStringHeight($w, $txt, $reseth, $autopadding, $mc_padding, $border); } else { - $this->SetFontSize($fmid); + $this->setFontSize($fmid); $this->resetLastH(); } } @@ -5914,7 +5996,7 @@ class TCPDF { $nl = $this->Write($this->lasth, $txt, '', 0, $align, true, $stretch, false, true, $maxh, 0, $mc_margin); if ($fitcell) { // restore font size - $this->SetFontSize($prev_FontSizePt); + $this->setFontSize($prev_FontSizePt); } } if ($autopadding) { @@ -5961,7 +6043,7 @@ class TCPDF { $this->setPage($page); if ($this->num_columns < 2) { // single-column mode - $this->SetX($x); + $this->setX($x); $this->y = $this->tMargin; } // account for margin changes @@ -6123,15 +6205,15 @@ class TCPDF { } if ($ln > 0) { //Go to the beginning of the next line - $this->SetY($currentY + $mc_margin['B']); + $this->setY($currentY + $mc_margin['B']); if ($ln == 2) { - $this->SetX($x + $w + $mc_margin['L'] + $mc_margin['R']); + $this->setX($x + $w + $mc_margin['L'] + $mc_margin['R']); } } else { // go left or right by case $this->setPage($startpage); $this->y = $y; - $this->SetX($x + $w + $mc_margin['L'] + $mc_margin['R']); + $this->setX($x + $w + $mc_margin['L'] + $mc_margin['R']); } $this->setContentMark(); $this->cell_padding = $prev_cell_padding; @@ -6143,18 +6225,18 @@ class TCPDF { /** * This method return the estimated number of lines for print a simple text string using Multicell() method. - * @param $txt (string) String for calculating his height - * @param $w (float) Width of cells. If 0, they extend up to the right margin of the page. - * @param $reseth (boolean) if true reset the last cell height (default false). - * @param $autopadding (boolean) if true, uses internal padding and automatically adjust it to account for line width (default true). - * @param $cellpadding (float) Internal cell padding, if empty uses default cell padding. - * @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) + * @param string $txt String for calculating his height + * @param float $w Width of cells. If 0, they extend up to the right margin of the page. + * @param boolean $reseth if true reset the last cell height (default false). + * @param boolean $autopadding if true, uses internal padding and automatically adjust it to account for line width (default true). + * @param array|null $cellpadding Internal cell padding, if empty uses default cell padding. + * @param mixed $border Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) * @return float Return the minimal height needed for multicell method for printing the $txt param. * @author Alexander Escalona Fern\E1ndez, Nicola Asuni * @public * @since 4.5.011 */ - public function getNumLines($txt, $w=0, $reseth=false, $autopadding=true, $cellpadding='', $border=0) { + public function getNumLines($txt, $w=0, $reseth=false, $autopadding=true, $cellpadding=null, $border=0) { if ($txt === NULL) { return 0; } @@ -6237,7 +6319,7 @@ class TCPDF { * $start_page = $pdf->getPage(); * // call your printing functions with your parameters * // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * $pdf->MultiCell($w=0, $h=0, $txt, $border=1, $align='L', $fill=false, $ln=1, $x='', $y='', $reseth=true, $stretch=0, $ishtml=false, $autopadding=true, $maxh=0); + * $pdf->MultiCell($w=0, $h=0, $txt, $border=1, $align='L', $fill=false, $ln=1, $x=null, $y=null, $reseth=true, $stretch=0, $ishtml=false, $autopadding=true, $maxh=0); * // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * // get the new Y * $end_y = $pdf->GetY(); @@ -6263,17 +6345,17 @@ class TCPDF { * // restore previous object * $pdf = $pdf->rollbackTransaction(); * - * @param $w (float) Width of cells. If 0, they extend up to the right margin of the page. - * @param $txt (string) String for calculating his height - * @param $reseth (boolean) if true reset the last cell height (default false). - * @param $autopadding (boolean) if true, uses internal padding and automatically adjust it to account for line width (default true). - * @param $cellpadding (float) Internal cell padding, if empty uses default cell padding. - * @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) + * @param float $w Width of cells. If 0, they extend up to the right margin of the page. + * @param string $txt String for calculating his height + * @param boolean $reseth if true reset the last cell height (default false). + * @param boolean $autopadding if true, uses internal padding and automatically adjust it to account for line width (default true). + * @param array|null $cellpadding Internal cell padding, if empty uses default cell padding. + * @param mixed $border Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) * @return float Return the minimal height needed for multicell method for printing the $txt param. * @author Nicola Asuni, Alexander Escalona Fern\E1ndez * @public */ - public function getStringHeight($w, $txt, $reseth=false, $autopadding=true, $cellpadding='', $border=0) { + public function getStringHeight($w, $txt, $reseth=false, $autopadding=true, $cellpadding=null, $border=0) { // adjust internal padding $prev_cell_padding = $this->cell_padding; $prev_lasth = $this->lasth; @@ -6290,30 +6372,30 @@ class TCPDF { /** * This method prints text from the current position.
              - * @param $h (float) Line height - * @param $txt (string) String to print - * @param $link (mixed) URL or identifier returned by AddLink() - * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false). - * @param $align (string) Allows to center or align the text. Possible values are:
              • L or empty string: left align (default value)
              • C: center
              • R: right align
              • J: justify
              - * @param $ln (boolean) if true set cursor at the bottom of the line, otherwise set cursor at the top of the line. - * @param $stretch (int) font stretch mode:
              • 0 = disabled
              • 1 = horizontal scaling only if text is larger than cell width
              • 2 = forced horizontal scaling to fit cell width
              • 3 = character spacing only if text is larger than cell width
              • 4 = forced character spacing to fit cell width
              General font stretching and scaling values will be preserved when possible. - * @param $firstline (boolean) if true prints only the first line and return the remaining string. - * @param $firstblock (boolean) if true the string is the starting of a line. - * @param $maxh (float) maximum height. It should be >= $h and less then remaining space to the bottom of the page, or 0 for disable this feature. - * @param $wadj (float) first line width will be reduced by this amount (used in HTML mode). - * @param $margin (array) margin array of the parent container + * @param float $h Line height + * @param string $txt String to print + * @param mixed $link URL or identifier returned by AddLink() + * @param boolean $fill Indicates if the cell background must be painted (true) or transparent (false). + * @param string $align Allows to center or align the text. Possible values are:
              • L or empty string: left align (default value)
              • C: center
              • R: right align
              • J: justify
              + * @param boolean $ln if true set cursor at the bottom of the line, otherwise set cursor at the top of the line. + * @param int $stretch font stretch mode:
              • 0 = disabled
              • 1 = horizontal scaling only if text is larger than cell width
              • 2 = forced horizontal scaling to fit cell width
              • 3 = character spacing only if text is larger than cell width
              • 4 = forced character spacing to fit cell width
              General font stretching and scaling values will be preserved when possible. + * @param boolean $firstline if true prints only the first line and return the remaining string. + * @param boolean $firstblock if true the string is the starting of a line. + * @param float $maxh maximum height. It should be >= $h and less then remaining space to the bottom of the page, or 0 for disable this feature. + * @param float $wadj first line width will be reduced by this amount (used in HTML mode). + * @param array|null $margin margin array of the parent container * @return mixed Return the number of cells or the remaining string if $firstline = true. * @public * @since 1.5 */ - public function Write($h, $txt, $link='', $fill=false, $align='', $ln=false, $stretch=0, $firstline=false, $firstblock=false, $maxh=0, $wadj=0, $margin='') { + public function Write($h, $txt, $link='', $fill=false, $align='', $ln=false, $stretch=0, $firstline=false, $firstblock=false, $maxh=0, $wadj=0, $margin=null) { // check page for no-write regions and adapt page margins if necessary list($this->x, $this->y) = $this->checkPageRegions($h, $this->x, $this->y); if (strlen($txt) == 0) { // fix empty text $txt = ' '; } - if ($margin === '') { + if (!is_array($margin)) { // set default margins $margin = $this->cell_margin; } @@ -6338,7 +6420,7 @@ class TCPDF { // calculate maximum width for a single character on string $chrw = $this->GetArrStringWidth($chars, '', '', 0, true); array_walk($chrw, array($this, 'getRawCharWidth')); - $maxchwidth = max($chrw); + $maxchwidth = ((is_array($chrw) || $chrw instanceof Countable) && count($chrw) > 0) ? max($chrw) : 0; // get array of chars $uchars = TCPDF_FONTS::UTF8ArrayToUniArray($chars, $this->isunicode); // get the number of characters @@ -6415,7 +6497,7 @@ class TCPDF { $w = $linew; $tmpcellpadding = $this->cell_padding; if ($maxh == 0) { - $this->SetCellPadding(0); + $this->setCellPadding(0); } } if ($firstblock AND $this->isRTLTextDir()) { @@ -6438,14 +6520,16 @@ class TCPDF { $shy = false; // account for margin changes if ((($this->y + $this->lasth) > $this->PageBreakTrigger) AND ($this->inPageBody())) { - $this->AcceptPageBreak(); - if ($this->rtl) { - $this->x -= $margin['R']; - } else { - $this->x += $margin['L']; + if ($this->AcceptPageBreak()) + { + if ($this->rtl) { + $this->x -= $margin['R']; + } else { + $this->x += $margin['L']; + } + $this->lMargin += $margin['L']; + $this->rMargin += $margin['R']; } - $this->lMargin += $margin['L']; - $this->rMargin += $margin['R']; } $w = $this->getRemainingWidth(); $wmax = ($w - $this->cell_padding['L'] - $this->cell_padding['R']); @@ -6489,7 +6573,7 @@ class TCPDF { // *** very slow *** $l = $this->GetArrStringWidth(TCPDF_FONTS::utf8Bidi(array_slice($chars, $j, ($i - $j)), '', $this->tmprtl, $this->isunicode, $this->CurrentFont)); } else { - $l += $this->GetCharWidth($c); + $l += $this->GetCharWidth($c, ($i+1 < $nb)); } if (($l > $wmax) OR (($c == 173) AND (($l + $tmp_shy_replacement_width) >= $wmax))) { if (($c == 173) AND (($l + $tmp_shy_replacement_width) > $wmax)) { @@ -6526,7 +6610,7 @@ class TCPDF { $w = $linew; $tmpcellpadding = $this->cell_padding; if ($maxh == 0) { - $this->SetCellPadding(0); + $this->setCellPadding(0); } } if ($firstblock AND $this->isRTLTextDir()) { @@ -6570,7 +6654,7 @@ class TCPDF { $w = $linew; $tmpcellpadding = $this->cell_padding; if ($maxh == 0) { - $this->SetCellPadding(0); + $this->setCellPadding(0); } } if ($firstblock AND $this->isRTLTextDir()) { @@ -6618,7 +6702,7 @@ class TCPDF { $w = $linew; $tmpcellpadding = $this->cell_padding; if ($maxh == 0) { - $this->SetCellPadding(0); + $this->setCellPadding(0); } } // print the line @@ -6643,14 +6727,16 @@ class TCPDF { } // account for margin changes if ((($this->y + $this->lasth) > $this->PageBreakTrigger) AND ($this->inPageBody())) { - $this->AcceptPageBreak(); - if ($this->rtl) { - $this->x -= $margin['R']; - } else { - $this->x += $margin['L']; + if ($this->AcceptPageBreak()) + { + if ($this->rtl) { + $this->x -= $margin['R']; + } else { + $this->x += $margin['L']; + } + $this->lMargin += $margin['L']; + $this->rMargin += $margin['R']; } - $this->lMargin += $margin['L']; - $this->rMargin += $margin['R']; } $w = $this->getRemainingWidth(); $wmax = $w - $this->cell_padding['L'] - $this->cell_padding['R']; @@ -6671,13 +6757,10 @@ class TCPDF { switch ($align) { case 'J': case 'C': { - $w = $w; break; } case 'L': { - if ($this->rtl) { - $w = $w; - } else { + if (!$this->rtl) { $w = $l; } break; @@ -6685,8 +6768,6 @@ class TCPDF { case 'R': { if ($this->rtl) { $w = $l; - } else { - $w = $w; } break; } @@ -6712,7 +6793,7 @@ class TCPDF { $w = $linew; $tmpcellpadding = $this->cell_padding; if ($maxh == 0) { - $this->SetCellPadding(0); + $this->setCellPadding(0); } } if ($firstblock AND $this->isRTLTextDir()) { @@ -6734,7 +6815,7 @@ class TCPDF { /** * Returns the remaining width between the current position and margins. - * @return int Return the remaining width + * @return float Return the remaining width * @protected */ protected function getRemainingWidth() { @@ -6748,12 +6829,12 @@ class TCPDF { /** * Set the block dimensions accounting for page breaks and page/column fitting - * @param $w (float) width - * @param $h (float) height - * @param $x (float) X coordinate - * @param $y (float) Y coodiante - * @param $fitonpage (boolean) if true the block is resized to not exceed page dimensions. - * @return array($w, $h, $x, $y) + * @param float $w width + * @param float $h height + * @param float $x X coordinate + * @param float $y Y coodiante + * @param boolean $fitonpage if true the block is resized to not exceed page dimensions. + * @return array array($w, $h, $x, $y) * @protected * @since 5.5.009 (2010-07-05) */ @@ -6802,6 +6883,8 @@ class TCPDF { } // resize the block to be contained on the remaining available page or column space if ($fitonpage) { + // fallback to avoid division by zero + $h = $h == 0 ? 1 : $h; $ratio_wh = ($w / $h); if (($y + $h) > $this->PageBreakTrigger) { $h = $this->PageBreakTrigger - $y; @@ -6829,43 +6912,49 @@ class TCPDF { * The format can be specified explicitly or inferred from the file extension.
              * It is possible to put a link on the image.
              * Remark: if an image is used several times, only one copy will be embedded in the file.
              - * @param $file (string) Name of the file containing the image or a '@' character followed by the image data string. To link an image without embedding it on the document, set an asterisk character before the URL (i.e.: '*http://www.example.com/image.jpg'). - * @param $x (float) Abscissa of the upper-left corner (LTR) or upper-right corner (RTL). - * @param $y (float) Ordinate of the upper-left corner (LTR) or upper-right corner (RTL). - * @param $w (float) Width of the image in the page. If not specified or equal to zero, it is automatically calculated. - * @param $h (float) Height of the image in the page. If not specified or equal to zero, it is automatically calculated. - * @param $type (string) Image format. Possible values are (case insensitive): JPEG and PNG (whitout GD library) and all images supported by GD: GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM;. If not specified, the type is inferred from the file extension. - * @param $link (mixed) URL or identifier returned by AddLink(). - * @param $align (string) Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:
              • T: top-right for LTR or top-left for RTL
              • M: middle-right for LTR or middle-left for RTL
              • B: bottom-right for LTR or bottom-left for RTL
              • N: next line
              - * @param $resize (mixed) If true resize (reduce) the image to fit $w and $h (requires GD or ImageMagick library); if false do not resize; if 2 force resize in all cases (upscaling and downscaling). - * @param $dpi (int) dot-per-inch resolution used on resize - * @param $palign (string) Allows to center or align the image on the current line. Possible values are:
              • L : left align
              • C : center
              • R : right align
              • '' : empty string : left for LTR or right for RTL
              - * @param $ismask (boolean) true if this image is a mask, false otherwise - * @param $imgmask (mixed) image object returned by this function or false - * @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) - * @param $fitbox (mixed) If not false scale image dimensions proportionally to fit within the ($w, $h) box. $fitbox can be true or a 2 characters string indicating the image alignment inside the box. The first character indicate the horizontal alignment (L = left, C = center, R = right) the second character indicate the vertical algnment (T = top, M = middle, B = bottom). - * @param $hidden (boolean) If true do not display the image. - * @param $fitonpage (boolean) If true the image is resized to not exceed page dimensions. - * @param $alt (boolean) If true the image will be added as alternative and not directly printed (the ID of the image will be returned). - * @param $altimgs (array) Array of alternate images IDs. Each alternative image must be an array with two values: an integer representing the image ID (the value returned by the Image method) and a boolean value to indicate if the image is the default for printing. - * @return image information + * @param string $file Name of the file containing the image or a '@' character followed by the image data string. To link an image without embedding it on the document, set an asterisk character before the URL (i.e.: '*http://www.example.com/image.jpg'). + * @param float|null $x Abscissa of the upper-left corner (LTR) or upper-right corner (RTL). + * @param float|null $y Ordinate of the upper-left corner (LTR) or upper-right corner (RTL). + * @param float $w Width of the image in the page. If not specified or equal to zero, it is automatically calculated. + * @param float $h Height of the image in the page. If not specified or equal to zero, it is automatically calculated. + * @param string $type Image format. Possible values are (case insensitive): JPEG and PNG (whitout GD library) and all images supported by GD: GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM;. If not specified, the type is inferred from the file extension. + * @param mixed $link URL or identifier returned by AddLink(). + * @param string $align Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:
              • T: top-right for LTR or top-left for RTL
              • M: middle-right for LTR or middle-left for RTL
              • B: bottom-right for LTR or bottom-left for RTL
              • N: next line
              + * @param mixed $resize If true resize (reduce) the image to fit $w and $h (requires GD or ImageMagick library); if false do not resize; if 2 force resize in all cases (upscaling and downscaling). + * @param int $dpi dot-per-inch resolution used on resize + * @param string $palign Allows to center or align the image on the current line. Possible values are:
              • L : left align
              • C : center
              • R : right align
              • '' : empty string : left for LTR or right for RTL
              + * @param boolean $ismask true if this image is a mask, false otherwise + * @param mixed $imgmask image object returned by this function or false + * @param mixed $border Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) + * @param mixed $fitbox If not false scale image dimensions proportionally to fit within the ($w, $h) box. $fitbox can be true or a 2 characters string indicating the image alignment inside the box. The first character indicate the horizontal alignment (L = left, C = center, R = right) the second character indicate the vertical algnment (T = top, M = middle, B = bottom). + * @param boolean $hidden If true do not display the image. + * @param boolean $fitonpage If true the image is resized to not exceed page dimensions. + * @param boolean $alt If true the image will be added as alternative and not directly printed (the ID of the image will be returned). + * @param array $altimgs Array of alternate images IDs. Each alternative image must be an array with two values: an integer representing the image ID (the value returned by the Image method) and a boolean value to indicate if the image is the default for printing. + * @return mixed|false image information * @public * @since 1.1 */ - public function Image($file, $x='', $y='', $w=0, $h=0, $type='', $link='', $align='', $resize=false, $dpi=300, $palign='', $ismask=false, $imgmask=false, $border=0, $fitbox=false, $hidden=false, $fitonpage=false, $alt=false, $altimgs=array()) { + public function Image($file, $x=null, $y=null, $w=0, $h=0, $type='', $link='', $align='', $resize=false, $dpi=300, $palign='', $ismask=false, $imgmask=false, $border=0, $fitbox=false, $hidden=false, $fitonpage=false, $alt=false, $altimgs=array()) { if ($this->state != 2) { - return; + return false; } - if (strcmp($x, '') === 0) { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if (strcmp($y, '') === 0) { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } // check page for no-write regions and adapt page margins if necessary list($x, $y) = $this->checkPageRegions($h, $x, $y); $exurl = ''; // external streams $imsize = FALSE; + + // Make sure the file variable is not empty or null because accessing $file[0] later + // results in error when running PHP 7.4 + if (empty($file)) { + return false; + } // check if we are passing an image as file or string if ($file[0] === '@') { // image from string @@ -6877,18 +6966,14 @@ class TCPDF { $exurl = $file; } // check if file exist and it is valid - if (!@TCPDF_STATIC::file_exists($file)) { + if (!@$this->fileExists($file)) { return false; } - if (($imsize = @getimagesize($file)) === FALSE) { - if (in_array($file, $this->imagekeys)) { - // get existing image data - $info = $this->getImageBuffer($file); - $imsize = array($info['w'], $info['h']); - } elseif (strpos($file, '__tcpdf_'.$this->file_id.'_img') === FALSE) { - $imgdata = TCPDF_STATIC::fileGetContents($file); - } - } + if (false !== $info = $this->getImageBuffer($file)) { + $imsize = array($info['w'], $info['h']); + } elseif (($imsize = @getimagesize($file)) === FALSE && strpos($file, '__tcpdf_'.$this->file_id.'_img') === FALSE){ + $imgdata = $this->getCachedFileContents($file); + } } if (!empty($imgdata)) { // copy image to cache @@ -7045,8 +7130,6 @@ class TCPDF { } elseif ($type == 'jpg') { $type = 'jpeg'; } - $mqr = TCPDF_STATIC::get_mqr(); - TCPDF_STATIC::set_mqr(false); // Specific image handlers (defined on TCPDF_IMAGES CLASS) $mtd = '_parse'.$type; // GD image handler function @@ -7093,7 +7176,7 @@ class TCPDF { $svgimg = substr($file, 1); } else { // get SVG file content - $svgimg = TCPDF_STATIC::fileGetContents($file); + $svgimg = $this->getCachedFileContents($file); } if ($svgimg !== FALSE) { // get width and height @@ -7146,9 +7229,8 @@ class TCPDF { } if ($info === false) { // unable to process image - return; + return false; } - TCPDF_STATIC::set_mqr($mqr); if ($ismask) { // force grayscale $info['cs'] = 'DeviceGray'; @@ -7176,9 +7258,9 @@ class TCPDF { } elseif ($palign == 'R') { $ximg = $this->w - $this->rMargin - $w; } else { - $ximg = $x; + $ximg = $this->rtl ? $x - $w : $x; } - + if ($ismask OR $hidden) { // image is not displayed return $info['i']; @@ -7221,7 +7303,7 @@ class TCPDF { break; } case 'N': { - $this->SetY($this->img_rb_y); + $this->setY($this->img_rb_y); break; } default:{ @@ -7238,20 +7320,20 @@ class TCPDF { /** * Extract info from a PNG image with alpha channel using the Imagick or GD library. - * @param $file (string) Name of the file containing the image. - * @param $x (float) Abscissa of the upper-left corner. - * @param $y (float) Ordinate of the upper-left corner. - * @param $wpx (float) Original width of the image in pixels. - * @param $hpx (float) original height of the image in pixels. - * @param $w (float) Width of the image in the page. If not specified or equal to zero, it is automatically calculated. - * @param $h (float) Height of the image in the page. If not specified or equal to zero, it is automatically calculated. - * @param $type (string) Image format. Possible values are (case insensitive): JPEG and PNG (whitout GD library) and all images supported by GD: GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM;. If not specified, the type is inferred from the file extension. - * @param $link (mixed) URL or identifier returned by AddLink(). - * @param $align (string) Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:
              • T: top-right for LTR or top-left for RTL
              • M: middle-right for LTR or middle-left for RTL
              • B: bottom-right for LTR or bottom-left for RTL
              • N: next line
              - * @param $resize (boolean) If true resize (reduce) the image to fit $w and $h (requires GD library). - * @param $dpi (int) dot-per-inch resolution used on resize - * @param $palign (string) Allows to center or align the image on the current line. Possible values are:
              • L : left align
              • C : center
              • R : right align
              • '' : empty string : left for LTR or right for RTL
              - * @param $filehash (string) File hash used to build unique file names. + * @param string $file Name of the file containing the image. + * @param float $x Abscissa of the upper-left corner. + * @param float $y Ordinate of the upper-left corner. + * @param float $wpx Original width of the image in pixels. + * @param float $hpx original height of the image in pixels. + * @param float $w Width of the image in the page. If not specified or equal to zero, it is automatically calculated. + * @param float $h Height of the image in the page. If not specified or equal to zero, it is automatically calculated. + * @param string $type Image format. Possible values are (case insensitive): JPEG and PNG (whitout GD library) and all images supported by GD: GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM;. If not specified, the type is inferred from the file extension. + * @param mixed $link URL or identifier returned by AddLink(). + * @param string $align Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:
              • T: top-right for LTR or top-left for RTL
              • M: middle-right for LTR or middle-left for RTL
              • B: bottom-right for LTR or bottom-left for RTL
              • N: next line
              + * @param boolean $resize If true resize (reduce) the image to fit $w and $h (requires GD library). + * @param int $dpi dot-per-inch resolution used on resize + * @param string $palign Allows to center or align the image on the current line. Possible values are:
              • L : left align
              • C : center
              • R : right align
              • '' : empty string : left for LTR or right for RTL
              + * @param string $filehash File hash used to build unique file names. * @author Nicola Asuni * @protected * @since 4.3.007 (2008-12-04) @@ -7315,7 +7397,7 @@ class TCPDF { $color = imagecolorat($img, $xpx, $ypx); // get and correct gamma color $alpha = $this->getGDgamma($img, $color); - imagesetpixel($imgalpha, $xpx, $ypx, $alpha); + imagesetpixel($imgalpha, (int) $xpx, (int) $ypx, (int) $alpha); } } imagepng($imgalpha, $tempfile_alpha); @@ -7346,8 +7428,8 @@ class TCPDF { /** * Get the GD-corrected PNG gamma value from alpha color - * @param $img (int) GD image Resource ID. - * @param $c (int) alpha color + * @param resource $img GD image Resource ID. + * @param int $c alpha color * @protected * @since 4.3.007 (2008-12-04) */ @@ -7355,9 +7437,9 @@ class TCPDF { if (!isset($this->gdgammacache['#'.$c])) { $colors = imagecolorsforindex($img, $c); // GD alpha is only 7 bit (0 -> 127) - $this->gdgammacache['#'.$c] = (((127 - $colors['alpha']) / 127) * 255); + $this->gdgammacache['#'.$c] = (int) (((127 - $colors['alpha']) / 127) * 255); // correct gamma - $this->gdgammacache['#'.$c] = (pow(($this->gdgammacache['#'.$c] / 255), 2.2) * 255); + $this->gdgammacache['#'.$c] = (int) (pow(($this->gdgammacache['#'.$c] / 255), 2.2) * 255); // store the latest values on cache to improve performances if (count($this->gdgammacache) > 8) { // remove one element from the cache array @@ -7370,13 +7452,13 @@ class TCPDF { /** * Performs a line break. * The current abscissa goes back to the left margin and the ordinate increases by the amount passed in parameter. - * @param $h (float) The height of the break. By default, the value equals the height of the last printed cell. - * @param $cell (boolean) if true add the current left (or right o for RTL) padding to the X coordinate + * @param float|null $h The height of the break. By default, the value equals the height of the last printed cell. + * @param boolean $cell if true add the current left (or right o for RTL) padding to the X coordinate * @public * @since 1.0 * @see Cell() */ - public function Ln($h='', $cell=false) { + public function Ln($h=null, $cell=false) { if (($this->num_columns > 1) AND ($this->y == $this->columns[$this->current_column]['y']) AND isset($this->columns[$this->current_column]['x']) AND ($this->x == $this->columns[$this->current_column]['x'])) { // revove vertical space from the top of the column return; @@ -7395,7 +7477,7 @@ class TCPDF { } else { $this->x = $this->lMargin + $cellpadding; } - if (is_string($h)) { + if (TCPDF_STATIC::empty_string($h)) { $h = $this->lasth; } $this->y += $h; @@ -7444,13 +7526,13 @@ class TCPDF { /** * Defines the abscissa of the current position. * If the passed value is negative, it is relative to the right of the page (or left if language is RTL). - * @param $x (float) The value of the abscissa in user units. - * @param $rtloff (boolean) if true always uses the page top-left corner as origin of axis. + * @param float $x The value of the abscissa in user units. + * @param boolean $rtloff if true always uses the page top-left corner as origin of axis. * @public * @since 1.2 * @see GetX(), GetY(), SetY(), SetXY() */ - public function SetX($x, $rtloff=false) { + public function setX($x, $rtloff=false) { $x = floatval($x); if (!$rtloff AND $this->rtl) { if ($x >= 0) { @@ -7476,14 +7558,14 @@ class TCPDF { /** * Moves the current abscissa back to the left margin and sets the ordinate. * If the passed value is negative, it is relative to the bottom of the page. - * @param $y (float) The value of the ordinate in user units. - * @param $resetx (bool) if true (default) reset the X position. - * @param $rtloff (boolean) if true always uses the page top-left corner as origin of axis. + * @param float $y The value of the ordinate in user units. + * @param bool $resetx if true (default) reset the X position. + * @param boolean $rtloff if true always uses the page top-left corner as origin of axis. * @public * @since 1.0 * @see GetX(), GetY(), SetY(), SetXY() */ - public function SetY($y, $resetx=true, $rtloff=false) { + public function setY($y, $resetx=true, $rtloff=false) { $y = floatval($y); if ($resetx) { //reset x @@ -7509,59 +7591,59 @@ class TCPDF { /** * Defines the abscissa and ordinate of the current position. * If the passed values are negative, they are relative respectively to the right and bottom of the page. - * @param $x (float) The value of the abscissa. - * @param $y (float) The value of the ordinate. - * @param $rtloff (boolean) if true always uses the page top-left corner as origin of axis. + * @param float $x The value of the abscissa. + * @param float $y The value of the ordinate. + * @param boolean $rtloff if true always uses the page top-left corner as origin of axis. * @public * @since 1.2 * @see SetX(), SetY() */ - public function SetXY($x, $y, $rtloff=false) { - $this->SetY($y, false, $rtloff); - $this->SetX($x, $rtloff); + public function setXY($x, $y, $rtloff=false) { + $this->setY($y, false, $rtloff); + $this->setX($x, $rtloff); } /** * Set the absolute X coordinate of the current pointer. - * @param $x (float) The value of the abscissa in user units. + * @param float $x The value of the abscissa in user units. * @public * @since 5.9.186 (2012-09-13) * @see setAbsX(), setAbsY(), SetAbsXY() */ - public function SetAbsX($x) { + public function setAbsX($x) { $this->x = floatval($x); } /** * Set the absolute Y coordinate of the current pointer. - * @param $y (float) (float) The value of the ordinate in user units. + * @param float $y (float) The value of the ordinate in user units. * @public * @since 5.9.186 (2012-09-13) * @see setAbsX(), setAbsY(), SetAbsXY() */ - public function SetAbsY($y) { + public function setAbsY($y) { $this->y = floatval($y); } /** * Set the absolute X and Y coordinates of the current pointer. - * @param $x (float) The value of the abscissa in user units. - * @param $y (float) (float) The value of the ordinate in user units. + * @param float $x The value of the abscissa in user units. + * @param float $y (float) The value of the ordinate in user units. * @public * @since 5.9.186 (2012-09-13) * @see setAbsX(), setAbsY(), SetAbsXY() */ - public function SetAbsXY($x, $y) { - $this->SetAbsX($x); - $this->SetAbsY($y); + public function setAbsXY($x, $y) { + $this->setAbsX($x); + $this->setAbsY($y); } /** * Send the document to a given destination: string, local file or browser. * In the last case, the plug-in may be used (if present) or a download ("Save as" dialog box) may be forced.
              * The method first calls Close() if necessary to terminate the document. - * @param $name (string) The name of the file when saved. Note that special characters are removed and blanks characters are replaced with the underscore character. - * @param $dest (string) Destination where to send the document. It can take one of the following values:
              • I: send the file inline to the browser (default). The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF.
              • D: send to the browser and force a file download with the name given by name.
              • F: save to a local server file with the name given by name.
              • S: return the document as a string (name is ignored).
              • FI: equivalent to F + I option
              • FD: equivalent to F + D option
              • E: return the document as base64 mime multi-part email attachment (RFC 2045)
              + * @param string $name The name of the file when saved + * @param string $dest Destination where to send the document. It can take one of the following values:
              • I: send the file inline to the browser (default). The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF.
              • D: send to the browser and force a file download with the name given by name.
              • F: save to a local server file with the name given by name.
              • S: return the document as a string (name is ignored).
              • FI: equivalent to F + I option
              • FD: equivalent to F + D option
              • E: return the document as base64 mime multi-part email attachment (RFC 2045)
              * @return string * @public * @since 1.0 @@ -7578,10 +7660,7 @@ class TCPDF { $dest = $dest ? 'D' : 'F'; } $dest = strtoupper($dest); - if ($dest[0] != 'F') { - $name = preg_replace('/[\s]+/', '_', $name); - $name = preg_replace('/[^a-zA-Z0-9_\.-]/', '', $name); - } + if ($this->sign) { // *** apply digital signature to the document *** // get the document content @@ -7652,7 +7731,8 @@ class TCPDF { header('Pragma: public'); header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - header('Content-Disposition: inline; filename="'.basename($name).'"'); + header('Content-Disposition: inline; filename="' . rawurlencode(basename($name)) . '"; ' . + 'filename*=UTF-8\'\'' . rawurlencode(basename($name))); TCPDF_STATIC::sendOutputData($this->getBuffer(), $this->bufferlen); } else { echo $this->getBuffer(); @@ -7683,7 +7763,8 @@ class TCPDF { header('Content-Type: application/pdf'); } // use the Content-Disposition header to supply a recommended filename - header('Content-Disposition: attachment; filename="'.basename($name).'"'); + header('Content-Disposition: attachment; filename="' . rawurlencode(basename($name)) . '"; ' . + 'filename*=UTF-8\'\'' . rawurlencode(basename($name))); header('Content-Transfer-Encoding: binary'); TCPDF_STATIC::sendOutputData($this->getBuffer(), $this->bufferlen); break; @@ -7761,20 +7842,16 @@ class TCPDF { protected static $cleaned_ids = array(); /** * Unset all class variables except the following critical variables. - * @param $destroyall (boolean) if true destroys all class variables, otherwise preserves critical variables. - * @param $preserve_objcopy (boolean) if true preserves the objcopy variable + * @param boolean $destroyall if true destroys all class variables, otherwise preserves critical variables. + * @param boolean $preserve_objcopy if true preserves the objcopy variable * @public * @since 4.5.016 (2009-02-24) */ public function _destroy($destroyall=false, $preserve_objcopy=false) { - // restore internal encoding - if (isset($this->internal_encoding) AND !empty($this->internal_encoding)) { - mb_internal_encoding($this->internal_encoding); - } if (isset(self::$cleaned_ids[$this->file_id])) { $destroyall = false; } - if ($destroyall AND !$preserve_objcopy) { + if ($destroyall AND !$preserve_objcopy && isset($this->file_id)) { self::$cleaned_ids[$this->file_id] = true; // remove all temporary files if ($handle = @opendir(K_PATH_CACHE)) { @@ -7787,7 +7864,7 @@ class TCPDF { } if (isset($this->imagekeys)) { foreach($this->imagekeys as $file) { - if (strpos($file, K_PATH_CACHE) === 0) { + if (strpos($file, K_PATH_CACHE) === 0 && TCPDF_STATIC::file_exists($file)) { @unlink($file); } } @@ -7795,7 +7872,6 @@ class TCPDF { } $preserve = array( 'file_id', - 'internal_encoding', 'state', 'bufferlen', 'buffer', @@ -7834,7 +7910,7 @@ class TCPDF { /** * Return an array containing variations for the basic page number alias. - * @param $a (string) Base alias. + * @param string $a Base alias. * @return array of page number aliases * @protected */ @@ -7871,10 +7947,10 @@ class TCPDF { /** * Replace right shift page number aliases with spaces to correct right alignment. * This works perfectly only when using monospaced fonts. - * @param $page (string) Page content. - * @param $aliases (array) Array of page aliases. - * @param $diff (int) initial difference to add. - * @return replaced page content. + * @param string $page Page content. + * @param array $aliases Array of page aliases. + * @param int $diff initial difference to add. + * @return string replaced page content. * @protected */ protected function replaceRightShiftPageNumAliases($page, $aliases, $diff) { @@ -7909,7 +7985,7 @@ class TCPDF { /** * Set page boxes to be included on page descriptions. - * @param $boxes (array) Array of page boxes to set on document: ('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox'). + * @param array $boxes Array of page boxes to set on document: ('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox'). * @protected */ protected function setPageBoxTypes($boxes) { @@ -8024,7 +8100,7 @@ class TCPDF { } $out .= ' /Contents '.($this->n + 1).' 0 R'; $out .= ' /Rotate '.$this->pagedim[$n]['Rotate']; - if (!$this->pdfa_mode) { + if (!$this->pdfa_mode || $this->pdfa_version >= 2) { $out .= ' /Group << /Type /Group /S /Transparency /CS /DeviceRGB >>'; } if (isset($this->pagedim[$n]['trans']) AND !empty($this->pagedim[$n]['trans'])) { @@ -8081,14 +8157,14 @@ class TCPDF { /** * Get references to page annotations. - * @param $n (int) page number + * @param int $n page number * @return string * @protected * @author Nicola Asuni * @since 5.0.010 (2010-05-17) */ protected function _getannotsrefs($n) { - if (!(isset($this->PageAnnots[$n]) OR ($this->sign AND isset($this->signature_data['cert_type'])))) { + if (!(isset($this->PageAnnots[$n]) OR count($this->empty_signature_appearance)>0 OR ($this->sign AND isset($this->signature_data['cert_type'])))) { return ''; } $out = ' /Annots ['; @@ -8379,8 +8455,13 @@ class TCPDF { } else { $annots .= ' /Name /Note'; } + $hasStateModel = isset($pl['opt']['statemodel']); + $hasState = isset($pl['opt']['state']); $statemodels = array('Marked', 'Review'); - if (isset($pl['opt']['statemodel']) AND in_array($pl['opt']['statemodel'], $statemodels)) { + if (!$hasStateModel && !$hasState) { + break; + } + if ($hasStateModel AND in_array($pl['opt']['statemodel'], $statemodels)) { $annots .= ' /StateModel /'.$pl['opt']['statemodel']; } else { $pl['opt']['statemodel'] = 'Marked'; @@ -8391,7 +8472,7 @@ class TCPDF { } else { $states = array('Accepted', 'Rejected', 'Cancelled', 'Completed', 'None'); } - if (isset($pl['opt']['state']) AND in_array($pl['opt']['state'], $states)) { + if ($hasState AND in_array($pl['opt']['state'], $states)) { $annots .= ' /State /'.$pl['opt']['state']; } else { if ($pl['opt']['statemodel'] == 'Marked') { @@ -8406,7 +8487,7 @@ class TCPDF { if (is_string($pl['txt']) && !empty($pl['txt'])) { if ($pl['txt'][0] == '#') { // internal destination - $annots .= ' /A <
              >'; + $annots .= ' /A <
              >'; } elseif ($pl['txt'][0] == '%') { // embedded PDF file $filename = basename(substr($pl['txt'], 1)); @@ -8451,7 +8532,7 @@ class TCPDF { } case 'freetext': { if (isset($pl['opt']['da']) AND !empty($pl['opt']['da'])) { - $annots .= ' /DA ('.$pl['opt']['da'].')'; + $annots .= ' /DA '.$this->_datastring($pl['opt']['da']); } if (isset($pl['opt']['q']) AND ($pl['opt']['q'] >= 0) AND ($pl['opt']['q'] <= 2)) { $annots .= ' /Q '.intval($pl['opt']['q']); @@ -8708,7 +8789,7 @@ class TCPDF { $annots .= ' /AA << '.$pl['opt']['aa'].' >>'; } if (isset($pl['opt']['da']) AND !empty($pl['opt']['da'])) { - $annots .= ' /DA ('.$pl['opt']['da'].')'; + $annots .= ' /DA '.$this->_datastring($pl['opt']['da']); } if (isset($pl['opt']['q']) AND ($pl['opt']['q'] >= 0) AND ($pl['opt']['q'] <= 2)) { $annots .= ' /Q '.intval($pl['opt']['q']); @@ -8769,9 +8850,9 @@ class TCPDF { /** * Put appearance streams XObject used to define annotation's appearance states. - * @param $w (int) annotation width - * @param $h (int) annotation height - * @param $stream (string) appearance stream + * @param int $w annotation width + * @param int $h annotation height + * @param string $stream appearance stream * @return int object ID * @protected * @since 4.8.001 (2009-09-09) @@ -8813,8 +8894,6 @@ class TCPDF { $this->_newobj(); $this->_out('<< /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['.$diff.'] >>'."\n".'endobj'); } - $mqr = TCPDF_STATIC::get_mqr(); - TCPDF_STATIC::set_mqr(false); foreach ($this->FontFiles as $file => $info) { // search and get font file to embedd $fontfile = TCPDF_FONTS::getFontFullPath($file, $info['fontdir']); @@ -8868,7 +8947,6 @@ class TCPDF { $this->_out($out); } } - TCPDF_STATIC::set_mqr($mqr); foreach ($this->fontkeys as $k) { //Font objects $font = $this->getFontBuffer($k); @@ -8953,7 +9031,7 @@ class TCPDF { /** * Adds unicode fonts.
              * Based on PDF Reference 1.3 (section 5) - * @param $font (array) font data + * @param array $font font data * @protected * @author Nicola Asuni * @since 1.52.0.TC005 (2005-01-05) @@ -9057,7 +9135,7 @@ class TCPDF { /** * Output CID-0 fonts. * A Type 0 CIDFont contains glyph descriptions based on the Adobe Type 1 font format - * @param $font (array) font data + * @param array $font font data * @protected * @author Andrew Whitehead, Nicola Asuni, Yukihiro Nakadaira * @since 3.2.000 (2008-06-23) @@ -9137,6 +9215,7 @@ class TCPDF { foreach ($this->imagekeys as $file) { $info = $this->getImageBuffer($file); // set object for alternate images array + $altoid = null; if ((!$this->pdfa_mode) AND isset($info['altimgs']) AND !empty($info['altimgs'])) { $altoid = $this->_newobj(); $out = '['; @@ -9184,7 +9263,7 @@ class TCPDF { $out .= ' /Decode [1 0 1 0 1 0 1 0]'; } $out .= ' /BitsPerComponent '.$info['bpc']; - if (isset($altoid) AND ($altoid > 0)) { + if ($altoid > 0) { // reference to alternate images dictionary $out .= ' /Alternates '.$altoid.' 0 R'; } @@ -9278,7 +9357,7 @@ class TCPDF { $out .= ' /Matrix [1 0 0 1 0 0]'; $out .= ' /Resources <<'; $out .= ' /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'; - if (!$this->pdfa_mode) { + if (!$this->pdfa_mode || $this->pdfa_version >= 2) { // transparency if (isset($data['extgstates']) AND !empty($data['extgstates'])) { $out .= ' /ExtGState <<'; @@ -9416,7 +9495,7 @@ class TCPDF { } $out .= ' >>'; } - if (!$this->pdfa_mode) { + if (!$this->pdfa_mode || $this->pdfa_version >= 2) { // transparency if (isset($this->extgstates) AND !empty($this->extgstates)) { $out .= ' /ExtGState <<'; @@ -9530,7 +9609,7 @@ class TCPDF { /** * Set additional XMP data to be added on the default XMP data just before the end of "x:xmpmeta" tag. * IMPORTANT: This data is added as-is without controls, so you have to validate your data before using this method! - * @param $xmp (string) Custom XMP data. + * @param string $xmp Custom XMP data. * @since 5.9.128 (2011-10-06) * @public */ @@ -9541,7 +9620,7 @@ class TCPDF { /** * Set additional XMP data to be added on the default XMP data just before the end of "rdf:RDF" tag. * IMPORTANT: This data is added as-is without controls, so you have to validate your data before using this method! - * @param $xmp (string) Custom XMP RDF data. + * @param string $xmp Custom XMP RDF data. * @since 6.3.0 (2019-09-19) * @public */ @@ -9551,7 +9630,7 @@ class TCPDF { /** * Put XMP data object and return ID. - * @return (int) The object ID. + * @return int The object ID. * @since 5.9.121 (2011-09-28) * @protected */ @@ -9859,8 +9938,8 @@ class TCPDF { } $out .= ' >> >>'; } - $font = $this->getFontBuffer('helvetica'); - $out .= ' /DA (/F'.$font['i'].' 0 Tf 0 g)'; + $font = $this->getFontBuffer((($this->pdfa_mode) ? 'pdfa' : '') .'helvetica'); + $out .= ' /DA ' . $this->_datastring('/F'.$font['i'].' 0 Tf 0 g'); $out .= ' /Q '.(($this->rtl)?'2':'0'); //$out .= ' /XFA '; $out .= ' >>'; @@ -10058,8 +10137,8 @@ class TCPDF { /** * Initialize a new page. - * @param $orientation (string) page orientation. Possible values are (case insensitive):
              • P or PORTRAIT (default)
              • L or LANDSCAPE
              - * @param $format (mixed) The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat(). + * @param string $orientation page orientation. Possible values are (case insensitive):
              • P or PORTRAIT (default)
              • L or LANDSCAPE
              + * @param mixed $format The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat(). * @protected * @see getPageSizeFromFormat(), setPageFormat() */ @@ -10123,13 +10202,13 @@ class TCPDF { /** * Return the starting object string for the selected object ID. - * @param $objid (int) Object ID (leave empty to get a new ID). + * @param int|null $objid Object ID (leave empty to get a new ID). * @return string the starting object string * @protected * @since 5.8.009 (2010-08-20) */ - protected function _getobj($objid='') { - if ($objid === '') { + protected function _getobj($objid=null) { + if (TCPDF_STATIC::empty_string($objid)) { ++$this->n; $objid = $this->n; } @@ -10140,9 +10219,9 @@ class TCPDF { /** * Underline text. - * @param $x (int) X coordinate - * @param $y (int) Y coordinate - * @param $txt (string) text to underline + * @param int $x X coordinate + * @param int $y Y coordinate + * @param string $txt text to underline * @protected */ protected function _dounderline($x, $y, $txt) { @@ -10152,9 +10231,9 @@ class TCPDF { /** * Underline for rectangular text area. - * @param $x (int) X coordinate - * @param $y (int) Y coordinate - * @param $w (int) width to underline + * @param int $x X coordinate + * @param int $y Y coordinate + * @param int $w width to underline * @protected * @since 4.8.008 (2009-09-29) */ @@ -10165,9 +10244,9 @@ class TCPDF { /** * Line through text. - * @param $x (int) X coordinate - * @param $y (int) Y coordinate - * @param $txt (string) text to linethrough + * @param int $x X coordinate + * @param int $y Y coordinate + * @param string $txt text to linethrough * @protected */ protected function _dolinethrough($x, $y, $txt) { @@ -10177,9 +10256,9 @@ class TCPDF { /** * Line through for rectangular text area. - * @param $x (int) X coordinate - * @param $y (int) Y coordinate - * @param $w (int) line length (width) + * @param int $x X coordinate + * @param int $y Y coordinate + * @param int $w line length (width) * @protected * @since 4.9.008 (2009-09-29) */ @@ -10190,9 +10269,9 @@ class TCPDF { /** * Overline text. - * @param $x (int) X coordinate - * @param $y (int) Y coordinate - * @param $txt (string) text to overline + * @param int $x X coordinate + * @param int $y Y coordinate + * @param string $txt text to overline * @protected * @since 4.9.015 (2010-04-19) */ @@ -10203,9 +10282,9 @@ class TCPDF { /** * Overline for rectangular text area. - * @param $x (int) X coordinate - * @param $y (int) Y coordinate - * @param $w (int) width to overline + * @param int $x X coordinate + * @param int $y Y coordinate + * @param int $w width to overline * @protected * @since 4.9.015 (2010-04-19) */ @@ -10217,8 +10296,8 @@ class TCPDF { /** * Format a data string for meta information - * @param $s (string) data string to escape. - * @param $n (int) object ID + * @param string $s data string to escape. + * @param int $n object ID * @return string escaped string. * @protected */ @@ -10232,7 +10311,7 @@ class TCPDF { /** * Set the document creation timestamp - * @param $time (mixed) Document creation timestamp in seconds or date-time string. + * @param mixed $time Document creation timestamp in seconds or date-time string. * @public * @since 5.9.152 (2012-03-23) */ @@ -10245,7 +10324,7 @@ class TCPDF { /** * Set the document modification timestamp - * @param $time (mixed) Document modification timestamp in seconds or date-time string. + * @param mixed $time Document modification timestamp in seconds or date-time string. * @public * @since 5.9.152 (2012-03-23) */ @@ -10258,7 +10337,7 @@ class TCPDF { /** * Returns document creation timestamp in seconds. - * @return (int) Creation timestamp in seconds. + * @return int Creation timestamp in seconds. * @public * @since 5.9.152 (2012-03-23) */ @@ -10268,7 +10347,7 @@ class TCPDF { /** * Returns document modification timestamp in seconds. - * @return (int) Modfication timestamp in seconds. + * @return int Modfication timestamp in seconds. * @public * @since 5.9.152 (2012-03-23) */ @@ -10278,8 +10357,8 @@ class TCPDF { /** * Returns a formatted date for meta information - * @param $n (int) Object ID. - * @param $timestamp (int) Timestamp to convert. + * @param int $n Object ID. + * @param int $timestamp Timestamp to convert. * @return string escaped date string. * @protected * @since 4.6.028 (2009-08-25) @@ -10293,8 +10372,8 @@ class TCPDF { /** * Format a text string for meta information - * @param $s (string) string to escape. - * @param $n (int) object ID + * @param string $s string to escape. + * @param int $n object ID * @return string escaped string. * @protected */ @@ -10308,8 +10387,8 @@ class TCPDF { /** * get raw output stream. - * @param $s (string) string to output. - * @param $n (int) object reference for encryption mode + * @param string $s string to output. + * @param int $n object reference for encryption mode * @protected * @author Nicola Asuni * @since 5.5.000 (2010-06-22) @@ -10324,7 +10403,7 @@ class TCPDF { /** * Output a string to the document. - * @param $s (string) string to output. + * @param string $s string to output. * @protected */ protected function _out($s) { @@ -10352,7 +10431,8 @@ class TCPDF { /** * Set header font. - * @param $font (array) Array describing the basic font parameters: (family, style, size). + * @param array $font Array describing the basic font parameters: (family, style, size). + * @phpstan-param array{0: string, 1: string, 2: float|null} $font * @public * @since 1.1 */ @@ -10362,7 +10442,8 @@ class TCPDF { /** * Get header font. - * @return array() Array describing the basic font parameters: (family, style, size). + * @return array Array describing the basic font parameters: (family, style, size). + * @phpstan-return array{0: string, 1: string, 2: float|null} * @public * @since 4.0.012 (2008-07-24) */ @@ -10372,7 +10453,8 @@ class TCPDF { /** * Set footer font. - * @param $font (array) Array describing the basic font parameters: (family, style, size). + * @param array $font Array describing the basic font parameters: (family, style, size). + * @phpstan-param array{0: string, 1: string, 2: float|null} $font * @public * @since 1.1 */ @@ -10382,7 +10464,8 @@ class TCPDF { /** * Get Footer font. - * @return array() Array describing the basic font parameters: (family, style, size). + * @return array Array describing the basic font parameters: (family, style, size). + * @phpstan-return array{0: string, 1: string, 2: float|null} $font * @public * @since 4.0.012 (2008-07-24) */ @@ -10392,7 +10475,7 @@ class TCPDF { /** * Set language array. - * @param $language (array) + * @param array $language * @public * @since 1.1 */ @@ -10418,17 +10501,17 @@ class TCPDF { /** * Output anchor link. - * @param $url (string) link URL or internal link (i.e.: <a href="#23,4.5">link to page 23 at 4.5 Y position</a>) - * @param $name (string) link name - * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false). - * @param $firstline (boolean) if true prints only the first line and return the remaining string. - * @param $color (array) array of RGB text color - * @param $style (string) font style (U, D, B, I) - * @param $firstblock (boolean) if true the string is the starting of a line. - * @return the number of cells used or the remaining text if $firstline = true; + * @param string $url link URL or internal link (i.e.: <a href="#23,4.5">link to page 23 at 4.5 Y position</a>) + * @param string $name link name + * @param boolean $fill Indicates if the cell background must be painted (true) or transparent (false). + * @param boolean $firstline if true prints only the first line and return the remaining string. + * @param array|null $color array of RGB text color + * @param string $style font style (U, D, B, I) + * @param boolean $firstblock if true the string is the starting of a line. + * @return int the number of cells used or the remaining text if $firstline = true; * @public */ - public function addHtmlLink($url, $name, $fill=false, $firstline=false, $color='', $style=-1, $firstblock=false) { + public function addHtmlLink($url, $name, $fill=false, $firstline=false, $color=null, $style=-1, $firstblock=false) { if (isset($url[1]) AND ($url[0] == '#') AND is_numeric($url[1])) { // convert url to internal link $lnkdata = explode(',', $url); @@ -10440,32 +10523,32 @@ class TCPDF { $lnky = 0; } $url = $this->AddLink(); - $this->SetLink($url, $lnky, $page); + $this->setLink($url, $lnky, $page); } } // store current settings $prevcolor = $this->fgcolor; $prevstyle = $this->FontStyle; if (empty($color)) { - $this->SetTextColorArray($this->htmlLinkColorArray); + $this->setTextColorArray($this->htmlLinkColorArray); } else { - $this->SetTextColorArray($color); + $this->setTextColorArray($color); } if ($style == -1) { - $this->SetFont('', $this->FontStyle.$this->htmlLinkFontStyle); + $this->setFont('', $this->FontStyle.$this->htmlLinkFontStyle); } else { - $this->SetFont('', $this->FontStyle.$style); + $this->setFont('', $this->FontStyle.$style); } $ret = $this->Write($this->lasth, $name, $url, $fill, '', false, 0, $firstline, $firstblock, 0); // restore settings - $this->SetFont('', $prevstyle); - $this->SetTextColorArray($prevcolor); + $this->setFont('', $prevstyle); + $this->setTextColorArray($prevcolor); return $ret; } /** * Converts pixels to User's Units. - * @param $px (int) pixels + * @param int $px pixels * @return float value in user's unit * @public * @see setImageScale(), getImageScale() @@ -10477,7 +10560,7 @@ class TCPDF { /** * Reverse function for htmlentities. * Convert entities in UTF-8. - * @param $text_to_convert (string) Text to convert. + * @param string $text_to_convert Text to convert. * @return string converted text string * @public */ @@ -10490,7 +10573,7 @@ class TCPDF { /** * Compute encryption key depending on object number where the encrypted data is stored. * This is used for all strings and streams without crypt filter specifier. - * @param $n (int) object number + * @param int $n object number * @return int object key * @protected * @author Nicola Asuni @@ -10509,9 +10592,9 @@ class TCPDF { /** * Encrypt the input string. - * @param $n (int) object number - * @param $s (string) data string to encrypt - * @return encrypted string + * @param int $n object number + * @param string $s data string to encrypt + * @return string encrypted string * @protected * @author Nicola Asuni * @since 5.0.005 (2010-05-11) @@ -10754,7 +10837,7 @@ class TCPDF { /** * Convert password for AES-256 encryption mode - * @param $password (string) password + * @param string $password password * @return string password * @protected * @since 5.9.006 (2010-10-19) @@ -10884,16 +10967,16 @@ class TCPDF { * Remark: the protection against modification is for people who have the full Acrobat product. * If you don't set any password, the document will open as usual. If you set a user password, the PDF viewer will ask for it before displaying the document. The master password, if different from the user one, can be used to get full access. * Note: protecting a document requires to encrypt it, which increases the processing time a lot. This can cause a PHP time-out in some cases, especially if the document contains images or fonts. - * @param $permissions (Array) the set of permissions (specify the ones you want to block):
              • print : Print the document;
              • modify : Modify the contents of the document by operations other than those controlled by 'fill-forms', 'extract' and 'assemble';
              • copy : Copy or otherwise extract text and graphics from the document;
              • annot-forms : Add or modify text annotations, fill in interactive form fields, and, if 'modify' is also set, create or modify interactive form fields (including signature fields);
              • fill-forms : Fill in existing interactive form fields (including signature fields), even if 'annot-forms' is not specified;
              • extract : Extract text and graphics (in support of accessibility to users with disabilities or for other purposes);
              • assemble : Assemble the document (insert, rotate, or delete pages and create bookmarks or thumbnail images), even if 'modify' is not set;
              • print-high : Print the document to a representation from which a faithful digital copy of the PDF content could be generated. When this is not set, printing is limited to a low-level representation of the appearance, possibly of degraded quality.
              • owner : (inverted logic - only for public-key) when set permits change of encryption and enables all other permissions.
              - * @param $user_pass (String) user password. Empty by default. - * @param $owner_pass (String) owner password. If not specified, a random value is used. - * @param $mode (int) encryption strength: 0 = RC4 40 bit; 1 = RC4 128 bit; 2 = AES 128 bit; 3 = AES 256 bit. - * @param $pubkeys (String) array of recipients containing public-key certificates ('c') and permissions ('p'). For example: array(array('c' => 'file://../examples/data/cert/tcpdf.crt', 'p' => array('print'))) + * @param array $permissions the set of permissions (specify the ones you want to block):
              • print : Print the document;
              • modify : Modify the contents of the document by operations other than those controlled by 'fill-forms', 'extract' and 'assemble';
              • copy : Copy or otherwise extract text and graphics from the document;
              • annot-forms : Add or modify text annotations, fill in interactive form fields, and, if 'modify' is also set, create or modify interactive form fields (including signature fields);
              • fill-forms : Fill in existing interactive form fields (including signature fields), even if 'annot-forms' is not specified;
              • extract : Extract text and graphics (in support of accessibility to users with disabilities or for other purposes);
              • assemble : Assemble the document (insert, rotate, or delete pages and create bookmarks or thumbnail images), even if 'modify' is not set;
              • print-high : Print the document to a representation from which a faithful digital copy of the PDF content could be generated. When this is not set, printing is limited to a low-level representation of the appearance, possibly of degraded quality.
              • owner : (inverted logic - only for public-key) when set permits change of encryption and enables all other permissions.
              + * @param string $user_pass user password. Empty by default. + * @param string|null $owner_pass owner password. If not specified, a random value is used. + * @param int $mode encryption strength: 0 = RC4 40 bit; 1 = RC4 128 bit; 2 = AES 128 bit; 3 = AES 256 bit. + * @param array|null $pubkeys array of recipients containing public-key certificates ('c') and permissions ('p'). For example: array(array('c' => 'file://../examples/data/cert/tcpdf.crt', 'p' => array('print'))) * @public * @since 2.0.000 (2008-01-02) * @author Nicola Asuni */ - public function SetProtection($permissions=array('print', 'modify', 'copy', 'annot-forms', 'fill-forms', 'extract', 'assemble', 'print-high'), $user_pass='', $owner_pass=null, $mode=0, $pubkeys=null) { + public function setProtection($permissions=array('print', 'modify', 'copy', 'annot-forms', 'fill-forms', 'extract', 'assemble', 'print-high'), $user_pass='', $owner_pass=null, $mode=0, $pubkeys=null) { if ($this->pdfa_mode) { // encryption is not allowed in PDF/A mode return; @@ -10963,7 +11046,7 @@ class TCPDF { $this->encryptdata['V'] = 4; $this->encryptdata['Length'] = 128; $this->encryptdata['CF']['CFM'] = 'AESV2'; - $this->encryptdata['CF']['Length'] = 128; + $this->encryptdata['CF']['Length'] = 16; if ($this->encryptdata['pubkey']) { $this->encryptdata['SubFilter'] = 'adbe.pkcs7.s5'; $this->encryptdata['Recipients'] = array(); @@ -10974,7 +11057,7 @@ class TCPDF { $this->encryptdata['V'] = 5; $this->encryptdata['Length'] = 256; $this->encryptdata['CF']['CFM'] = 'AESV3'; - $this->encryptdata['CF']['Length'] = 256; + $this->encryptdata['CF']['Length'] = 32; if ($this->encryptdata['pubkey']) { $this->encryptdata['SubFilter'] = 'adbe.pkcs7.s5'; $this->encryptdata['Recipients'] = array(); @@ -11040,9 +11123,9 @@ class TCPDF { } /** * Horizontal Scaling. - * @param $s_x (float) scaling factor for width as percent. 0 is not allowed. - * @param $x (int) abscissa of the scaling center. Default is current x position - * @param $y (int) ordinate of the scaling center. Default is current y position + * @param float $s_x scaling factor for width as percent. 0 is not allowed. + * @param int $x abscissa of the scaling center. Default is current x position + * @param int $y ordinate of the scaling center. Default is current y position * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() @@ -11053,9 +11136,9 @@ class TCPDF { /** * Vertical Scaling. - * @param $s_y (float) scaling factor for height as percent. 0 is not allowed. - * @param $x (int) abscissa of the scaling center. Default is current x position - * @param $y (int) ordinate of the scaling center. Default is current y position + * @param float $s_y scaling factor for height as percent. 0 is not allowed. + * @param int $x abscissa of the scaling center. Default is current x position + * @param int $y ordinate of the scaling center. Default is current y position * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() @@ -11066,9 +11149,9 @@ class TCPDF { /** * Vertical and horizontal proportional Scaling. - * @param $s (float) scaling factor for width and height as percent. 0 is not allowed. - * @param $x (int) abscissa of the scaling center. Default is current x position - * @param $y (int) ordinate of the scaling center. Default is current y position + * @param float $s scaling factor for width and height as percent. 0 is not allowed. + * @param int $x abscissa of the scaling center. Default is current x position + * @param int $y ordinate of the scaling center. Default is current y position * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() @@ -11079,19 +11162,19 @@ class TCPDF { /** * Vertical and horizontal non-proportional Scaling. - * @param $s_x (float) scaling factor for width as percent. 0 is not allowed. - * @param $s_y (float) scaling factor for height as percent. 0 is not allowed. - * @param $x (int) abscissa of the scaling center. Default is current x position - * @param $y (int) ordinate of the scaling center. Default is current y position + * @param float $s_x scaling factor for width as percent. 0 is not allowed. + * @param float $s_y scaling factor for height as percent. 0 is not allowed. + * @param float|null $x abscissa of the scaling center. Default is current x position + * @param float|null $y ordinate of the scaling center. Default is current y position * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() */ - public function Scale($s_x, $s_y, $x='', $y='') { - if ($x === '') { + public function Scale($s_x, $s_y, $x=null, $y=null) { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if ($y === '') { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } if (($s_x == 0) OR ($s_y == 0)) { @@ -11115,55 +11198,55 @@ class TCPDF { /** * Horizontal Mirroring. - * @param $x (int) abscissa of the point. Default is current x position + * @param float|null $x abscissa of the point. Default is current x position * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() */ - public function MirrorH($x='') { + public function MirrorH($x=null) { $this->Scale(-100, 100, $x); } /** * Verical Mirroring. - * @param $y (int) ordinate of the point. Default is current y position + * @param float|null $y ordinate of the point. Default is current y position * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() */ - public function MirrorV($y='') { - $this->Scale(100, -100, '', $y); + public function MirrorV($y=null) { + $this->Scale(100, -100, null, $y); } /** * Point reflection mirroring. - * @param $x (int) abscissa of the point. Default is current x position - * @param $y (int) ordinate of the point. Default is current y position + * @param float|null $x abscissa of the point. Default is current x position + * @param float|null $y ordinate of the point. Default is current y position * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() */ - public function MirrorP($x='',$y='') { + public function MirrorP($x=null,$y=null) { $this->Scale(-100, -100, $x, $y); } /** * Reflection against a straight line through point (x, y) with the gradient angle (angle). - * @param $angle (float) gradient angle of the straight line. Default is 0 (horizontal line). - * @param $x (int) abscissa of the point. Default is current x position - * @param $y (int) ordinate of the point. Default is current y position + * @param float $angle gradient angle of the straight line. Default is 0 (horizontal line). + * @param float|null $x abscissa of the point. Default is current x position + * @param float|null $y ordinate of the point. Default is current y position * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() */ - public function MirrorL($angle=0, $x='',$y='') { + public function MirrorL($angle=0, $x=null,$y=null) { $this->Scale(-100, 100, $x, $y); $this->Rotate(-2*($angle-90), $x, $y); } /** * Translate graphic object horizontally. - * @param $t_x (int) movement to the right (or left for RTL) + * @param int $t_x movement to the right (or left for RTL) * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() @@ -11174,7 +11257,7 @@ class TCPDF { /** * Translate graphic object vertically. - * @param $t_y (int) movement to the bottom + * @param int $t_y movement to the bottom * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() @@ -11185,8 +11268,8 @@ class TCPDF { /** * Translate graphic object horizontally and vertically. - * @param $t_x (int) movement to the right - * @param $t_y (int) movement to the bottom + * @param int $t_x movement to the right + * @param int $t_y movement to the bottom * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() @@ -11206,18 +11289,18 @@ class TCPDF { /** * Rotate object. - * @param $angle (float) angle in degrees for counter-clockwise rotation - * @param $x (int) abscissa of the rotation center. Default is current x position - * @param $y (int) ordinate of the rotation center. Default is current y position + * @param float $angle angle in degrees for counter-clockwise rotation + * @param float|null $x abscissa of the rotation center. Default is current x position + * @param float|null $y ordinate of the rotation center. Default is current y position * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() */ - public function Rotate($angle, $x='', $y='') { - if ($x === '') { + public function Rotate($angle, $x=null, $y=null) { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if ($y === '') { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } $y = ($this->h - $y) * $this->k; @@ -11236,45 +11319,45 @@ class TCPDF { /** * Skew horizontally. - * @param $angle_x (float) angle in degrees between -90 (skew to the left) and 90 (skew to the right) - * @param $x (int) abscissa of the skewing center. default is current x position - * @param $y (int) ordinate of the skewing center. default is current y position + * @param float $angle_x angle in degrees between -90 (skew to the left) and 90 (skew to the right) + * @param float|null $x abscissa of the skewing center. default is current x position + * @param float|null $y ordinate of the skewing center. default is current y position * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() */ - public function SkewX($angle_x, $x='', $y='') { + public function SkewX($angle_x, $x=null, $y=null) { $this->Skew($angle_x, 0, $x, $y); } /** * Skew vertically. - * @param $angle_y (float) angle in degrees between -90 (skew to the bottom) and 90 (skew to the top) - * @param $x (int) abscissa of the skewing center. default is current x position - * @param $y (int) ordinate of the skewing center. default is current y position + * @param float $angle_y angle in degrees between -90 (skew to the bottom) and 90 (skew to the top) + * @param float|null $x abscissa of the skewing center. default is current x position + * @param float|null $y ordinate of the skewing center. default is current y position * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() */ - public function SkewY($angle_y, $x='', $y='') { + public function SkewY($angle_y, $x=null, $y=null) { $this->Skew(0, $angle_y, $x, $y); } /** * Skew. - * @param $angle_x (float) angle in degrees between -90 (skew to the left) and 90 (skew to the right) - * @param $angle_y (float) angle in degrees between -90 (skew to the bottom) and 90 (skew to the top) - * @param $x (int) abscissa of the skewing center. default is current x position - * @param $y (int) ordinate of the skewing center. default is current y position + * @param float $angle_x angle in degrees between -90 (skew to the left) and 90 (skew to the right) + * @param float $angle_y angle in degrees between -90 (skew to the bottom) and 90 (skew to the top) + * @param float|null $x abscissa of the skewing center. default is current x position + * @param float|null $y ordinate of the skewing center. default is current y position * @public * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() */ - public function Skew($angle_x, $angle_y, $x='', $y='') { - if ($x === '') { + public function Skew($angle_x, $angle_y, $x=null, $y=null) { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if ($y === '') { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } if (($angle_x <= -90) OR ($angle_x >= 90) OR ($angle_y <= -90) OR ($angle_y >= 90)) { @@ -11296,7 +11379,7 @@ class TCPDF { /** * Apply graphic transformations. - * @param $tm (array) transformation matrix + * @param array $tm transformation matrix * @protected * @since 2.1.000 (2008-01-07) * @see StartTransform(), StopTransform() @@ -11328,12 +11411,12 @@ class TCPDF { /** * Defines the line width. By default, the value equals 0.2 mm. The method can be called before the first page is created and the value is retained from page to page. - * @param $width (float) The width. + * @param float $width The width. * @public * @since 1.0 * @see Line(), Rect(), Cell(), MultiCell() */ - public function SetLineWidth($width) { + public function setLineWidth($width) { //Set line width $this->LineWidth = $width; $this->linestyleWidth = sprintf('%F w', ($width * $this->k)); @@ -11355,7 +11438,7 @@ class TCPDF { /** * Set line style. - * @param $style (array) Line style. Array with keys among the following: + * @param array $style Line style. Array with keys among the following: *
                *
              • width (float): Width of the line in user units.
              • *
              • cap (string): Type of cap to put on the line. Possible values are: @@ -11371,15 +11454,15 @@ class TCPDF { * the point at which the pattern starts.
              • *
              • color (array): Draw color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName).
              • *
              - * @param $ret (boolean) if true do not send the command. + * @param boolean $ret if true do not send the command. * @return string the PDF command * @public * @since 2.1.000 (2008-01-08) */ - public function SetLineStyle($style, $ret=false) { + public function setLineStyle($style, $ret=false) { $s = ''; // string to be returned if (!is_array($style)) { - return; + return $s; } if (isset($style['width'])) { $this->LineWidth = $style['width']; @@ -11423,7 +11506,7 @@ class TCPDF { $s .= $this->linestyleDash.' '; } if (isset($style['color'])) { - $s .= $this->SetDrawColorArray($style['color'], true).' '; + $s .= $this->setDrawColorArray($style['color'], true).' '; } if (!$ret AND ($this->state == 2)) { $this->_out($s); @@ -11433,8 +11516,8 @@ class TCPDF { /** * Begin a new subpath by moving the current point to coordinates (x, y), omitting any connecting line segment. - * @param $x (float) Abscissa of point. - * @param $y (float) Ordinate of point. + * @param float $x Abscissa of point. + * @param float $y Ordinate of point. * @protected * @since 2.1.000 (2008-01-08) */ @@ -11447,8 +11530,8 @@ class TCPDF { /** * Append a straight line segment from the current point to the point (x, y). * The new current point shall be (x, y). - * @param $x (float) Abscissa of end point. - * @param $y (float) Ordinate of end point. + * @param float $x Abscissa of end point. + * @param float $y Ordinate of end point. * @protected * @since 2.1.000 (2008-01-08) */ @@ -11460,11 +11543,11 @@ class TCPDF { /** * Append a rectangle to the current path as a complete subpath, with lower-left corner (x, y) and dimensions widthand height in user space. - * @param $x (float) Abscissa of upper-left corner. - * @param $y (float) Ordinate of upper-left corner. - * @param $w (float) Width. - * @param $h (float) Height. - * @param $op (string) options + * @param float $x Abscissa of upper-left corner. + * @param float $y Ordinate of upper-left corner. + * @param float $w Width. + * @param float $h Height. + * @param string $op options * @protected * @since 2.1.000 (2008-01-08) */ @@ -11477,12 +11560,12 @@ class TCPDF { /** * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x2, y2) as the Bezier control points. * The new current point shall be (x3, y3). - * @param $x1 (float) Abscissa of control point 1. - * @param $y1 (float) Ordinate of control point 1. - * @param $x2 (float) Abscissa of control point 2. - * @param $y2 (float) Ordinate of control point 2. - * @param $x3 (float) Abscissa of end point. - * @param $y3 (float) Ordinate of end point. + * @param float $x1 Abscissa of control point 1. + * @param float $y1 Ordinate of control point 1. + * @param float $x2 Abscissa of control point 2. + * @param float $y2 Ordinate of control point 2. + * @param float $x3 Abscissa of end point. + * @param float $y3 Ordinate of end point. * @protected * @since 2.1.000 (2008-01-08) */ @@ -11495,10 +11578,10 @@ class TCPDF { /** * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using the current point and (x2, y2) as the Bezier control points. * The new current point shall be (x3, y3). - * @param $x2 (float) Abscissa of control point 2. - * @param $y2 (float) Ordinate of control point 2. - * @param $x3 (float) Abscissa of end point. - * @param $y3 (float) Ordinate of end point. + * @param float $x2 Abscissa of control point 2. + * @param float $y2 Ordinate of control point 2. + * @param float $x3 Abscissa of end point. + * @param float $y3 Ordinate of end point. * @protected * @since 4.9.019 (2010-04-26) */ @@ -11511,10 +11594,10 @@ class TCPDF { /** * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x3, y3) as the Bezier control points. * The new current point shall be (x3, y3). - * @param $x1 (float) Abscissa of control point 1. - * @param $y1 (float) Ordinate of control point 1. - * @param $x3 (float) Abscissa of end point. - * @param $y3 (float) Ordinate of end point. + * @param float $x1 Abscissa of control point 1. + * @param float $y1 Ordinate of control point 1. + * @param float $x3 Abscissa of end point. + * @param float $y3 Ordinate of end point. * @protected * @since 2.1.000 (2008-01-08) */ @@ -11526,11 +11609,11 @@ class TCPDF { /** * Draws a line between two points. - * @param $x1 (float) Abscissa of first point. - * @param $y1 (float) Ordinate of first point. - * @param $x2 (float) Abscissa of second point. - * @param $y2 (float) Ordinate of second point. - * @param $style (array) Line style. Array like for SetLineStyle(). Default value: default line style (empty array). + * @param float $x1 Abscissa of first point. + * @param float $y1 Ordinate of first point. + * @param float $x2 Abscissa of second point. + * @param float $y2 Ordinate of second point. + * @param array $style Line style. Array like for SetLineStyle(). Default value: default line style (empty array). * @public * @since 1.0 * @see SetLineWidth(), SetDrawColor(), SetLineStyle() @@ -11540,7 +11623,7 @@ class TCPDF { return; } if (is_array($style)) { - $this->SetLineStyle($style); + $this->setLineStyle($style); } $this->_outPoint($x1, $y1); $this->_outLine($x2, $y2); @@ -11549,18 +11632,18 @@ class TCPDF { /** * Draws a rectangle. - * @param $x (float) Abscissa of upper-left corner. - * @param $y (float) Ordinate of upper-left corner. - * @param $w (float) Width. - * @param $h (float) Height. - * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information. - * @param $border_style (array) Border style of rectangle. Array with keys among the following: + * @param float $x Abscissa of upper-left corner. + * @param float $y Ordinate of upper-left corner. + * @param float $w Width. + * @param float $h Height. + * @param string $style Style of rendering. See the getPathPaintOperator() function for more information. + * @param array $border_style Border style of rectangle. Array with keys among the following: *
                *
              • all: Line style of all borders. Array like for SetLineStyle().
              • *
              • L, T, R, B or combinations: Line style of left, top, right or bottom border. Array like for SetLineStyle().
              • *
              * If a key is not present or is null, the correspondent border is not drawn. Default value: default line style (empty array). - * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). + * @param array $fill_color Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). * @public * @since 1.0 * @see SetLineStyle() @@ -11574,12 +11657,12 @@ class TCPDF { } if (!(strpos($style, 'F') === false) AND !empty($fill_color)) { // set background color - $this->SetFillColorArray($fill_color); + $this->setFillColorArray($fill_color); } if (!empty($border_style)) { if (isset($border_style['all']) AND !empty($border_style['all'])) { //set global style for border - $this->SetLineStyle($border_style['all']); + $this->setLineStyle($border_style['all']); $border_style = array(); } else { // remove stroke operator from style @@ -11621,17 +11704,17 @@ class TCPDF { * Draws a Bezier curve. * The Bezier curve is a tangent to the line between the control points at * either end of the curve. - * @param $x0 (float) Abscissa of start point. - * @param $y0 (float) Ordinate of start point. - * @param $x1 (float) Abscissa of control point 1. - * @param $y1 (float) Ordinate of control point 1. - * @param $x2 (float) Abscissa of control point 2. - * @param $y2 (float) Ordinate of control point 2. - * @param $x3 (float) Abscissa of end point. - * @param $y3 (float) Ordinate of end point. - * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information. - * @param $line_style (array) Line style of curve. Array like for SetLineStyle(). Default value: default line style (empty array). - * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). + * @param float $x0 Abscissa of start point. + * @param float $y0 Ordinate of start point. + * @param float $x1 Abscissa of control point 1. + * @param float $y1 Ordinate of control point 1. + * @param float $x2 Abscissa of control point 2. + * @param float $y2 Ordinate of control point 2. + * @param float $x3 Abscissa of end point. + * @param float $y3 Ordinate of end point. + * @param string $style Style of rendering. See the getPathPaintOperator() function for more information. + * @param array $line_style Line style of curve. Array like for SetLineStyle(). Default value: default line style (empty array). + * @param array $fill_color Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). * @public * @see SetLineStyle() * @since 2.1.000 (2008-01-08) @@ -11640,12 +11723,12 @@ class TCPDF { if ($this->state != 2) { return; } - if (!(false === strpos($style, 'F')) AND isset($fill_color)) { - $this->SetFillColorArray($fill_color); + if (!(false === strpos($style, 'F')) AND is_array($fill_color)) { + $this->setFillColorArray($fill_color); } $op = TCPDF_STATIC::getPathPaintOperator($style); if ($line_style) { - $this->SetLineStyle($line_style); + $this->setLineStyle($line_style); } $this->_outPoint($x0, $y0); $this->_outCurve($x1, $y1, $x2, $y2, $x3, $y3); @@ -11656,12 +11739,12 @@ class TCPDF { * Draws a poly-Bezier curve. * Each Bezier curve segment is a tangent to the line between the control points at * either end of the curve. - * @param $x0 (float) Abscissa of start point. - * @param $y0 (float) Ordinate of start point. - * @param $segments (float) An array of bezier descriptions. Format: array(x1, y1, x2, y2, x3, y3). - * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information. - * @param $line_style (array) Line style of curve. Array like for SetLineStyle(). Default value: default line style (empty array). - * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). + * @param float $x0 Abscissa of start point. + * @param float $y0 Ordinate of start point. + * @param float[] $segments An array of bezier descriptions. Format: array(x1, y1, x2, y2, x3, y3). + * @param string $style Style of rendering. See the getPathPaintOperator() function for more information. + * @param array $line_style Line style of curve. Array like for SetLineStyle(). Default value: default line style (empty array). + * @param array $fill_color Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). * @public * @see SetLineStyle() * @since 3.0008 (2008-05-12) @@ -11670,15 +11753,15 @@ class TCPDF { if ($this->state != 2) { return; } - if (!(false === strpos($style, 'F')) AND isset($fill_color)) { - $this->SetFillColorArray($fill_color); + if (!(false === strpos($style, 'F')) AND is_array($fill_color)) { + $this->setFillColorArray($fill_color); } $op = TCPDF_STATIC::getPathPaintOperator($style); if ($op == 'f') { $line_style = array(); } if ($line_style) { - $this->SetLineStyle($line_style); + $this->setLineStyle($line_style); } $this->_outPoint($x0, $y0); foreach ($segments as $segment) { @@ -11691,37 +11774,37 @@ class TCPDF { /** * Draws an ellipse. * An ellipse is formed from n Bezier curves. - * @param $x0 (float) Abscissa of center point. - * @param $y0 (float) Ordinate of center point. - * @param $rx (float) Horizontal radius. - * @param $ry (float) Vertical radius (if ry = 0 then is a circle, see Circle()). Default value: 0. - * @param $angle: (float) Angle oriented (anti-clockwise). Default value: 0. - * @param $astart: (float) Angle start of draw line. Default value: 0. - * @param $afinish: (float) Angle finish of draw line. Default value: 360. - * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information. - * @param $line_style (array) Line style of ellipse. Array like for SetLineStyle(). Default value: default line style (empty array). - * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). - * @param $nc (integer) Number of curves used to draw a 90 degrees portion of ellipse. + * @param float $x0 Abscissa of center point. + * @param float $y0 Ordinate of center point. + * @param float $rx Horizontal radius. + * @param float $ry Vertical radius (if ry = 0 then is a circle, see Circle()). Default value: 0. + * @param float $angle Angle oriented (anti-clockwise). Default value: 0. + * @param float $astart Angle start of draw line. Default value: 0. + * @param float $afinish Angle finish of draw line. Default value: 360. + * @param string $style Style of rendering. See the getPathPaintOperator() function for more information. + * @param array $line_style Line style of ellipse. Array like for SetLineStyle(). Default value: default line style (empty array). + * @param array $fill_color Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). + * @param integer $nc Number of curves used to draw a 90 degrees portion of ellipse. * @author Nicola Asuni * @public * @since 2.1.000 (2008-01-08) */ - public function Ellipse($x0, $y0, $rx, $ry='', $angle=0, $astart=0, $afinish=360, $style='', $line_style=array(), $fill_color=array(), $nc=2) { + public function Ellipse($x0, $y0, $rx, $ry=0, $angle=0, $astart=0, $afinish=360, $style='', $line_style=array(), $fill_color=array(), $nc=2) { if ($this->state != 2) { return; } if (TCPDF_STATIC::empty_string($ry) OR ($ry == 0)) { $ry = $rx; } - if (!(false === strpos($style, 'F')) AND isset($fill_color)) { - $this->SetFillColorArray($fill_color); + if (!(false === strpos($style, 'F')) AND is_array($fill_color)) { + $this->setFillColorArray($fill_color); } $op = TCPDF_STATIC::getPathPaintOperator($style); if ($op == 'f') { $line_style = array(); } if ($line_style) { - $this->SetLineStyle($line_style); + $this->setLineStyle($line_style); } $this->_outellipticalarc($x0, $y0, $rx, $ry, $angle, $astart, $afinish, false, $nc, true, true, false); $this->_out($op); @@ -11730,18 +11813,18 @@ class TCPDF { /** * Append an elliptical arc to the current path. * An ellipse is formed from n Bezier curves. - * @param $xc (float) Abscissa of center point. - * @param $yc (float) Ordinate of center point. - * @param $rx (float) Horizontal radius. - * @param $ry (float) Vertical radius (if ry = 0 then is a circle, see Circle()). Default value: 0. - * @param $xang: (float) Angle between the X-axis and the major axis of the ellipse. Default value: 0. - * @param $angs: (float) Angle start of draw line. Default value: 0. - * @param $angf: (float) Angle finish of draw line. Default value: 360. - * @param $pie (boolean) if true do not mark the border point (used to draw pie sectors). - * @param $nc (integer) Number of curves used to draw a 90 degrees portion of ellipse. - * @param $startpoint (boolean) if true output a starting point. - * @param $ccw (boolean) if true draws in counter-clockwise. - * @param $svg (boolean) if true the angles are in svg mode (already calculated). + * @param float $xc Abscissa of center point. + * @param float $yc Ordinate of center point. + * @param float $rx Horizontal radius. + * @param float $ry Vertical radius (if ry = 0 then is a circle, see Circle()). Default value: 0. + * @param float $xang Angle between the X-axis and the major axis of the ellipse. Default value: 0. + * @param float $angs Angle start of draw line. Default value: 0. + * @param float $angf Angle finish of draw line. Default value: 360. + * @param boolean $pie if true do not mark the border point (used to draw pie sectors). + * @param integer $nc Number of curves used to draw a 90 degrees portion of ellipse. + * @param boolean $startpoint if true output a starting point. + * @param boolean $ccw if true draws in counter-clockwise. + * @param boolean $svg if true the angles are in svg mode (already calculated). * @return array bounding box coordinates (x min, y min, x max, y max) * @author Nicola Asuni * @protected @@ -11866,15 +11949,15 @@ class TCPDF { /** * Draws a circle. * A circle is formed from n Bezier curves. - * @param $x0 (float) Abscissa of center point. - * @param $y0 (float) Ordinate of center point. - * @param $r (float) Radius. - * @param $angstr: (float) Angle start of draw line. Default value: 0. - * @param $angend: (float) Angle finish of draw line. Default value: 360. - * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information. - * @param $line_style (array) Line style of circle. Array like for SetLineStyle(). Default value: default line style (empty array). - * @param $fill_color (array) Fill color. Format: array(red, green, blue). Default value: default color (empty array). - * @param $nc (integer) Number of curves used to draw a 90 degrees portion of circle. + * @param float $x0 Abscissa of center point. + * @param float $y0 Ordinate of center point. + * @param float $r Radius. + * @param float $angstr Angle start of draw line. Default value: 0. + * @param float $angend Angle finish of draw line. Default value: 360. + * @param string $style Style of rendering. See the getPathPaintOperator() function for more information. + * @param array $line_style Line style of circle. Array like for SetLineStyle(). Default value: default line style (empty array). + * @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array). + * @param integer $nc Number of curves used to draw a 90 degrees portion of circle. * @public * @since 2.1.000 (2008-01-08) */ @@ -11884,15 +11967,15 @@ class TCPDF { /** * Draws a polygonal line - * @param $p (array) Points 0 to ($np - 1). Array with values (x0, y0, x1, y1,..., x(np-1), y(np - 1)) - * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information. - * @param $line_style (array) Line style of polygon. Array with keys among the following: + * @param array $p Points 0 to ($np - 1). Array with values (x0, y0, x1, y1,..., x(np-1), y(np - 1)) + * @param string $style Style of rendering. See the getPathPaintOperator() function for more information. + * @param array $line_style Line style of polygon. Array with keys among the following: *
                *
              • all: Line style of all lines. Array like for SetLineStyle().
              • *
              • 0 to ($np - 1): Line style of each line. Array like for SetLineStyle().
              • *
              * If a key is not present or is null, not draws the line. Default value is default line style (empty array). - * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). + * @param array $fill_color Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). * @since 4.8.003 (2009-09-15) * @public */ @@ -11902,16 +11985,16 @@ class TCPDF { /** * Draws a polygon. - * @param $p (array) Points 0 to ($np - 1). Array with values (x0, y0, x1, y1,..., x(np-1), y(np - 1)) - * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information. - * @param $line_style (array) Line style of polygon. Array with keys among the following: + * @param array $p Points 0 to ($np - 1). Array with values (x0, y0, x1, y1,..., x(np-1), y(np - 1)) + * @param string $style Style of rendering. See the getPathPaintOperator() function for more information. + * @param array $line_style Line style of polygon. Array with keys among the following: *
                *
              • all: Line style of all lines. Array like for SetLineStyle().
              • *
              • 0 to ($np - 1): Line style of each line. Array like for SetLineStyle().
              • *
              * If a key is not present or is null, not draws the line. Default value is default line style (empty array). - * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). - * @param $closed (boolean) if true the polygon is closes, otherwise will remain open + * @param array $fill_color Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). + * @param boolean $closed if true the polygon is closes, otherwise will remain open * @public * @since 2.1.000 (2008-01-08) */ @@ -11932,8 +12015,8 @@ class TCPDF { } $nc += 4; } - if (!(false === strpos($style, 'F')) AND isset($fill_color)) { - $this->SetFillColorArray($fill_color); + if (!(false === strpos($style, 'F')) AND is_array($fill_color)) { + $this->setFillColorArray($fill_color); } $op = TCPDF_STATIC::getPathPaintOperator($style); if ($op == 'f') { @@ -11942,7 +12025,7 @@ class TCPDF { $draw = true; if ($line_style) { if (isset($line_style['all'])) { - $this->SetLineStyle($line_style['all']); + $this->setLineStyle($line_style['all']); } else { $draw = false; if ($op == 'B') { @@ -11962,7 +12045,7 @@ class TCPDF { if ($line_style[$line_num] != 0) { if (is_array($line_style[$line_num])) { $this->_out('S'); - $this->SetLineStyle($line_style[$line_num]); + $this->setLineStyle($line_style[$line_num]); $this->_outPoint($p[$i - 2], $p[$i - 1]); $this->_outLine($p[$i], $p[$i + 1]); $this->_out('S'); @@ -11989,21 +12072,21 @@ class TCPDF { /** * Draws a regular polygon. - * @param $x0 (float) Abscissa of center point. - * @param $y0 (float) Ordinate of center point. - * @param $r: (float) Radius of inscribed circle. - * @param $ns (integer) Number of sides. - * @param $angle (float) Angle oriented (anti-clockwise). Default value: 0. - * @param $draw_circle (boolean) Draw inscribed circle or not. Default value: false. - * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information. - * @param $line_style (array) Line style of polygon sides. Array with keys among the following: + * @param float $x0 Abscissa of center point. + * @param float $y0 Ordinate of center point. + * @param float $r Radius of inscribed circle. + * @param integer $ns Number of sides. + * @param float $angle Angle oriented (anti-clockwise). Default value: 0. + * @param boolean $draw_circle Draw inscribed circle or not. Default value: false. + * @param string $style Style of rendering. See the getPathPaintOperator() function for more information. + * @param array $line_style Line style of polygon sides. Array with keys among the following: *
                *
              • all: Line style of all sides. Array like for SetLineStyle().
              • *
              • 0 to ($ns - 1): Line style of each side. Array like for SetLineStyle().
              • *
              * If a key is not present or is null, not draws the side. Default value is default line style (empty array). - * @param $fill_color (array) Fill color. Format: array(red, green, blue). Default value: default color (empty array). - * @param $circle_style (string) Style of rendering of inscribed circle (if draws). Possible values are: + * @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array). + * @param string $circle_style Style of rendering of inscribed circle (if draws). Possible values are: *
                *
              • D or empty string: Draw (default).
              • *
              • F: Fill.
              • @@ -12011,8 +12094,8 @@ class TCPDF { *
              • CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).
              • *
              • CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).
              • *
              - * @param $circle_outLine_style (array) Line style of inscribed circle (if draws). Array like for SetLineStyle(). Default value: default line style (empty array). - * @param $circle_fill_color (array) Fill color of inscribed circle (if draws). Format: array(red, green, blue). Default value: default color (empty array). + * @param array $circle_outLine_style Line style of inscribed circle (if draws). Array like for SetLineStyle(). Default value: default line style (empty array). + * @param array $circle_fill_color Fill color of inscribed circle (if draws). Format: array(red, green, blue). Default value: default color (empty array). * @public * @since 2.1.000 (2008-01-08) */ @@ -12035,23 +12118,23 @@ class TCPDF { /** * Draws a star polygon - * @param $x0 (float) Abscissa of center point. - * @param $y0 (float) Ordinate of center point. - * @param $r (float) Radius of inscribed circle. - * @param $nv (integer) Number of vertices. - * @param $ng (integer) Number of gap (if ($ng % $nv = 1) then is a regular polygon). - * @param $angle: (float) Angle oriented (anti-clockwise). Default value: 0. - * @param $draw_circle: (boolean) Draw inscribed circle or not. Default value is false. - * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information. - * @param $line_style (array) Line style of polygon sides. Array with keys among the following: + * @param float $x0 Abscissa of center point. + * @param float $y0 Ordinate of center point. + * @param float $r Radius of inscribed circle. + * @param integer $nv Number of vertices. + * @param integer $ng Number of gap (if ($ng % $nv = 1) then is a regular polygon). + * @param float $angle Angle oriented (anti-clockwise). Default value: 0. + * @param boolean $draw_circle Draw inscribed circle or not. Default value is false. + * @param string $style Style of rendering. See the getPathPaintOperator() function for more information. + * @param array $line_style Line style of polygon sides. Array with keys among the following: *
                *
              • all: Line style of all sides. Array like for * SetLineStyle().
              • *
              • 0 to (n - 1): Line style of each side. Array like for SetLineStyle().
              • *
              * If a key is not present or is null, not draws the side. Default value is default line style (empty array). - * @param $fill_color (array) Fill color. Format: array(red, green, blue). Default value: default color (empty array). - * @param $circle_style (string) Style of rendering of inscribed circle (if draws). Possible values are: + * @param array $fill_color Fill color. Format: array(red, green, blue). Default value: default color (empty array). + * @param string $circle_style Style of rendering of inscribed circle (if draws). Possible values are: *
                *
              • D or empty string: Draw (default).
              • *
              • F: Fill.
              • @@ -12059,8 +12142,8 @@ class TCPDF { *
              • CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).
              • *
              • CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).
              • *
              - * @param $circle_outLine_style (array) Line style of inscribed circle (if draws). Array like for SetLineStyle(). Default value: default line style (empty array). - * @param $circle_fill_color (array) Fill color of inscribed circle (if draws). Format: array(red, green, blue). Default value: default color (empty array). + * @param array $circle_outLine_style Line style of inscribed circle (if draws). Array like for SetLineStyle(). Default value: default line style (empty array). + * @param array $circle_fill_color Fill color of inscribed circle (if draws). Format: array(red, green, blue). Default value: default color (empty array). * @public * @since 2.1.000 (2008-01-08) */ @@ -12094,15 +12177,15 @@ class TCPDF { /** * Draws a rounded rectangle. - * @param $x (float) Abscissa of upper-left corner. - * @param $y (float) Ordinate of upper-left corner. - * @param $w (float) Width. - * @param $h (float) Height. - * @param $r (float) the radius of the circle used to round off the corners of the rectangle. - * @param $round_corner (string) Draws rounded corner or not. String with a 0 (not rounded i-corner) or 1 (rounded i-corner) in i-position. Positions are, in order and begin to 0: top right, bottom right, bottom left and top left. Default value: all rounded corner ("1111"). - * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information. - * @param $border_style (array) Border style of rectangle. Array like for SetLineStyle(). Default value: default line style (empty array). - * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). + * @param float $x Abscissa of upper-left corner. + * @param float $y Ordinate of upper-left corner. + * @param float $w Width. + * @param float $h Height. + * @param float $r the radius of the circle used to round off the corners of the rectangle. + * @param string $round_corner Draws rounded corner or not. String with a 0 (not rounded i-corner) or 1 (rounded i-corner) in i-position. Positions are, in order and begin to 0: top right, bottom right, bottom left and top left. Default value: all rounded corner ("1111"). + * @param string $style Style of rendering. See the getPathPaintOperator() function for more information. + * @param array $border_style Border style of rectangle. Array like for SetLineStyle(). Default value: default line style (empty array). + * @param array $fill_color Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). * @public * @since 2.1.000 (2008-01-08) */ @@ -12112,16 +12195,16 @@ class TCPDF { /** * Draws a rounded rectangle. - * @param $x (float) Abscissa of upper-left corner. - * @param $y (float) Ordinate of upper-left corner. - * @param $w (float) Width. - * @param $h (float) Height. - * @param $rx (float) the x-axis radius of the ellipse used to round off the corners of the rectangle. - * @param $ry (float) the y-axis radius of the ellipse used to round off the corners of the rectangle. - * @param $round_corner (string) Draws rounded corner or not. String with a 0 (not rounded i-corner) or 1 (rounded i-corner) in i-position. Positions are, in order and begin to 0: top right, bottom right, bottom left and top left. Default value: all rounded corner ("1111"). - * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information. - * @param $border_style (array) Border style of rectangle. Array like for SetLineStyle(). Default value: default line style (empty array). - * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). + * @param float $x Abscissa of upper-left corner. + * @param float $y Ordinate of upper-left corner. + * @param float $w Width. + * @param float $h Height. + * @param float $rx the x-axis radius of the ellipse used to round off the corners of the rectangle. + * @param float $ry the y-axis radius of the ellipse used to round off the corners of the rectangle. + * @param string $round_corner Draws rounded corner or not. String with a 0 (not rounded i-corner) or 1 (rounded i-corner) in i-position. Positions are, in order and begin to 0: top right, bottom right, bottom left and top left. Default value: all rounded corner ("1111"). + * @param string $style Style of rendering. See the getPathPaintOperator() function for more information. + * @param array $border_style Border style of rectangle. Array like for SetLineStyle(). Default value: default line style (empty array). + * @param array $fill_color Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array). * @public * @since 4.9.019 (2010-04-22) */ @@ -12135,15 +12218,15 @@ class TCPDF { return; } // Rounded - if (!(false === strpos($style, 'F')) AND isset($fill_color)) { - $this->SetFillColorArray($fill_color); + if (!(false === strpos($style, 'F')) AND is_array($fill_color)) { + $this->setFillColorArray($fill_color); } $op = TCPDF_STATIC::getPathPaintOperator($style); if ($op == 'f') { $border_style = array(); } if ($border_style) { - $this->SetLineStyle($border_style); + $this->setLineStyle($border_style); } $MyArc = 4 / 3 * (sqrt(2) - 1); $this->_outPoint($x + $rx, $y); @@ -12185,13 +12268,13 @@ class TCPDF { /** * Draws a grahic arrow. - * @param $x0 (float) Abscissa of first point. - * @param $y0 (float) Ordinate of first point. - * @param $x1 (float) Abscissa of second point. - * @param $y1 (float) Ordinate of second point. - * @param $head_style (int) (0 = draw only arrowhead arms, 1 = draw closed arrowhead, but no fill, 2 = closed and filled arrowhead, 3 = filled arrowhead) - * @param $arm_size (float) length of arrowhead arms - * @param $arm_angle (int) angle between an arm and the shaft + * @param float $x0 Abscissa of first point. + * @param float $y0 Ordinate of first point. + * @param float $x1 Abscissa of second point. + * @param float $y1 Ordinate of second point. + * @param int $head_style (0 = draw only arrowhead arms, 1 = draw closed arrowhead, but no fill, 2 = closed and filled arrowhead, 3 = filled arrowhead) + * @param float $arm_size length of arrowhead arms + * @param int $arm_angle angle between an arm and the shaft * @author Piotr Galecki, Nicola Asuni, Andy Meier * @since 4.6.018 (2009-07-10) */ @@ -12251,11 +12334,11 @@ class TCPDF { /** * Add a Named Destination. * NOTE: destination names are unique, so only last entry will be saved. - * @param $name (string) Destination name. - * @param $y (float) Y position in user units of the destiantion on the selected page (default = -1 = current position; 0 = page start;). - * @param $page (int|string) Target page number (leave empty for current page). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages. - * @param $x (float) X position in user units of the destiantion on the selected page (default = -1 = current position;). - * @return (string) Stripped named destination identifier or false in case of error. + * @param string $name Destination name. + * @param float $y Y position in user units of the destiantion on the selected page (default = -1 = current position; 0 = page start;). + * @param int|string $page Target page number (leave empty for current page). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages. + * @param float $x X position in user units of the destiantion on the selected page (default = -1 = current position;). + * @return string|false Stripped named destination identifier or false in case of error. * @public * @author Christian Deligant, Nicola Asuni * @since 5.9.097 (2011-06-23) @@ -12298,7 +12381,7 @@ class TCPDF { /** * Return the Named Destination array. - * @return (array) Named Destination array. + * @return array Named Destination array. * @public * @author Nicola Asuni * @since 5.9.097 (2011-06-23) @@ -12329,14 +12412,14 @@ class TCPDF { /** * Adds a bookmark - alias for Bookmark(). - * @param $txt (string) Bookmark description. - * @param $level (int) Bookmark level (minimum value is 0). - * @param $y (float) Y position in user units of the bookmark on the selected page (default = -1 = current position; 0 = page start;). - * @param $page (int|string) Target page number (leave empty for current page). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages. - * @param $style (string) Font style: B = Bold, I = Italic, BI = Bold + Italic. - * @param $color (array) RGB color array (values from 0 to 255). - * @param $x (float) X position in user units of the bookmark on the selected page (default = -1 = current position;). - * @param $link (mixed) URL, or numerical link ID, or named destination (# character followed by the destination name), or embedded file (* character followed by the file name). + * @param string $txt Bookmark description. + * @param int $level Bookmark level (minimum value is 0). + * @param float $y Y position in user units of the bookmark on the selected page (default = -1 = current position; 0 = page start;). + * @param int|string $page Target page number (leave empty for current page). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages. + * @param string $style Font style: B = Bold, I = Italic, BI = Bold + Italic. + * @param array $color RGB color array (values from 0 to 255). + * @param float $x X position in user units of the bookmark on the selected page (default = -1 = current position;). + * @param mixed $link URL, or numerical link ID, or named destination (# character followed by the destination name), or embedded file (* character followed by the file name). * @public */ public function setBookmark($txt, $level=0, $y=-1, $page='', $style='', $color=array(0,0,0), $x=-1, $link='') { @@ -12345,14 +12428,14 @@ class TCPDF { /** * Adds a bookmark. - * @param $txt (string) Bookmark description. - * @param $level (int) Bookmark level (minimum value is 0). - * @param $y (float) Y position in user units of the bookmark on the selected page (default = -1 = current position; 0 = page start;). - * @param $page (int|string) Target page number (leave empty for current page). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages. - * @param $style (string) Font style: B = Bold, I = Italic, BI = Bold + Italic. - * @param $color (array) RGB color array (values from 0 to 255). - * @param $x (float) X position in user units of the bookmark on the selected page (default = -1 = current position;). - * @param $link (mixed) URL, or numerical link ID, or named destination (# character followed by the destination name), or embedded file (* character followed by the file name). + * @param string $txt Bookmark description. + * @param int $level Bookmark level (minimum value is 0). + * @param float $y Y position in user units of the bookmark on the selected page (default = -1 = current position; 0 = page start;). + * @param int|string $page Target page number (leave empty for current page). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages. + * @param string $style Font style: B = Bold, I = Italic, BI = Bold + Italic. + * @param array $color RGB color array (values from 0 to 255). + * @param float $x X position in user units of the bookmark on the selected page (default = -1 = current position;). + * @param mixed $link URL, or numerical link ID, or named destination (# character followed by the destination name), or embedded file (* character followed by the file name). * @public * @since 2.1.002 (2008-02-12) */ @@ -12543,7 +12626,7 @@ class TCPDF { /** * Adds a javascript - * @param $script (string) Javascript code + * @param string $script Javascript code * @public * @author Johannes G\FCntert, Nicola Asuni * @since 2.1.002 (2008-02-12) @@ -12554,8 +12637,8 @@ class TCPDF { /** * Adds a javascript object and return object ID - * @param $script (string) Javascript code - * @param $onload (boolean) if true executes this object when opening the document + * @param string $script Javascript code + * @param boolean $onload if true executes this object when opening the document * @return int internal object ID * @public * @author Nicola Asuni @@ -12624,13 +12707,13 @@ class TCPDF { /** * Adds a javascript form field. - * @param $type (string) field type - * @param $name (string) field name - * @param $x (int) horizontal position - * @param $y (int) vertical position - * @param $w (int) width - * @param $h (int) height - * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference. + * @param string $type field type + * @param string $name field name + * @param int $x horizontal position + * @param int $y vertical position + * @param int $w width + * @param int $h height + * @param array $prop javascript field properties. Possible values are described on official Javascript for Acrobat API reference. * @protected * @author Denis Van Nuffelen, Nicola Asuni * @since 2.1.002 (2008-02-12) @@ -12666,7 +12749,7 @@ class TCPDF { /** * Set default properties for form fields. - * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference. + * @param array $prop javascript field properties. Possible values are described on official Javascript for Acrobat API reference. * @public * @author Nicola Asuni * @since 4.8.000 (2009-09-06) @@ -12688,23 +12771,23 @@ class TCPDF { /** * Creates a text field - * @param $name (string) field name - * @param $w (float) Width of the rectangle - * @param $h (float) Height of the rectangle - * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference. - * @param $opt (array) annotation parameters. Possible values are described on official PDF32000_2008 reference. - * @param $x (float) Abscissa of the upper-left corner of the rectangle - * @param $y (float) Ordinate of the upper-left corner of the rectangle - * @param $js (boolean) if true put the field using JavaScript (requires Acrobat Writer to be rendered). + * @param string $name field name + * @param float $w Width of the rectangle + * @param float $h Height of the rectangle + * @param array $prop javascript field properties. Possible values are described on official Javascript for Acrobat API reference. + * @param array $opt annotation parameters. Possible values are described on official PDF32000_2008 reference. + * @param float|null $x Abscissa of the upper-left corner of the rectangle + * @param float|null $y Ordinate of the upper-left corner of the rectangle + * @param boolean $js if true put the field using JavaScript (requires Acrobat Writer to be rendered). * @public * @author Nicola Asuni * @since 4.8.000 (2009-09-07) */ - public function TextField($name, $w, $h, $prop=array(), $opt=array(), $x='', $y='', $js=false) { - if ($x === '') { + public function TextField($name, $w, $h, $prop=array(), $opt=array(), $x=null, $y=null, $js=false) { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if ($y === '') { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } // check page for no-write regions and adapt page margins if necessary @@ -12808,24 +12891,24 @@ class TCPDF { /** * Creates a RadioButton field. - * @param $name (string) Field name. - * @param $w (int) Width of the radio button. - * @param $prop (array) Javascript field properties. Possible values are described on official Javascript for Acrobat API reference. - * @param $opt (array) Annotation parameters. Possible values are described on official PDF32000_2008 reference. - * @param $onvalue (string) Value to be returned if selected. - * @param $checked (boolean) Define the initial state. - * @param $x (float) Abscissa of the upper-left corner of the rectangle - * @param $y (float) Ordinate of the upper-left corner of the rectangle - * @param $js (boolean) If true put the field using JavaScript (requires Acrobat Writer to be rendered). + * @param string $name Field name. + * @param int $w Width of the radio button. + * @param array $prop Javascript field properties. Possible values are described on official Javascript for Acrobat API reference. + * @param array $opt Annotation parameters. Possible values are described on official PDF32000_2008 reference. + * @param string $onvalue Value to be returned if selected. + * @param boolean $checked Define the initial state. + * @param float|null $x Abscissa of the upper-left corner of the rectangle + * @param float|null $y Ordinate of the upper-left corner of the rectangle + * @param boolean $js If true put the field using JavaScript (requires Acrobat Writer to be rendered). * @public * @author Nicola Asuni * @since 4.8.000 (2009-09-07) */ - public function RadioButton($name, $w, $prop=array(), $opt=array(), $onvalue='On', $checked=false, $x='', $y='', $js=false) { - if ($x === '') { + public function RadioButton($name, $w, $prop=array(), $opt=array(), $onvalue='On', $checked=false, $x=null, $y=null, $js=false) { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if ($y === '') { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } // check page for no-write regions and adapt page margins if necessary @@ -12911,24 +12994,24 @@ class TCPDF { /** * Creates a List-box field - * @param $name (string) field name - * @param $w (int) width - * @param $h (int) height - * @param $values (array) array containing the list of values. - * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference. - * @param $opt (array) annotation parameters. Possible values are described on official PDF32000_2008 reference. - * @param $x (float) Abscissa of the upper-left corner of the rectangle - * @param $y (float) Ordinate of the upper-left corner of the rectangle - * @param $js (boolean) if true put the field using JavaScript (requires Acrobat Writer to be rendered). + * @param string $name field name + * @param int $w width + * @param int $h height + * @param array $values array containing the list of values. + * @param array $prop javascript field properties. Possible values are described on official Javascript for Acrobat API reference. + * @param array $opt annotation parameters. Possible values are described on official PDF32000_2008 reference. + * @param float|null $x Abscissa of the upper-left corner of the rectangle + * @param float|null $y Ordinate of the upper-left corner of the rectangle + * @param boolean $js if true put the field using JavaScript (requires Acrobat Writer to be rendered). * @public * @author Nicola Asuni * @since 4.8.000 (2009-09-07) */ - public function ListBox($name, $w, $h, $values, $prop=array(), $opt=array(), $x='', $y='', $js=false) { - if ($x === '') { + public function ListBox($name, $w, $h, $values, $prop=array(), $opt=array(), $x=null, $y=null, $js=false) { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if ($y === '') { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } // check page for no-write regions and adapt page margins if necessary @@ -12997,24 +13080,24 @@ class TCPDF { /** * Creates a Combo-box field - * @param $name (string) field name - * @param $w (int) width - * @param $h (int) height - * @param $values (array) array containing the list of values. - * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference. - * @param $opt (array) annotation parameters. Possible values are described on official PDF32000_2008 reference. - * @param $x (float) Abscissa of the upper-left corner of the rectangle - * @param $y (float) Ordinate of the upper-left corner of the rectangle - * @param $js (boolean) if true put the field using JavaScript (requires Acrobat Writer to be rendered). + * @param string $name field name + * @param int $w width + * @param int $h height + * @param array $values array containing the list of values. + * @param array $prop javascript field properties. Possible values are described on official Javascript for Acrobat API reference. + * @param array $opt annotation parameters. Possible values are described on official PDF32000_2008 reference. + * @param float|null $x Abscissa of the upper-left corner of the rectangle + * @param float|null $y Ordinate of the upper-left corner of the rectangle + * @param boolean $js if true put the field using JavaScript (requires Acrobat Writer to be rendered). * @public * @author Nicola Asuni * @since 4.8.000 (2009-09-07) */ - public function ComboBox($name, $w, $h, $values, $prop=array(), $opt=array(), $x='', $y='', $js=false) { - if ($x === '') { + public function ComboBox($name, $w, $h, $values, $prop=array(), $opt=array(), $x=null, $y=null, $js=false) { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if ($y === '') { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } // check page for no-write regions and adapt page margins if necessary @@ -13084,24 +13167,24 @@ class TCPDF { /** * Creates a CheckBox field - * @param $name (string) field name - * @param $w (int) width - * @param $checked (boolean) define the initial state. - * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference. - * @param $opt (array) annotation parameters. Possible values are described on official PDF32000_2008 reference. - * @param $onvalue (string) value to be returned if selected. - * @param $x (float) Abscissa of the upper-left corner of the rectangle - * @param $y (float) Ordinate of the upper-left corner of the rectangle - * @param $js (boolean) if true put the field using JavaScript (requires Acrobat Writer to be rendered). + * @param string $name field name + * @param int $w width + * @param boolean $checked define the initial state. + * @param array $prop javascript field properties. Possible values are described on official Javascript for Acrobat API reference. + * @param array $opt annotation parameters. Possible values are described on official PDF32000_2008 reference. + * @param string $onvalue value to be returned if selected. + * @param float|null $x Abscissa of the upper-left corner of the rectangle + * @param float|null $y Ordinate of the upper-left corner of the rectangle + * @param boolean $js if true put the field using JavaScript (requires Acrobat Writer to be rendered). * @public * @author Nicola Asuni * @since 4.8.000 (2009-09-07) */ - public function CheckBox($name, $w, $checked=false, $prop=array(), $opt=array(), $onvalue='Yes', $x='', $y='', $js=false) { - if ($x === '') { + public function CheckBox($name, $w, $checked=false, $prop=array(), $opt=array(), $onvalue='Yes', $x=null, $y=null, $js=false) { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if ($y === '') { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } // check page for no-write regions and adapt page margins if necessary @@ -13163,25 +13246,25 @@ class TCPDF { /** * Creates a button field - * @param $name (string) field name - * @param $w (int) width - * @param $h (int) height - * @param $caption (string) caption. - * @param $action (mixed) action triggered by pressing the button. Use a string to specify a javascript action. Use an array to specify a form action options as on section 12.7.5 of PDF32000_2008. - * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference. - * @param $opt (array) annotation parameters. Possible values are described on official PDF32000_2008 reference. - * @param $x (float) Abscissa of the upper-left corner of the rectangle - * @param $y (float) Ordinate of the upper-left corner of the rectangle - * @param $js (boolean) if true put the field using JavaScript (requires Acrobat Writer to be rendered). + * @param string $name field name + * @param int $w width + * @param int $h height + * @param string $caption caption. + * @param mixed $action action triggered by pressing the button. Use a string to specify a javascript action. Use an array to specify a form action options as on section 12.7.5 of PDF32000_2008. + * @param array $prop javascript field properties. Possible values are described on official Javascript for Acrobat API reference. + * @param array $opt annotation parameters. Possible values are described on official PDF32000_2008 reference. + * @param float|null $x Abscissa of the upper-left corner of the rectangle + * @param float|null $y Ordinate of the upper-left corner of the rectangle + * @param boolean $js if true put the field using JavaScript (requires Acrobat Writer to be rendered). * @public * @author Nicola Asuni * @since 4.8.000 (2009-09-07) */ - public function Button($name, $w, $h, $caption, $action, $prop=array(), $opt=array(), $x='', $y='', $js=false) { - if ($x === '') { + public function Button($name, $w, $h, $caption, $action, $prop=array(), $opt=array(), $x=null, $y=null, $js=false) { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if ($y === '') { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } // check page for no-write regions and adapt page margins if necessary @@ -13214,7 +13297,7 @@ class TCPDF { 'R' => array('width' => $bw, 'cap' => 'square', 'join' => 'miter', 'dash' => 0, 'color' => array(51)), 'T' => array('width' => $bw, 'cap' => 'square', 'join' => 'miter', 'dash' => 0, 'color' => array(231)), 'B' => array('width' => $bw, 'cap' => 'square', 'join' => 'miter', 'dash' => 0, 'color' => array(51))); - $this->SetFillColor(204); + $this->setFillColor(204); $this->Cell($w, $h, $caption, $border, 0, 'C', true, '', 1, false, 'T', 'M'); $this->endTemplate(); --$this->n; @@ -13420,14 +13503,14 @@ class TCPDF { * WARNING: This is experimental and currently do not work. * Check the PDF Reference 8.7.1 Transform Methods, * Table 8.105 Entries in the UR transform parameters dictionary - * @param $enable (boolean) if true enable user's rights on PDF reader - * @param $document (string) Names specifying additional document-wide usage rights for the document. The only defined value is "/FullSave", which permits a user to save the document along with modified form and/or annotation data. - * @param $annots (string) Names specifying additional annotation-related usage rights for the document. Valid names in PDF 1.5 and later are /Create/Delete/Modify/Copy/Import/Export, which permit the user to perform the named operation on annotations. - * @param $form (string) Names specifying additional form-field-related usage rights for the document. Valid names are: /Add/Delete/FillIn/Import/Export/SubmitStandalone/SpawnTemplate - * @param $signature (string) Names specifying additional signature-related usage rights for the document. The only defined value is /Modify, which permits a user to apply a digital signature to an existing signature form field or clear a signed signature form field. - * @param $ef (string) Names specifying additional usage rights for named embedded files in the document. Valid names are /Create/Delete/Modify/Import, which permit the user to perform the named operation on named embedded files + * @param boolean $enable if true enable user's rights on PDF reader + * @param string $document Names specifying additional document-wide usage rights for the document. The only defined value is "/FullSave", which permits a user to save the document along with modified form and/or annotation data. + * @param string $annots Names specifying additional annotation-related usage rights for the document. Valid names in PDF 1.5 and later are /Create/Delete/Modify/Copy/Import/Export, which permit the user to perform the named operation on annotations. + * @param string $form Names specifying additional form-field-related usage rights for the document. Valid names are: /Add/Delete/FillIn/Import/Export/SubmitStandalone/SpawnTemplate + * @param string $signature Names specifying additional signature-related usage rights for the document. The only defined value is /Modify, which permits a user to apply a digital signature to an existing signature form field or clear a signed signature form field. + * @param string $ef Names specifying additional usage rights for named embedded files in the document. Valid names are /Create/Delete/Modify/Import, which permit the user to perform the named operation on named embedded files Names specifying additional embedded-files-related usage rights for the document. - * @param $formex (string) Names specifying additional form-field-related usage rights. The only valid name is BarcodePlaintext, which permits text form field data to be encoded as a plaintext two-dimensional barcode. + * @param string $formex Names specifying additional form-field-related usage rights. The only valid name is BarcodePlaintext, which permits text form field data to be encoded as a plaintext two-dimensional barcode. * @public * @author Nicola Asuni * @since 2.9.000 (2008-03-26) @@ -13458,13 +13541,13 @@ class TCPDF { * To create self-signed signature: openssl req -x509 -nodes -days 365000 -newkey rsa:1024 -keyout tcpdf.crt -out tcpdf.crt * To export crt to p12: openssl pkcs12 -export -in tcpdf.crt -out tcpdf.p12 * To convert pfx certificate to pem: openssl pkcs12 -in tcpdf.pfx -out tcpdf.crt -nodes - * @param $signing_cert (mixed) signing certificate (string or filename prefixed with 'file://') - * @param $private_key (mixed) private key (string or filename prefixed with 'file://') - * @param $private_key_password (string) password - * @param $extracerts (string) specifies the name of a file containing a bunch of extra certificates to include in the signature which can for example be used to help the recipient to verify the certificate that you used. - * @param $cert_type (int) The access permissions granted for this document. Valid values shall be: 1 = No changes to the document shall be permitted; any change to the document shall invalidate the signature; 2 = Permitted changes shall be filling in forms, instantiating page templates, and signing; other changes shall invalidate the signature; 3 = Permitted changes shall be the same as for 2, as well as annotation creation, deletion, and modification; other changes shall invalidate the signature. - * @param $info (array) array of option information: Name, Location, Reason, ContactInfo. - * @param $approval (string) Enable approval signature eg. for PDF incremental update + * @param mixed $signing_cert signing certificate (string or filename prefixed with 'file://') + * @param mixed $private_key private key (string or filename prefixed with 'file://') + * @param string $private_key_password password + * @param string $extracerts specifies the name of a file containing a bunch of extra certificates to include in the signature which can for example be used to help the recipient to verify the certificate that you used. + * @param int $cert_type The access permissions granted for this document. Valid values shall be: 1 = No changes to the document shall be permitted; any change to the document shall invalidate the signature; 2 = Permitted changes shall be filling in forms, instantiating page templates, and signing; other changes shall invalidate the signature; 3 = Permitted changes shall be the same as for 2, as well as annotation creation, deletion, and modification; other changes shall invalidate the signature. + * @param array $info array of option information: Name, Location, Reason, ContactInfo. + * @param string $approval Enable approval signature eg. for PDF incremental update * @public * @author Nicola Asuni * @since 4.6.005 (2009-04-24) @@ -13496,12 +13579,12 @@ class TCPDF { /** * Set the digital signature appearance (a cliccable rectangle area to get signature properties) - * @param $x (float) Abscissa of the upper-left corner. - * @param $y (float) Ordinate of the upper-left corner. - * @param $w (float) Width of the signature area. - * @param $h (float) Height of the signature area. - * @param $page (int) option page number (if < 0 the current page is used). - * @param $name (string) Name of the signature. + * @param float $x Abscissa of the upper-left corner. + * @param float $y Ordinate of the upper-left corner. + * @param float $w Width of the signature area. + * @param float $h Height of the signature area. + * @param int $page option page number (if < 0 the current page is used). + * @param string $name Name of the signature. * @public * @author Nicola Asuni * @since 5.3.011 (2010-06-17) @@ -13512,12 +13595,12 @@ class TCPDF { /** * Add an empty digital signature appearance (a cliccable rectangle area to get signature properties) - * @param $x (float) Abscissa of the upper-left corner. - * @param $y (float) Ordinate of the upper-left corner. - * @param $w (float) Width of the signature area. - * @param $h (float) Height of the signature area. - * @param $page (int) option page number (if < 0 the current page is used). - * @param $name (string) Name of the signature. + * @param float $x Abscissa of the upper-left corner. + * @param float $y Ordinate of the upper-left corner. + * @param float $w Width of the signature area. + * @param float $h Height of the signature area. + * @param int $page option page number (if < 0 the current page is used). + * @param string $name Name of the signature. * @public * @author Nicola Asuni * @since 5.9.101 (2011-07-06) @@ -13529,13 +13612,13 @@ class TCPDF { /** * Get the array that defines the signature appearance (page and rectangle coordinates). - * @param $x (float) Abscissa of the upper-left corner. - * @param $y (float) Ordinate of the upper-left corner. - * @param $w (float) Width of the signature area. - * @param $h (float) Height of the signature area. - * @param $page (int) option page number (if < 0 the current page is used). - * @param $name (string) Name of the signature. - * @return (array) Array defining page and rectangle coordinates of signature appearance. + * @param float $x Abscissa of the upper-left corner. + * @param float $y Ordinate of the upper-left corner. + * @param float $w Width of the signature area. + * @param float $h Height of the signature area. + * @param int $page option page number (if < 0 the current page is used). + * @param string $name Name of the signature. + * @return array Array defining page and rectangle coordinates of signature appearance. * @protected * @author Nicola Asuni * @since 5.9.101 (2011-07-06) @@ -13564,10 +13647,10 @@ class TCPDF { * Enable document timestamping (requires the OpenSSL Library). * The trusted timestamping improve document security that means that no one should be able to change the document once it has been recorded. * Use with digital signature only! - * @param $tsa_host (string) Time Stamping Authority (TSA) server (prefixed with 'https://') - * @param $tsa_username (string) Specifies the username for TSA authorization (optional) OR specifies the TSA authorization PEM file (see: example_66.php, optional) - * @param $tsa_password (string) Specifies the password for TSA authorization (optional) - * @param $tsa_cert (string) Specifies the location of TSA certificate for authorization (optional for cURL) + * @param string $tsa_host Time Stamping Authority (TSA) server (prefixed with 'https://') + * @param string $tsa_username Specifies the username for TSA authorization (optional) OR specifies the TSA authorization PEM file (see: example_66.php, optional) + * @param string $tsa_password Specifies the password for TSA authorization (optional) + * @param string $tsa_cert Specifies the location of TSA certificate for authorization (optional for cURL) * @public * @author Richard Stockinger * @since 6.0.090 (2014-06-16) @@ -13594,8 +13677,8 @@ class TCPDF { /** * NOT YET IMPLEMENTED * Request TSA for a timestamp - * @param $signature (string) Digital signature as binary string - * @return (string) Timestamped digital signature + * @param string $signature Digital signature as binary string + * @return string Timestamped digital signature * @protected * @author Richard Stockinger * @since 6.0.090 (2014-06-16) @@ -13611,11 +13694,11 @@ class TCPDF { /** * Create a new page group. * NOTE: call this function before calling AddPage() - * @param $page (int) starting group page (leave empty for next page). + * @param int|null $page starting group page (leave empty for next page). * @public * @since 3.0.000 (2008-03-27) */ - public function startPageGroup($page='') { + public function startPageGroup($page=null) { if (empty($page)) { $page = $this->page + 1; } @@ -13624,7 +13707,7 @@ class TCPDF { /** * Set the starting page number. - * @param $num (int) Starting page number. + * @param int $num Starting page number. * @since 5.9.093 (2011-06-16) * @public */ @@ -13691,7 +13774,7 @@ class TCPDF { * Return the alias for the total number of pages in the current page group. * If the current font is unicode type, the returned string is surrounded by additional curly braces. * This alias will be replaced by the total number of pages in this group. - * @return alias of the current page group + * @return string alias of the current page group * @public * @since 3.0.000 (2008-03-27) */ @@ -13706,7 +13789,7 @@ class TCPDF { * Return the alias for the page number on the current page group. * If the current font is unicode type, the returned string is surrounded by additional curly braces. * This alias will be replaced by the page number (relative to the belonging group). - * @return alias of the current page group + * @return string alias of the current page group * @public * @since 4.5.000 (2009-01-02) */ @@ -13719,7 +13802,7 @@ class TCPDF { /** * Return the current page in the group. - * @return current page in the group + * @return int current page in the group * @public * @since 3.0.000 (2008-03-27) */ @@ -13773,10 +13856,10 @@ class TCPDF { /** * Start a new pdf layer. - * @param $name (string) Layer name (only a-z letters and numbers). Leave empty for automatic name. - * @param $print (boolean|null) Set to TRUE to print this layer, FALSE to not print and NULL to not set this option - * @param $view (boolean) Set to true to view this layer. - * @param $lock (boolean) If true lock the layer + * @param string $name Layer name (only a-z letters and numbers). Leave empty for automatic name. + * @param boolean|null $print Set to TRUE to print this layer, FALSE to not print and NULL to not set this option + * @param boolean $view Set to true to view this layer. + * @param boolean $lock If true lock the layer * @public * @since 5.9.102 (2011-07-13) */ @@ -13815,7 +13898,7 @@ class TCPDF { * Set the visibility of the successive elements. * This can be useful, for instance, to put a background * image or color that will show on screen but won't print. - * @param $v (string) visibility mode. Legal values are: all, print, screen or view. + * @param string $v visibility mode. Legal values are: all, print, screen or view. * @public * @since 3.0.000 (2008-03-27) */ @@ -13847,14 +13930,14 @@ class TCPDF { /** * Add transparency parameters to the current extgstate - * @param $parms (array) parameters - * @return the number of extgstates + * @param array $parms parameters + * @return int|void the number of extgstates * @protected * @since 3.0.000 (2008-03-27) */ protected function addExtGState($parms) { - if ($this->pdfa_mode) { - // transparencies are not allowed in PDF/A mode + if (($this->pdfa_mode && $this->pdfa_version < 2) || ($this->state != 2)) { + // transparency is not allowed in PDF/A-1 mode return; } // check if this ExtGState already exist @@ -13879,13 +13962,13 @@ class TCPDF { /** * Add an extgstate - * @param $gs (array) extgstate + * @param int $gs extgstate * @protected * @since 3.0.000 (2008-03-27) */ protected function setExtGState($gs) { - if ($this->pdfa_mode OR ($this->state != 2)) { - // transparency is not allowed in PDF/A mode + if (($this->pdfa_mode && $this->pdfa_version < 2) OR ($this->state != 2)) { + // transparency is not allowed in PDF/A-1 mode return; } $this->_out(sprintf('/GS%d gs', $gs)); @@ -13919,13 +14002,13 @@ class TCPDF { /** * Set overprint mode for stroking (OP) and non-stroking (op) painting operations. * (Check the "Entries in a Graphics State Parameter Dictionary" on PDF 32000-1:2008). - * @param $stroking (boolean) If true apply overprint for stroking operations. - * @param $nonstroking (boolean) If true apply overprint for painting operations other than stroking. - * @param $mode (integer) Overprint mode: (0 = each source colour component value replaces the value previously painted for the corresponding device colorant; 1 = a tint value of 0.0 for a source colour component shall leave the corresponding component of the previously painted colour unchanged). + * @param boolean $stroking If true apply overprint for stroking operations. + * @param boolean|null $nonstroking If true apply overprint for painting operations other than stroking. + * @param integer $mode Overprint mode: (0 = each source colour component value replaces the value previously painted for the corresponding device colorant; 1 = a tint value of 0.0 for a source colour component shall leave the corresponding component of the previously painted colour unchanged). * @public * @since 5.9.152 (2012-03-23) */ - public function setOverprint($stroking=true, $nonstroking='', $mode=0) { + public function setOverprint($stroking=true, $nonstroking=null, $mode=0) { if ($this->state != 2) { return; } @@ -13947,7 +14030,7 @@ class TCPDF { /** * Get the overprint mode array (OP, op, OPM). * (Check the "Entries in a Graphics State Parameter Dictionary" on PDF 32000-1:2008). - * @return array. + * @return array * @public * @since 5.9.152 (2012-03-23) */ @@ -13957,16 +14040,16 @@ class TCPDF { /** * Set alpha for stroking (CA) and non-stroking (ca) operations. - * @param $stroking (float) Alpha value for stroking operations: real value from 0 (transparent) to 1 (opaque). - * @param $bm (string) blend mode, one of the following: Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity - * @param $nonstroking (float) Alpha value for non-stroking operations: real value from 0 (transparent) to 1 (opaque). - * @param $ais (boolean) + * @param float $stroking Alpha value for stroking operations: real value from 0 (transparent) to 1 (opaque). + * @param string $bm blend mode, one of the following: Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity + * @param float|null $nonstroking Alpha value for non-stroking operations: real value from 0 (transparent) to 1 (opaque). + * @param boolean $ais * @public * @since 3.0.000 (2008-03-27) */ - public function setAlpha($stroking=1, $bm='Normal', $nonstroking='', $ais=false) { - if ($this->pdfa_mode) { - // transparency is not allowed in PDF/A mode + public function setAlpha($stroking=1, $bm='Normal', $nonstroking=null, $ais=false) { + if ($this->pdfa_mode && $this->pdfa_version < 2) { + // transparency is not allowed in PDF/A-1 mode return; } $stroking = floatval($stroking); @@ -13992,7 +14075,7 @@ class TCPDF { /** * Get the alpha mode array (CA, ca, BM, AIS). * (Check the "Entries in a Graphics State Parameter Dictionary" on PDF 32000-1:2008). - * @return array. + * @return array * @public * @since 5.9.152 (2012-03-23) */ @@ -14002,7 +14085,7 @@ class TCPDF { /** * Set the default JPEG compression quality (1-100) - * @param $quality (int) JPEG quality, integer between 1 and 100 + * @param int $quality JPEG quality, integer between 1 and 100 * @public * @since 3.0.000 (2008-03-27) */ @@ -14015,7 +14098,7 @@ class TCPDF { /** * Set the default number of columns in a row for HTML tables. - * @param $cols (int) number of columns + * @param int $cols number of columns * @public * @since 3.0.014 (2008-06-04) */ @@ -14025,7 +14108,7 @@ class TCPDF { /** * Set the height of the cell (line height) respect the font height. - * @param $h (int) cell proportion respect font height (typical value = 1.25). + * @param float $h cell proportion respect font height (typical value = 1.25). * @public * @since 3.0.014 (2008-06-04) */ @@ -14036,6 +14119,7 @@ class TCPDF { /** * return the height of cell repect font height. * @public + * @return float * @since 4.0.012 (2008-07-24) */ public function getCellHeightRatio() { @@ -14044,15 +14128,18 @@ class TCPDF { /** * Set the PDF version (check PDF reference for valid values). - * @param $version (string) PDF document version. + * @param string $version PDF document version. * @public * @since 3.1.000 (2008-06-09) */ public function setPDFVersion($version='1.7') { if ($this->pdfa_mode && $this->pdfa_version == 1 ) { - // PDF/A mode + // PDF/A-1 mode $this->PDFVersion = '1.4'; - } else { + } elseif ($this->pdfa_mode && $this->pdfa_version >= 2 ) { + // PDF/A-2 mode + $this->PDFVersion = '1.7'; + } else { $this->PDFVersion = $version; } } @@ -14061,7 +14148,7 @@ class TCPDF { * Set the viewer preferences dictionary controlling the way the document is to be presented on the screen or in print. * (see Section 8.1 of PDF reference, "Viewer Preferences"). *
              • HideToolbar boolean (Optional) A flag specifying whether to hide the viewer application's tool bars when the document is active. Default value: false.
              • HideMenubar boolean (Optional) A flag specifying whether to hide the viewer application's menu bar when the document is active. Default value: false.
              • HideWindowUI boolean (Optional) A flag specifying whether to hide user interface elements in the document's window (such as scroll bars and navigation controls), leaving only the document's contents displayed. Default value: false.
              • FitWindow boolean (Optional) A flag specifying whether to resize the document's window to fit the size of the first displayed page. Default value: false.
              • CenterWindow boolean (Optional) A flag specifying whether to position the document's window in the center of the screen. Default value: false.
              • DisplayDocTitle boolean (Optional; PDF 1.4) A flag specifying whether the window's title bar should display the document title taken from the Title entry of the document information dictionary (see Section 10.2.1, "Document Information Dictionary"). If false, the title bar should instead display the name of the PDF file containing the document. Default value: false.
              • NonFullScreenPageMode name (Optional) The document's page mode, specifying how to display the document on exiting full-screen mode:
                • UseNone Neither document outline nor thumbnail images visible
                • UseOutlines Document outline visible
                • UseThumbs Thumbnail images visible
                • UseOC Optional content group panel visible
                This entry is meaningful only if the value of the PageMode entry in the catalog dictionary (see Section 3.6.1, "Document Catalog") is FullScreen; it is ignored otherwise. Default value: UseNone.
              • ViewArea name (Optional; PDF 1.4) The name of the page boundary representing the area of a page to be displayed when viewing the document on the screen. Valid values are (see Section 10.10.1, "Page Boundaries").:
                • MediaBox
                • CropBox (default)
                • BleedBox
                • TrimBox
                • ArtBox
              • ViewClip name (Optional; PDF 1.4) The name of the page boundary to which the contents of a page are to be clipped when viewing the document on the screen. Valid values are (see Section 10.10.1, "Page Boundaries").:
                • MediaBox
                • CropBox (default)
                • BleedBox
                • TrimBox
                • ArtBox
              • PrintArea name (Optional; PDF 1.4) The name of the page boundary representing the area of a page to be rendered when printing the document. Valid values are (see Section 10.10.1, "Page Boundaries").:
                • MediaBox
                • CropBox (default)
                • BleedBox
                • TrimBox
                • ArtBox
              • PrintClip name (Optional; PDF 1.4) The name of the page boundary to which the contents of a page are to be clipped when printing the document. Valid values are (see Section 10.10.1, "Page Boundaries").:
                • MediaBox
                • CropBox (default)
                • BleedBox
                • TrimBox
                • ArtBox
              • PrintScaling name (Optional; PDF 1.6) The page scaling option to be selected when a print dialog is displayed for this document. Valid values are:
                • None, which indicates that the print dialog should reflect no page scaling
                • AppDefault (default), which indicates that applications should use the current print scaling
              • Duplex name (Optional; PDF 1.7) The paper handling option to use when printing the file from the print dialog. The following values are valid:
                • Simplex - Print single-sided
                • DuplexFlipShortEdge - Duplex and flip on the short edge of the sheet
                • DuplexFlipLongEdge - Duplex and flip on the long edge of the sheet
                Default value: none
              • PickTrayByPDFSize boolean (Optional; PDF 1.7) A flag specifying whether the PDF page size is used to select the input paper tray. This setting influences only the preset values used to populate the print dialog presented by a PDF viewer application. If PickTrayByPDFSize is true, the check box in the print dialog associated with input paper tray is checked. Note: This setting has no effect on Mac OS systems, which do not provide the ability to pick the input tray by size.
              • PrintPageRange array (Optional; PDF 1.7) The page numbers used to initialize the print dialog box when the file is printed. The first page of the PDF file is denoted by 1. Each pair consists of the first and last pages in the sub-range. An odd number of integers causes this entry to be ignored. Negative numbers cause the entire array to be ignored. Default value: as defined by PDF viewer application
              • NumCopies integer (Optional; PDF 1.7) The number of copies to be printed when the print dialog is opened for this file. Supported values are the integers 2 through 5. Values outside this range are ignored. Default value: as defined by PDF viewer application, but typically 1
              - * @param $preferences (array) array of options. + * @param array $preferences array of options. * @author Nicola Asuni * @public * @since 3.1.000 (2008-06-09) @@ -14072,13 +14159,13 @@ class TCPDF { /** * Paints color transition registration bars - * @param $x (float) abscissa of the top left corner of the rectangle. - * @param $y (float) ordinate of the top left corner of the rectangle. - * @param $w (float) width of the rectangle. - * @param $h (float) height of the rectangle. - * @param $transition (boolean) if true prints tcolor transitions to white. - * @param $vertical (boolean) if true prints bar vertically. - * @param $colors (string) colors to print separated by comma. Valid values are: A,W,R,G,B,C,M,Y,K,RGB,CMYK,ALL,ALLSPOT,. Where: A = grayscale black, W = grayscale white, R = RGB red, G RGB green, B RGB blue, C = CMYK cyan, M = CMYK magenta, Y = CMYK yellow, K = CMYK key/black, RGB = RGB registration color, CMYK = CMYK registration color, ALL = Spot registration color, ALLSPOT = print all defined spot colors, = name of the spot color to print. + * @param float $x abscissa of the top left corner of the rectangle. + * @param float $y ordinate of the top left corner of the rectangle. + * @param float $w width of the rectangle. + * @param float $h height of the rectangle. + * @param boolean $transition if true prints tcolor transitions to white. + * @param boolean $vertical if true prints bar vertically. + * @param string $colors colors to print separated by comma. Valid values are: A,W,R,G,B,C,M,Y,K,RGB,CMYK,ALL,ALLSPOT,. Where: A = grayscale black, W = grayscale white, R = RGB red, G RGB green, B RGB blue, C = CMYK cyan, M = CMYK magenta, Y = CMYK yellow, K = CMYK key/black, RGB = RGB registration color, CMYK = CMYK registration color, ALL = Spot registration color, ALLSPOT = print all defined spot colors, = name of the spot color to print. * @author Nicola Asuni * @since 4.9.000 (2010-03-26) * @public @@ -14201,7 +14288,7 @@ class TCPDF { // color gradient $this->LinearGradient($xb, $yb, $wb, $hb, $col_a, $col_b, $coords); } else { - $this->SetFillColorArray($col_b); + $this->setFillColorArray($col_b); // colored rectangle $this->Rect($xb, $yb, $wb, $hb, 'F', array()); } @@ -14213,18 +14300,18 @@ class TCPDF { /** * Paints crop marks. - * @param $x (float) abscissa of the crop mark center. - * @param $y (float) ordinate of the crop mark center. - * @param $w (float) width of the crop mark. - * @param $h (float) height of the crop mark. - * @param $type (string) type of crop mark, one symbol per type separated by comma: T = TOP, F = BOTTOM, L = LEFT, R = RIGHT, TL = A = TOP-LEFT, TR = B = TOP-RIGHT, BL = C = BOTTOM-LEFT, BR = D = BOTTOM-RIGHT. - * @param $color (array) crop mark color (default spot registration color). + * @param float $x abscissa of the crop mark center. + * @param float $y ordinate of the crop mark center. + * @param float $w width of the crop mark. + * @param float $h height of the crop mark. + * @param string $type type of crop mark, one symbol per type separated by comma: T = TOP, F = BOTTOM, L = LEFT, R = RIGHT, TL = A = TOP-LEFT, TR = B = TOP-RIGHT, BL = C = BOTTOM-LEFT, BR = D = BOTTOM-RIGHT. + * @param array $color crop mark color (default spot registration color). * @author Nicola Asuni * @since 4.9.000 (2010-03-26) * @public */ public function cropMark($x, $y, $w, $h, $type='T,R,B,L', $color=array(100,100,100,100,'All')) { - $this->SetLineStyle(array('width' => (0.5 / $this->k), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $color)); + $this->setLineStyle(array('width' => (0.5 / $this->k), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $color)); $type = strtoupper($type); $type = preg_replace('/[^A-Z\-\,]*/', '', $type); // split type in single components @@ -14284,28 +14371,28 @@ class TCPDF { /** * Paints a registration mark - * @param $x (float) abscissa of the registration mark center. - * @param $y (float) ordinate of the registration mark center. - * @param $r (float) radius of the crop mark. - * @param $double (boolean) if true print two concentric crop marks. - * @param $cola (array) crop mark color (default spot registration color 'All'). - * @param $colb (array) second crop mark color (default spot registration color 'None'). + * @param float $x abscissa of the registration mark center. + * @param float $y ordinate of the registration mark center. + * @param float $r radius of the crop mark. + * @param boolean $double if true print two concentric crop marks. + * @param array $cola crop mark color (default spot registration color 'All'). + * @param array $colb second crop mark color (default spot registration color 'None'). * @author Nicola Asuni * @since 4.9.000 (2010-03-26) * @public */ public function registrationMark($x, $y, $r, $double=false, $cola=array(100,100,100,100,'All'), $colb=array(0,0,0,0,'None')) { $line_style = array('width' => max((0.5 / $this->k),($r / 30)), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $cola); - $this->SetFillColorArray($cola); + $this->setFillColorArray($cola); $this->PieSector($x, $y, $r, 90, 180, 'F'); $this->PieSector($x, $y, $r, 270, 360, 'F'); $this->Circle($x, $y, $r, 0, 360, 'C', $line_style, array(), 8); if ($double) { $ri = $r * 0.5; - $this->SetFillColorArray($colb); + $this->setFillColorArray($colb); $this->PieSector($x, $y, $ri, 90, 180, 'F'); $this->PieSector($x, $y, $ri, 270, 360, 'F'); - $this->SetFillColorArray($cola); + $this->setFillColorArray($cola); $this->PieSector($x, $y, $ri, 0, 90, 'F'); $this->PieSector($x, $y, $ri, 180, 270, 'F'); $this->Circle($x, $y, $ri, 0, 360, 'C', $line_style, array(), 8); @@ -14314,9 +14401,9 @@ class TCPDF { /** * Paints a CMYK registration mark - * @param $x (float) abscissa of the registration mark center. - * @param $y (float) ordinate of the registration mark center. - * @param $r (float) radius of the crop mark. + * @param float $x abscissa of the registration mark center. + * @param float $y ordinate of the registration mark center. + * @param float $r radius of the crop mark. * @author Nicola Asuni * @since 6.0.038 (2013-09-30) * @public @@ -14329,20 +14416,20 @@ class TCPDF { // external radius $re = ($r * 1.3); // Cyan - $this->SetFillColorArray(array(100,0,0,0)); + $this->setFillColorArray(array(100,0,0,0)); $this->PieSector($x, $y, $ri, 270, 360, 'F'); // Magenta - $this->SetFillColorArray(array(0,100,0,0)); + $this->setFillColorArray(array(0,100,0,0)); $this->PieSector($x, $y, $ri, 0, 90, 'F'); // Yellow - $this->SetFillColorArray(array(0,0,100,0)); + $this->setFillColorArray(array(0,0,100,0)); $this->PieSector($x, $y, $ri, 90, 180, 'F'); // Key - black - $this->SetFillColorArray(array(0,0,0,100)); + $this->setFillColorArray(array(0,0,0,100)); $this->PieSector($x, $y, $ri, 180, 270, 'F'); // registration color $line_style = array('width' => $lw, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(100,100,100,100,'All')); - $this->SetFillColorArray(array(100,100,100,100,'All')); + $this->setFillColorArray(array(100,100,100,100,'All')); // external circle $this->Circle($x, $y, $r, 0, 360, 'C', $line_style, array(), 8); // cross lines @@ -14354,13 +14441,13 @@ class TCPDF { /** * Paints a linear colour gradient. - * @param $x (float) abscissa of the top left corner of the rectangle. - * @param $y (float) ordinate of the top left corner of the rectangle. - * @param $w (float) width of the rectangle. - * @param $h (float) height of the rectangle. - * @param $col1 (array) first color (Grayscale, RGB or CMYK components). - * @param $col2 (array) second color (Grayscale, RGB or CMYK components). - * @param $coords (array) array of the form (x1, y1, x2, y2) which defines the gradient vector (see linear_gradient_coords.jpg). The default value is from left to right (x1=0, y1=0, x2=1, y2=0). + * @param float $x abscissa of the top left corner of the rectangle. + * @param float $y ordinate of the top left corner of the rectangle. + * @param float $w width of the rectangle. + * @param float $h height of the rectangle. + * @param array $col1 first color (Grayscale, RGB or CMYK components). + * @param array $col2 second color (Grayscale, RGB or CMYK components). + * @param array $coords array of the form (x1, y1, x2, y2) which defines the gradient vector (see linear_gradient_coords.jpg). The default value is from left to right (x1=0, y1=0, x2=1, y2=0). * @author Andreas W\FCrmser, Nicola Asuni * @since 3.1.000 (2008-06-09) * @public @@ -14372,13 +14459,13 @@ class TCPDF { /** * Paints a radial colour gradient. - * @param $x (float) abscissa of the top left corner of the rectangle. - * @param $y (float) ordinate of the top left corner of the rectangle. - * @param $w (float) width of the rectangle. - * @param $h (float) height of the rectangle. - * @param $col1 (array) first color (Grayscale, RGB or CMYK components). - * @param $col2 (array) second color (Grayscale, RGB or CMYK components). - * @param $coords (array) array of the form (fx, fy, cx, cy, r) where (fx, fy) is the starting point of the gradient with color1, (cx, cy) is the center of the circle with color2, and r is the radius of the circle (see radial_gradient_coords.jpg). (fx, fy) should be inside the circle, otherwise some areas will not be defined. + * @param float $x abscissa of the top left corner of the rectangle. + * @param float $y ordinate of the top left corner of the rectangle. + * @param float $w width of the rectangle. + * @param float $h height of the rectangle. + * @param array $col1 first color (Grayscale, RGB or CMYK components). + * @param array $col2 second color (Grayscale, RGB or CMYK components). + * @param array $coords array of the form (fx, fy, cx, cy, r) where (fx, fy) is the starting point of the gradient with color1, (cx, cy) is the center of the circle with color2, and r is the radius of the circle (see radial_gradient_coords.jpg). (fx, fy) should be inside the circle, otherwise some areas will not be defined. * @author Andreas W\FCrmser, Nicola Asuni * @since 3.1.000 (2008-06-09) * @public @@ -14390,24 +14477,24 @@ class TCPDF { /** * Paints a coons patch mesh. - * @param $x (float) abscissa of the top left corner of the rectangle. - * @param $y (float) ordinate of the top left corner of the rectangle. - * @param $w (float) width of the rectangle. - * @param $h (float) height of the rectangle. - * @param $col1 (array) first color (lower left corner) (RGB components). - * @param $col2 (array) second color (lower right corner) (RGB components). - * @param $col3 (array) third color (upper right corner) (RGB components). - * @param $col4 (array) fourth color (upper left corner) (RGB components). - * @param $coords (array)
              • for one patch mesh: array(float x1, float y1, .... float x12, float y12): 12 pairs of coordinates (normally from 0 to 1) which specify the Bezier control points that define the patch. First pair is the lower left edge point, next is its right control point (control point 2). Then the other points are defined in the order: control point 1, edge point, control point 2 going counter-clockwise around the patch. Last (x12, y12) is the first edge point's left control point (control point 1).
              • for two or more patch meshes: array[number of patches]: arrays with the following keys for each patch: f: where to put that patch (0 = first patch, 1, 2, 3 = right, top and left of precedent patch - I didn't figure this out completely - just try and error ;-) points: 12 pairs of coordinates of the Bezier control points as above for the first patch, 8 pairs of coordinates for the following patches, ignoring the coordinates already defined by the precedent patch (I also didn't figure out the order of these - also: try and see what's happening) colors: must be 4 colors for the first patch, 2 colors for the following patches
              - * @param $coords_min (array) minimum value used by the coordinates. If a coordinate's value is smaller than this it will be cut to coords_min. default: 0 - * @param $coords_max (array) maximum value used by the coordinates. If a coordinate's value is greater than this it will be cut to coords_max. default: 1 - * @param $antialias (boolean) A flag indicating whether to filter the shading function to prevent aliasing artifacts. + * @param float $x abscissa of the top left corner of the rectangle. + * @param float $y ordinate of the top left corner of the rectangle. + * @param float $w width of the rectangle. + * @param float $h height of the rectangle. + * @param array $col1 first color (lower left corner) (RGB components). + * @param array $col2 second color (lower right corner) (RGB components). + * @param array $col3 third color (upper right corner) (RGB components). + * @param array $col4 fourth color (upper left corner) (RGB components). + * @param array $coords
              • for one patch mesh: array(float x1, float y1, .... float x12, float y12): 12 pairs of coordinates (normally from 0 to 1) which specify the Bezier control points that define the patch. First pair is the lower left edge point, next is its right control point (control point 2). Then the other points are defined in the order: control point 1, edge point, control point 2 going counter-clockwise around the patch. Last (x12, y12) is the first edge point's left control point (control point 1).
              • for two or more patch meshes: array[number of patches]: arrays with the following keys for each patch: f: where to put that patch (0 = first patch, 1, 2, 3 = right, top and left of precedent patch - I didn't figure this out completely - just try and error ;-) points: 12 pairs of coordinates of the Bezier control points as above for the first patch, 8 pairs of coordinates for the following patches, ignoring the coordinates already defined by the precedent patch (I also didn't figure out the order of these - also: try and see what's happening) colors: must be 4 colors for the first patch, 2 colors for the following patches
              + * @param array $coords_min minimum value used by the coordinates. If a coordinate's value is smaller than this it will be cut to coords_min. default: 0 + * @param array $coords_max maximum value used by the coordinates. If a coordinate's value is greater than this it will be cut to coords_max. default: 1 + * @param boolean $antialias A flag indicating whether to filter the shading function to prevent aliasing artifacts. * @author Andreas W\FCrmser, Nicola Asuni * @since 3.1.000 (2008-06-09) * @public */ public function CoonsPatchMesh($x, $y, $w, $h, $col1=array(), $col2=array(), $col3=array(), $col4=array(), $coords=array(0.00,0.0,0.33,0.00,0.67,0.00,1.00,0.00,1.00,0.33,1.00,0.67,1.00,1.00,0.67,1.00,0.33,1.00,0.00,1.00,0.00,0.67,0.00,0.33), $coords_min=0, $coords_max=1, $antialias=false) { - if ($this->pdfa_mode OR ($this->state != 2)) { + if (($this->pdfa_mode && $this->pdfa_version < 2) OR ($this->state != 2)) { return; } $this->Clip($x, $y, $w, $h); @@ -14467,8 +14554,8 @@ class TCPDF { if ($patch_array[$i]['points'][$j] > $bpcd) { $patch_array[$i]['points'][$j] = $bpcd; } - $this->gradients[$n]['stream'] .= chr(floor($patch_array[$i]['points'][$j] / 256)); - $this->gradients[$n]['stream'] .= chr(floor($patch_array[$i]['points'][$j] % 256)); + $this->gradients[$n]['stream'] .= chr((int) floor($patch_array[$i]['points'][$j] / 256)); + $this->gradients[$n]['stream'] .= chr((int) floor(intval($patch_array[$i]['points'][$j]) % 256)); } $count_cols = count($patch_array[$i]['colors']); for ($j=0; $j < $count_cols; ++$j) { @@ -14490,10 +14577,10 @@ class TCPDF { /** * Set a rectangular clipping area. - * @param $x (float) abscissa of the top left corner of the rectangle (or top right corner for RTL mode). - * @param $y (float) ordinate of the top left corner of the rectangle. - * @param $w (float) width of the rectangle. - * @param $h (float) height of the rectangle. + * @param float $x abscissa of the top left corner of the rectangle (or top right corner for RTL mode). + * @param float $y ordinate of the top left corner of the rectangle. + * @param float $w width of the rectangle. + * @param float $h height of the rectangle. * @author Andreas W\FCrmser, Nicola Asuni * @since 3.1.000 (2008-06-09) * @protected @@ -14516,17 +14603,17 @@ class TCPDF { /** * Output gradient. - * @param $type (int) type of gradient (1 Function-based shading; 2 Axial shading; 3 Radial shading; 4 Free-form Gouraud-shaded triangle mesh; 5 Lattice-form Gouraud-shaded triangle mesh; 6 Coons patch mesh; 7 Tensor-product patch mesh). (Not all types are currently supported) - * @param $coords (array) array of coordinates. - * @param $stops (array) array gradient color components: color = array of GRAY, RGB or CMYK color components; offset = (0 to 1) represents a location along the gradient vector; exponent = exponent of the exponential interpolation function (default = 1). - * @param $background (array) An array of colour components appropriate to the colour space, specifying a single background colour value. - * @param $antialias (boolean) A flag indicating whether to filter the shading function to prevent aliasing artifacts. + * @param int $type type of gradient (1 Function-based shading; 2 Axial shading; 3 Radial shading; 4 Free-form Gouraud-shaded triangle mesh; 5 Lattice-form Gouraud-shaded triangle mesh; 6 Coons patch mesh; 7 Tensor-product patch mesh). (Not all types are currently supported) + * @param array $coords array of coordinates. + * @param array $stops array gradient color components: color = array of GRAY, RGB or CMYK color components; offset = (0 to 1) represents a location along the gradient vector; exponent = exponent of the exponential interpolation function (default = 1). + * @param array $background An array of colour components appropriate to the colour space, specifying a single background colour value. + * @param boolean $antialias A flag indicating whether to filter the shading function to prevent aliasing artifacts. * @author Nicola Asuni * @since 3.1.000 (2008-06-09) * @public */ public function Gradient($type, $coords, $stops, $background=array(), $antialias=false) { - if ($this->pdfa_mode OR ($this->state != 2)) { + if (($this->pdfa_mode && $this->pdfa_version < 2) OR ($this->state != 2)) { return; } $n = count($this->gradients) + 1; @@ -14582,7 +14669,7 @@ class TCPDF { } if (isset($stop['opacity'])) { $this->gradients[$n]['colors'][$key]['opacity'] = $stop['opacity']; - if ((!$this->pdfa_mode) AND ($stop['opacity'] < 1)) { + if ((!($this->pdfa_mode && $this->pdfa_version < 2)) AND ($stop['opacity'] < 1)) { $this->gradients[$n]['transparency'] = true; } } else { @@ -14633,7 +14720,7 @@ class TCPDF { * @protected */ function _putshaders() { - if ($this->pdfa_mode) { + if ($this->pdfa_mode && $this->pdfa_version < 2) { return; } $idt = count($this->gradients); //index for transparency gradients @@ -14812,14 +14899,14 @@ class TCPDF { /** * Draw the sector of a circle. * It can be used for instance to render pie charts. - * @param $xc (float) abscissa of the center. - * @param $yc (float) ordinate of the center. - * @param $r (float) radius. - * @param $a (float) start angle (in degrees). - * @param $b (float) end angle (in degrees). - * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information. - * @param $cw: (float) indicates whether to go clockwise (default: true). - * @param $o: (float) origin of angles (0 for 3 o'clock, 90 for noon, 180 for 9 o'clock, 270 for 6 o'clock). Default: 90. + * @param float $xc abscissa of the center. + * @param float $yc ordinate of the center. + * @param float $r radius. + * @param float $a start angle (in degrees). + * @param float $b end angle (in degrees). + * @param string $style Style of rendering. See the getPathPaintOperator() function for more information. + * @param float $cw indicates whether to go clockwise (default: true). + * @param float $o origin of angles (0 for 3 o'clock, 90 for noon, 180 for 9 o'clock, 270 for 6 o'clock). Default: 90. * @author Maxime Delorme, Nicola Asuni * @since 3.1.000 (2008-06-09) * @public @@ -14831,16 +14918,16 @@ class TCPDF { /** * Draw the sector of an ellipse. * It can be used for instance to render pie charts. - * @param $xc (float) abscissa of the center. - * @param $yc (float) ordinate of the center. - * @param $rx (float) the x-axis radius. - * @param $ry (float) the y-axis radius. - * @param $a (float) start angle (in degrees). - * @param $b (float) end angle (in degrees). - * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information. - * @param $cw: (float) indicates whether to go clockwise. - * @param $o: (float) origin of angles (0 for 3 o'clock, 90 for noon, 180 for 9 o'clock, 270 for 6 o'clock). - * @param $nc (integer) Number of curves used to draw a 90 degrees portion of arc. + * @param float $xc abscissa of the center. + * @param float $yc ordinate of the center. + * @param float $rx the x-axis radius. + * @param float $ry the y-axis radius. + * @param float $a start angle (in degrees). + * @param float $b end angle (in degrees). + * @param string $style Style of rendering. See the getPathPaintOperator() function for more information. + * @param float $cw indicates whether to go clockwise. + * @param float $o origin of angles (0 for 3 o'clock, 90 for noon, 180 for 9 o'clock, 270 for 6 o'clock). + * @param integer $nc Number of curves used to draw a 90 degrees portion of arc. * @author Maxime Delorme, Nicola Asuni * @since 3.1.000 (2008-06-09) * @public @@ -14873,23 +14960,23 @@ class TCPDF { * NOTE: EPS is not yet fully implemented, use the setRasterizeVectorImages() method to enable/disable rasterization of vector images using ImageMagick library. * Only vector drawing is supported, not text or bitmap. * Although the script was successfully tested with various AI format versions, best results are probably achieved with files that were exported in the AI3 format (tested with Illustrator CS2, Freehand MX and Photoshop CS2). - * @param $file (string) Name of the file containing the image or a '@' character followed by the EPS/AI data string. - * @param $x (float) Abscissa of the upper-left corner. - * @param $y (float) Ordinate of the upper-left corner. - * @param $w (float) Width of the image in the page. If not specified or equal to zero, it is automatically calculated. - * @param $h (float) Height of the image in the page. If not specified or equal to zero, it is automatically calculated. - * @param $link (mixed) URL or identifier returned by AddLink(). - * @param $useBoundingBox (boolean) specifies whether to position the bounding box (true) or the complete canvas (false) at location (x,y). Default value is true. - * @param $align (string) Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:
              • T: top-right for LTR or top-left for RTL
              • M: middle-right for LTR or middle-left for RTL
              • B: bottom-right for LTR or bottom-left for RTL
              • N: next line
              - * @param $palign (string) Allows to center or align the image on the current line. Possible values are:
              • L : left align
              • C : center
              • R : right align
              • '' : empty string : left for LTR or right for RTL
              - * @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) - * @param $fitonpage (boolean) if true the image is resized to not exceed page dimensions. - * @param $fixoutvals (boolean) if true remove values outside the bounding box. + * @param string $file Name of the file containing the image or a '@' character followed by the EPS/AI data string. + * @param float|null $x Abscissa of the upper-left corner. + * @param float|null $y Ordinate of the upper-left corner. + * @param float $w Width of the image in the page. If not specified or equal to zero, it is automatically calculated. + * @param float $h Height of the image in the page. If not specified or equal to zero, it is automatically calculated. + * @param mixed $link URL or identifier returned by AddLink(). + * @param boolean $useBoundingBox specifies whether to position the bounding box (true) or the complete canvas (false) at location (x,y). Default value is true. + * @param string $align Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:
              • T: top-right for LTR or top-left for RTL
              • M: middle-right for LTR or middle-left for RTL
              • B: bottom-right for LTR or bottom-left for RTL
              • N: next line
              + * @param string $palign Allows to center or align the image on the current line. Possible values are:
              • L : left align
              • C : center
              • R : right align
              • '' : empty string : left for LTR or right for RTL
              + * @param mixed $border Indicates if borders must be drawn around the cell. The value can be a number:
              • 0: no border (default)
              • 1: frame
              or a string containing some or all of the following characters (in any order):
              • L: left
              • T: top
              • R: right
              • B: bottom
              or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) + * @param boolean $fitonpage if true the image is resized to not exceed page dimensions. + * @param boolean $fixoutvals if true remove values outside the bounding box. * @author Valentin Schmidt, Nicola Asuni * @since 3.1.000 (2008-06-09) * @public */ - public function ImageEps($file, $x='', $y='', $w=0, $h=0, $link='', $useBoundingBox=true, $align='', $palign='', $border=0, $fitonpage=false, $fixoutvals=false) { + public function ImageEps($file, $x=null, $y=null, $w=0, $h=0, $link='', $useBoundingBox=true, $align='', $palign='', $border=0, $fitonpage=false, $fixoutvals=false) { if ($this->state != 2) { return; } @@ -14897,10 +14984,10 @@ class TCPDF { // convert EPS to raster image using GD or ImageMagick libraries return $this->Image($file, $x, $y, $w, $h, 'EPS', $link, $align, true, 300, $palign, false, false, $border, false, false, $fitonpage); } - if ($x === '') { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if ($y === '') { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } // check page for no-write regions and adapt page margins if necessary @@ -14909,7 +14996,7 @@ class TCPDF { if ($file[0] === '@') { // image from string $data = substr($file, 1); } else { // EPS/AI file - $data = TCPDF_STATIC::fileGetContents($file); + $data = $this->getCachedFileContents($file); } if ($data === FALSE) { $this->Error('EPS file not found: '.$file); @@ -15010,9 +15097,7 @@ class TCPDF { // translate $this->_out(sprintf('%F %F %F %F %F %F cm', 1, 0, 0, 1, $dx, $dy + ($this->hPt - (2 * $y * $k) - ($y2 - $y1)))); // scale - if (isset($scale_x)) { - $this->_out(sprintf('%F %F %F %F %F %F cm', $scale_x, 0, 0, $scale_y, $x1 * (1 - $scale_x), $y2 * (1 - $scale_y))); - } + $this->_out(sprintf('%F %F %F %F %F %F cm', $scale_x, 0, 0, $scale_y, $x1 * (1 - $scale_x), $y2 * (1 - $scale_y))); // handle pc/unix/mac line endings $lines = preg_split('/[\r\n]+/si', $data, -1, PREG_SPLIT_NO_EMPTY); $u=0; @@ -15193,7 +15278,7 @@ class TCPDF { break; } case 'N':{ - $this->SetY($this->img_rb_y); + $this->setY($this->img_rb_y); break; } default:{ @@ -15205,7 +15290,7 @@ class TCPDF { /** * Set document barcode. - * @param $bc (string) barcode + * @param string $bc barcode * @public */ public function setBarcode($bc='') { @@ -15224,14 +15309,14 @@ class TCPDF { /** * Print a Linear Barcode. - * @param $code (string) code to print - * @param $type (string) type of barcode (see tcpdf_barcodes_1d.php for supported formats). - * @param $x (int) x position in user units (empty string = current x position) - * @param $y (int) y position in user units (empty string = current y position) - * @param $w (int) width in user units (empty string = remaining page width) - * @param $h (int) height in user units (empty string = remaining page height) - * @param $xres (float) width of the smallest bar in user units (empty string = default value = 0.4mm) - * @param $style (array) array of options:
                + * @param string $code code to print + * @param string $type type of barcode (see tcpdf_barcodes_1d.php for supported formats). + * @param float|null $x x position in user units (null = current x position) + * @param float|null $y y position in user units (null = current y position) + * @param float|null $w width in user units (null = remaining page width) + * @param float|null $h height in user units (null = remaining page height) + * @param float|null $xres width of the smallest bar in user units (null = default value = 0.4mm) + * @param array $style array of options:
                  *
                • boolean $style['border'] if true prints a border
                • *
                • int $style['padding'] padding to leave around the barcode in user units (set to 'auto' for automatic padding)
                • *
                • int $style['hpadding'] horizontal padding in user units (set to 'auto' for automatic padding)
                • @@ -15247,12 +15332,12 @@ class TCPDF { *
                • string $style['stretch'] if true stretch the barcode to best fit the available width, otherwise uses $xres resolution for a single bar.
                • *
                • string $style['fitwidth'] if true reduce the width to fit the barcode width + padding. When this option is enabled the 'stretch' option is automatically disabled.
                • *
                • string $style['cellfitalign'] this option works only when 'fitwidth' is true and 'position' is unset or empty. Set the horizontal position of the containing barcode cell inside the specified rectangle: L = left; C = center; R = right.
                - * @param $align (string) Indicates the alignment of the pointer next to barcode insertion relative to barcode height. The value can be:
                • T: top-right for LTR or top-left for RTL
                • M: middle-right for LTR or middle-left for RTL
                • B: bottom-right for LTR or bottom-left for RTL
                • N: next line
                + * @param string $align Indicates the alignment of the pointer next to barcode insertion relative to barcode height. The value can be:
                • T: top-right for LTR or top-left for RTL
                • M: middle-right for LTR or middle-left for RTL
                • B: bottom-right for LTR or bottom-left for RTL
                • N: next line
                * @author Nicola Asuni * @since 3.1.000 (2008-06-09) * @public */ - public function write1DBarcode($code, $type, $x='', $y='', $w='', $h='', $xres='', $style=array(), $align='') { + public function write1DBarcode($code, $type, $x=null, $y=null, $w=null, $h=null, $xres=null, $style=array(), $align='') { if (TCPDF_STATIC::empty_string(trim($code))) { return; } @@ -15262,7 +15347,7 @@ class TCPDF { // create new barcode object $barcodeobj = new TCPDFBarcode($code, $type); $arrcode = $barcodeobj->getBarcodeArray(); - if (($arrcode === false) OR empty($arrcode) OR ($arrcode['maxw'] <= 0)) { + if (empty($arrcode) OR ($arrcode['maxw'] <= 0)) { $this->Error('Error in 1D barcode string'); } if ($arrcode['maxh'] <= 0) { @@ -15311,20 +15396,20 @@ class TCPDF { if (isset($style['fontsize'])) { $fontsize = $style['fontsize']; } - $this->SetFont($style['font'], '', $fontsize); + $this->setFont($style['font'], '', $fontsize); } if (!isset($style['stretchtext'])) { $style['stretchtext'] = 4; } - if ($x === '') { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if ($y === '') { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } // check page for no-write regions and adapt page margins if necessary list($x, $y) = $this->checkPageRegions($h, $x, $y); - if (($w === '') OR ($w <= 0)) { + if (TCPDF_STATIC::empty_string($w) OR ($w <= 0)) { if ($this->rtl) { $w = $x - $this->lMargin; } else { @@ -15408,7 +15493,7 @@ class TCPDF { } $text_height = $this->getCellHeight($fontsize / $this->k); // height - if (($h === '') OR ($h <= 0)) { + if (TCPDF_STATIC::empty_string($h) OR ($h <= 0)) { // set default height $h = (($arrcode['maxw'] * $xres) / 3) + (2 * $vpadding) + $text_height; } @@ -15418,7 +15503,7 @@ class TCPDF { if ($text_height > $h) { $fontsize = (($h * $this->k) / (4 * $this->cell_height_ratio)); $text_height = $this->getCellHeight($fontsize / $this->k); - $this->SetFont($style['font'], '', $fontsize); + $this->setFont($style['font'], '', $fontsize); } if ($vpadding > 0) { $vpadding = (($h - $text_height) / 4); @@ -15483,8 +15568,8 @@ class TCPDF { $this->Rect($xpos_rect, $y, $w, $h, 'D'); } // set foreground color - $this->SetDrawColorArray($style['fgcolor']); - $this->SetTextColorArray($style['fgcolor']); + $this->setDrawColorArray($style['fgcolor']); + $this->setTextColorArray($style['fgcolor']); // print bars foreach ($arrcode['bcode'] as $k => $v) { $bw = ($v['w'] * $xres); @@ -15510,8 +15595,8 @@ class TCPDF { $this->x = $xpos_text; $this->y = $y + $vpadding + $barh; $cellpadding = $this->cell_padding; - $this->SetCellPadding(0); - $this->Cell($txtwidth, '', $label, 0, 0, 'C', false, '', $style['stretchtext'], false, 'T', 'T'); + $this->setCellPadding(0); + $this->Cell($txtwidth, 0, $label, 0, 0, 'C', false, '', $style['stretchtext'], false, 'T', 'T'); $this->cell_padding = $cellpadding; } // restore original direction @@ -15536,7 +15621,7 @@ class TCPDF { break; } case 'N':{ - $this->SetY($this->img_rb_y); + $this->setY($this->img_rb_y); break; } default:{ @@ -15548,13 +15633,13 @@ class TCPDF { /** * Print 2D Barcode. - * @param $code (string) code to print - * @param $type (string) type of barcode (see tcpdf_barcodes_2d.php for supported formats). - * @param $x (int) x position in user units - * @param $y (int) y position in user units - * @param $w (int) width in user units - * @param $h (int) height in user units - * @param $style (array) array of options:
                  + * @param string $code code to print + * @param string $type type of barcode (see tcpdf_barcodes_2d.php for supported formats). + * @param float|null $x x position in user units + * @param float|null $y y position in user units + * @param float|null $w width in user units + * @param float|null $h height in user units + * @param array $style array of options:
                    *
                  • boolean $style['border'] if true prints a border around the barcode
                  • *
                  • int $style['padding'] padding to leave around the barcode in barcode units (set to 'auto' for automatic padding)
                  • *
                  • int $style['hpadding'] horizontal padding in barcode units (set to 'auto' for automatic padding)
                  • @@ -15564,13 +15649,13 @@ class TCPDF { *
                  • array $style['fgcolor'] color array for bars and text
                  • *
                  • mixed $style['bgcolor'] color array for background or false for transparent
                  • *
                  • string $style['position'] barcode position on the page: L = left margin; C = center; R = right margin; S = stretch
                  • - * @param $align (string) Indicates the alignment of the pointer next to barcode insertion relative to barcode height. The value can be:
                    • T: top-right for LTR or top-left for RTL
                    • M: middle-right for LTR or middle-left for RTL
                    • B: bottom-right for LTR or bottom-left for RTL
                    • N: next line
                    - * @param $distort (boolean) if true distort the barcode to fit width and height, otherwise preserve aspect ratio + * @param string $align Indicates the alignment of the pointer next to barcode insertion relative to barcode height. The value can be:
                    • T: top-right for LTR or top-left for RTL
                    • M: middle-right for LTR or middle-left for RTL
                    • B: bottom-right for LTR or bottom-left for RTL
                    • N: next line
                    + * @param boolean $distort if true distort the barcode to fit width and height, otherwise preserve aspect ratio * @author Nicola Asuni * @since 4.5.037 (2009-04-07) * @public */ - public function write2DBarcode($code, $type, $x='', $y='', $w='', $h='', $style=array(), $align='', $distort=false) { + public function write2DBarcode($code, $type, $x=null, $y=null, $w=null, $h=null, $style=array(), $align='', $distort=false) { if (TCPDF_STATIC::empty_string(trim($code))) { return; } @@ -15580,7 +15665,7 @@ class TCPDF { // create new barcode object $barcodeobj = new TCPDF2DBarcode($code, $type); $arrcode = $barcodeobj->getBarcodeArray(); - if (($arrcode === false) OR empty($arrcode) OR !isset($arrcode['num_rows']) OR ($arrcode['num_rows'] == 0) OR !isset($arrcode['num_cols']) OR ($arrcode['num_cols'] == 0)) { + if (empty($arrcode) OR !isset($arrcode['num_rows']) OR ($arrcode['num_rows'] == 0) OR !isset($arrcode['num_cols']) OR ($arrcode['num_cols'] == 0)) { $this->Error('Error in 2D barcode string'); } // set default values @@ -15621,10 +15706,10 @@ class TCPDF { if (!isset($style['module_height'])) { $style['module_height'] = 1; // height of a single module in points } - if ($x === '') { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if ($y === '') { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } // check page for no-write regions and adapt page margins if necessary @@ -15666,7 +15751,7 @@ class TCPDF { $h = $maxh; } // set dimensions - if ((($w === '') OR ($w <= 0)) AND (($h === '') OR ($h <= 0))) { + if ((TCPDF_STATIC::empty_string($w) OR ($w <= 0)) AND (TCPDF_STATIC::empty_string($h) OR ($h <= 0))) { $w = ($cols + $hpad) * ($mw / $this->k); $h = ($rows + $vpad) * ($mh / $this->k); } elseif (($w === '') OR ($w <= 0)) { @@ -15733,7 +15818,7 @@ class TCPDF { $this->Rect($xpos, $y, $w, $h, 'D'); } // set foreground color - $this->SetDrawColorArray($style['fgcolor']); + $this->setDrawColorArray($style['fgcolor']); // print barcode cells // for each row for ($r = 0; $r < $rows; ++$r) { @@ -15770,7 +15855,7 @@ class TCPDF { break; } case 'N':{ - $this->SetY($this->img_rb_y); + $this->setY($this->img_rb_y); break; } default:{ @@ -15836,7 +15921,7 @@ class TCPDF { /** * Returns the current font size. - * @return current font size + * @return float current font size * @public * @since 3.2.000 (2008-06-23) */ @@ -15846,7 +15931,7 @@ class TCPDF { /** * Returns the current font size in points unit. - * @return current font size in points unit + * @return int current font size in points unit * @public * @since 3.2.000 (2008-06-23) */ @@ -15876,23 +15961,23 @@ class TCPDF { /** * Cleanup HTML code (requires HTML Tidy library). - * @param $html (string) htmlcode to fix - * @param $default_css (string) CSS commands to add - * @param $tagvs (array) parameters for setHtmlVSpace method - * @param $tidy_options (array) options for tidy_parse_string function + * @param string $html htmlcode to fix + * @param string $default_css CSS commands to add + * @param array|null $tagvs parameters for setHtmlVSpace method + * @param array|null $tidy_options options for tidy_parse_string function * @return string XHTML code cleaned up * @author Nicola Asuni * @public * @since 5.9.017 (2010-11-16) * @see setHtmlVSpace() */ - public function fixHTMLCode($html, $default_css='', $tagvs='', $tidy_options='') { + public function fixHTMLCode($html, $default_css='', $tagvs=null, $tidy_options=null) { return TCPDF_STATIC::fixHTMLCode($html, $default_css, $tagvs, $tidy_options, $this->tagvspaces); } /** * Returns the border width from CSS property - * @param $width (string) border width + * @param string $width border width * @return int with in user units * @protected * @since 5.7.000 (2010-08-02) @@ -15912,7 +15997,7 @@ class TCPDF { /** * Returns the border dash style from CSS property - * @param $style (string) border style to convert + * @param string $style border style to convert * @return int sash style (return -1 in case of none or hidden border) * @protected * @since 5.7.000 (2010-08-02) @@ -15948,21 +16033,21 @@ class TCPDF { /** * Returns the border style array from CSS border properties - * @param $cssborder (string) border properties + * @param string $cssborder border properties * @return array containing border properties * @protected * @since 5.7.000 (2010-08-02) */ protected function getCSSBorderStyle($cssborder) { $bprop = preg_split('/[\s]+/', trim($cssborder)); + $count = count($bprop); + if ($count > 0 && $bprop[$count - 1] === '!important') { + unset($bprop[$count - 1]); + --$count; + } + $border = array(); // value to be returned - switch (count($bprop)) { - case 3: { - $width = $bprop[0]; - $style = $bprop[1]; - $color = $bprop[2]; - break; - } + switch ($count) { case 2: { $width = 'medium'; $style = $bprop[0]; @@ -15975,12 +16060,18 @@ class TCPDF { $color = 'black'; break; } - default: { + case 0: { $width = 'medium'; $style = 'solid'; $color = 'black'; break; } + default: { + $width = $bprop[0]; + $style = $bprop[1]; + $color = $bprop[2]; + break; + } } if ($style == 'none') { return array(); @@ -15998,8 +16089,8 @@ class TCPDF { /** * Get the internal Cell padding from CSS attribute. - * @param $csspadding (string) padding properties - * @param $width (float) width of the containing element + * @param string $csspadding padding properties + * @param float $width width of the containing element * @return array of cell paddings * @public * @since 5.9.000 (2010-10-04) @@ -16052,8 +16143,8 @@ class TCPDF { /** * Get the internal Cell margin from CSS attribute. - * @param $cssmargin (string) margin properties - * @param $width (float) width of the containing element + * @param string $cssmargin margin properties + * @param float $width width of the containing element * @return array of cell margins * @public * @since 5.9.000 (2010-10-04) @@ -16106,8 +16197,8 @@ class TCPDF { /** * Get the border-spacing from CSS attribute. - * @param $cssbspace (string) border-spacing CSS properties - * @param $width (float) width of the containing element + * @param string $cssbspace border-spacing CSS properties + * @param float $width width of the containing element * @return array of border spacings * @public * @since 5.9.010 (2010-10-27) @@ -16140,8 +16231,8 @@ class TCPDF { /** * Returns the letter-spacing value from CSS value - * @param $spacing (string) letter-spacing value - * @param $parent (float) font spacing (tracking) value of the parent element + * @param string $spacing letter-spacing value + * @param float $parent font spacing (tracking) value of the parent element * @return float quantity to increases or decreases the space between characters in a text. * @protected * @since 5.9.000 (2010-10-02) @@ -16171,8 +16262,8 @@ class TCPDF { /** * Returns the percentage of font stretching from CSS value - * @param $stretch (string) stretch mode - * @param $parent (float) stretch value of the parent element + * @param string $stretch stretch mode + * @param float $parent stretch value of the parent element * @return float font stretching percentage * @protected * @since 5.9.000 (2010-10-02) @@ -16242,10 +16333,10 @@ class TCPDF { /** * Convert HTML string containing font size value to points - * @param $val (string) String containing font size value and unit. - * @param $refsize (float) Reference font size in points. - * @param $parent_size (float) Parent font size in points. - * @param $defaultunit (string) Default unit (can be one of the following: %, em, ex, px, in, mm, pc, pt). + * @param string $val String containing font size value and unit. + * @param float $refsize Reference font size in points. + * @param float $parent_size Parent font size in points. + * @param string $defaultunit Default unit (can be one of the following: %, em, ex, px, in, mm, pc, pt). * @return float value in points * @public */ @@ -16290,6 +16381,7 @@ class TCPDF { break; } default: { + $parentSize = $this->getHTMLUnitToUnits($parent_size, $refsize, $defaultunit, true); $size = $this->getHTMLUnitToUnits($val, $parent_size, $defaultunit, true); } } @@ -16298,25 +16390,72 @@ class TCPDF { /** * Returns the HTML DOM array. - * @param $html (string) html code + * @param string $html html code * @return array * @protected * @since 3.2.000 (2008-06-20) */ protected function getHtmlDomArray($html) { + // set inheritable properties fot the first void element + // possible inheritable properties are: azimuth, border-collapse, border-spacing, caption-side, color, cursor, direction, empty-cells, font, font-family, font-stretch, font-size, font-size-adjust, font-style, font-variant, font-weight, letter-spacing, line-height, list-style, list-style-image, list-style-position, list-style-type, orphans, page, page-break-inside, quotes, speak, speak-header, text-align, text-indent, text-transform, volume, white-space, widows, word-spacing + $dom = array( + array( + 'tag' => false, + 'block' => false, + 'value' => '', + 'parent' => 0, + 'hide' => false, + 'fontname' => $this->FontFamily, + 'fontstyle' => $this->FontStyle, + 'fontsize' => $this->FontSizePt, + 'font-stretch' => $this->font_stretching, + 'letter-spacing' => $this->font_spacing, + 'stroke' => $this->textstrokewidth, + 'fill' => (($this->textrendermode % 2) == 0), + 'clip' => ($this->textrendermode > 3), + 'line-height' => $this->cell_height_ratio, + 'bgcolor' => false, + 'fgcolor' => $this->fgcolor, // color + 'strokecolor' => $this->strokecolor, + 'align' => '', + 'listtype' => '', + 'text-indent' => 0, + 'text-transform' => '', + 'border' => array(), + 'dir' => $this->rtl?'rtl':'ltr', + 'width' => 0, + 'height' => 0, + 'x' => 0, + 'y' => 0, + 'w' => 0, + 'h' => 0, + 'l' => 0, + 't' => 0, + 'r' => 0, + 'b' => 0, + 'padding' => array('T' => 0, 'R' => 0, 'B' => 0, 'L' => 0), + 'margin' => array('T' => 0, 'R' => 0, 'B' => 0, 'L' => 0), + 'border-spacing' => array('H' => 0, 'V' => 0), + 'border-collapse' => 'separate', + ) + ); + + if($html === '' || $html === null) { + return $dom; + } // array of CSS styles ( selector => properties). $css = array(); // get CSS array defined at previous call $matches = array(); - if (preg_match_all('/([^\<]*)<\/cssarray>/isU', $html, $matches) > 0) { + if (preg_match_all('/([^\<]*?)<\/cssarray>/is', $html, $matches) > 0) { if (isset($matches[1][0])) { $css = array_merge($css, json_decode($this->unhtmlentities($matches[1][0]), true)); } - $html = preg_replace('/(.*?)<\/cssarray>/isU', '', $html); + $html = preg_replace('/(.*?)<\/cssarray>/is', '', $html); } // extract external CSS files $matches = array(); - if (preg_match_all('/]*)>/isU', $html, $matches) > 0) { + if (preg_match_all('/]*?)>/is', $html, $matches) > 0) { foreach ($matches[1] as $key => $link) { $type = array(); if (preg_match('/type[\s]*=[\s]*"text\/css"/', $link, $type)) { @@ -16328,7 +16467,7 @@ class TCPDF { $type = array(); if (preg_match('/href[\s]*=[\s]*"([^"]*)"/', $link, $type) > 0) { // read CSS data file - $cssdata = TCPDF_STATIC::fileGetContents(trim($type[1])); + $cssdata = $this->getCachedFileContents(trim($type[1])); if (($cssdata !== FALSE) AND (strlen($cssdata) > 0)) { $css = array_merge($css, TCPDF_STATIC::extractCSSproperties($cssdata)); } @@ -16339,7 +16478,7 @@ class TCPDF { } // extract style tags $matches = array(); - if (preg_match_all('/]*)>([^\<]*)<\/style>/isU', $html, $matches) > 0) { + if (preg_match_all('/]*?)>([^\<]*?)<\/style>/is', $html, $matches) > 0) { foreach ($matches[1] as $key => $media) { $type = array(); preg_match('/media[\s]*=[\s]*"([^"]*)"/', $media, $type); @@ -16354,8 +16493,8 @@ class TCPDF { // create a special tag to contain the CSS array (used for table content) $csstagarray = ''.htmlentities(json_encode($css)).''; // remove head and style blocks - $html = preg_replace('/]*)>(.*?)<\/head>/siU', '', $html); - $html = preg_replace('/]*)>([^\<]*)<\/style>/isU', '', $html); + $html = preg_replace('/]*?)>(.*?)<\/head>/is', '', $html); + $html = preg_replace('/]*?)>([^\<]*?)<\/style>/is', '', $html); // define block tags $blocktags = array('blockquote','br','dd','dl','div','dt','h1','h2','h3','h4','h5','h6','hr','li','ol','p','pre','ul','tcpdf','table','tr','td'); // define self-closing tags @@ -16448,37 +16587,8 @@ class TCPDF { // count elements $maxel = count($a); $elkey = 0; - $key = 0; - // create an array of elements - $dom = array(); - $dom[$key] = array(); - // set inheritable properties fot the first void element - // possible inheritable properties are: azimuth, border-collapse, border-spacing, caption-side, color, cursor, direction, empty-cells, font, font-family, font-stretch, font-size, font-size-adjust, font-style, font-variant, font-weight, letter-spacing, line-height, list-style, list-style-image, list-style-position, list-style-type, orphans, page, page-break-inside, quotes, speak, speak-header, text-align, text-indent, text-transform, volume, white-space, widows, word-spacing - $dom[$key]['tag'] = false; - $dom[$key]['block'] = false; - $dom[$key]['value'] = ''; - $dom[$key]['parent'] = 0; - $dom[$key]['hide'] = false; - $dom[$key]['fontname'] = $this->FontFamily; - $dom[$key]['fontstyle'] = $this->FontStyle; - $dom[$key]['fontsize'] = $this->FontSizePt; - $dom[$key]['font-stretch'] = $this->font_stretching; - $dom[$key]['letter-spacing'] = $this->font_spacing; - $dom[$key]['stroke'] = $this->textstrokewidth; - $dom[$key]['fill'] = (($this->textrendermode % 2) == 0); - $dom[$key]['clip'] = ($this->textrendermode > 3); - $dom[$key]['line-height'] = $this->cell_height_ratio; - $dom[$key]['bgcolor'] = false; - $dom[$key]['fgcolor'] = $this->fgcolor; // color - $dom[$key]['strokecolor'] = $this->strokecolor; - $dom[$key]['align'] = ''; - $dom[$key]['listtype'] = ''; - $dom[$key]['text-indent'] = 0; - $dom[$key]['text-transform'] = ''; - $dom[$key]['border'] = array(); - $dom[$key]['dir'] = $this->rtl?'rtl':'ltr'; $thead = false; // true when we are inside the THEAD tag - ++$key; + $key = 1; $level = array(); array_push($level, 0); // root while ($elkey < $maxel) { @@ -16549,7 +16659,11 @@ class TCPDF { $dom[($dom[$key]['parent'])]['content'] = str_replace('', '', $dom[($dom[$key]['parent'])]['content']); } // store header rows on a new table - if (($dom[$key]['value'] == 'tr') AND ($dom[($dom[$key]['parent'])]['thead'] === true)) { + if ( + ($dom[$key]['value'] === 'tr') + && !empty($dom[($dom[$key]['parent'])]['thead']) + && ($dom[($dom[$key]['parent'])]['thead'] === true) + ) { if (TCPDF_STATIC::empty_string($dom[($dom[($dom[$key]['parent'])]['parent'])]['thead'])) { $dom[($dom[($dom[$key]['parent'])]['parent'])]['thead'] = $csstagarray.$a[$dom[($dom[($dom[$key]['parent'])]['parent'])]['elkey']]; } @@ -16979,10 +17093,20 @@ class TCPDF { // rows on thead block are printed as a separate table } else { $dom[$key]['thead'] = false; + $parent = $dom[$key]['parent']; + + if (!isset($dom[$parent]['rows'])) { + $dom[$parent]['rows'] = 0; + } // store the number of rows on table element - ++$dom[($dom[$key]['parent'])]['rows']; + ++$dom[$parent]['rows']; + + if (!isset($dom[$parent]['trids'])) { + $dom[$parent]['trids'] = array(); + } + // store the TR elements IDs on table element - array_push($dom[($dom[$key]['parent'])]['trids'], $key); + array_push($dom[$parent]['trids'], $key); } } if (($dom[$key]['value'] == 'th') OR ($dom[$key]['value'] == 'td')) { @@ -17075,6 +17199,7 @@ class TCPDF { } } } + $element = preg_replace("/&NBSP;/i", " ", $element); } $dom[$key]['value'] = stripslashes($this->unhtmlentities($element)); } @@ -17100,41 +17225,59 @@ class TCPDF { } /** - * Return an hash code used to ensure that the serialized data has been generated by this TCPDF instance. - * @param $data (string) serialized data - * @return string - * @public static + * Calculates the hash value of the given data. + * + * @param string $data The data to be hashed. + * @return string The hashed value of the data. */ - protected function getHashForTCPDFtagParams($data) { - return md5(strlen($data).$this->file_id.$data); + protected function hashTCPDFtag($data) { + return hash_hmac('sha256', $data, $this->hash_key, false); } /** - * Serialize an array of parameters to be used with TCPDF tag in HTML code. - * @param $data (array) parameters array - * @return string containing serialized data + * Serialize data to be used with TCPDF tag in HTML code. + * @param string $method TCPDF method name + * @param array $params Method parameters + * @return string Serialized data * @public static */ - public function serializeTCPDFtagParameters($data) { + public function serializeTCPDFtag($method, $params=array()) { + $data = array('m' => $method, 'p' => $params); $encoded = urlencode(json_encode($data)); - return $this->getHashForTCPDFtagParams($encoded).$encoded; + $hash = $this->hashTCPDFtag($encoded); + return strlen($hash).'+'.$hash.'+'.$encoded; } /** - * Unserialize parameters to be used with TCPDF tag in HTML code. - * @param $data (string) serialized data + * Unserialize data to be used with TCPDF tag in HTML code. + * @param string $data serialized data * @return array containing unserialized data * @protected static */ - protected function unserializeTCPDFtagParameters($data) { - $hash = substr($data, 0, 32); - $encoded = substr($data, 32); - if ($hash != $this->getHashForTCPDFtagParams($encoded)) { + protected function unserializeTCPDFtag($data) { + $hpos = strpos($data, '+'); + $hlen = intval(substr($data, 0, $hpos)); + $hash = substr($data, $hpos + 1, $hlen); + $encoded = substr($data, $hpos + 2 + $hlen); + if ($hash != $this->hashTCPDFtag($encoded)) { $this->Error('Invalid parameters'); } return json_decode(urldecode($encoded), true); } + /** + * Check if a TCPDF tag is allowed + * @param string $method TCPDF method name + * @return boolean + * @protected + */ + protected function allowedTCPDFtag($method) { + if (defined('K_ALLOWED_TCPDF_TAGS')) { + return (strpos(K_ALLOWED_TCPDF_TAGS, '|'.$method.'|') !== false); + } + return false; + } + /** * Prints a cell (rectangular area) with optional borders, background color and html text string. * The upper-left corner of the cell corresponds to the current position. After the call, the current position moves to the right or to the next line.
                    @@ -17142,18 +17285,17 @@ class TCPDF { * IMPORTANT: The HTML must be well formatted - try to clean-up it using an application like HTML-Tidy before submitting. * Supported tags are: a, b, blockquote, br, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, img, li, ol, p, pre, small, span, strong, sub, sup, table, tcpdf, td, th, thead, tr, tt, u, ul * NOTE: all the HTML attributes must be enclosed in double-quote. - * @param $w (float) Cell width. If 0, the cell extends up to the right margin. - * @param $h (float) Cell minimum height. The cell extends automatically if needed. - * @param $x (float) upper-left corner X coordinate - * @param $y (float) upper-left corner Y coordinate - * @param $html (string) html text to print. Default value: empty string. - * @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
                    • 0: no border (default)
                    • 1: frame
                    or a string containing some or all of the following characters (in any order):
                    • L: left
                    • T: top
                    • R: right
                    • B: bottom
                    or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) - * @param $ln (int) Indicates where the current position should go after the call. Possible values are:
                    • 0: to the right (or left for RTL language)
                    • 1: to the beginning of the next line
                    • 2: below
                    -Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. - * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false). - * @param $reseth (boolean) if true reset the last cell height (default true). - * @param $align (string) Allows to center or align the text. Possible values are:
                    • L : left align
                    • C : center
                    • R : right align
                    • '' : empty string : left for LTR or right for RTL
                    - * @param $autopadding (boolean) if true, uses internal padding and automatically adjust it to account for line width. + * @param float $w Cell width. If 0, the cell extends up to the right margin. + * @param float $h Cell minimum height. The cell extends automatically if needed. + * @param float|null $x upper-left corner X coordinate + * @param float|null $y upper-left corner Y coordinate + * @param string $html html text to print. Default value: empty string. + * @param mixed $border Indicates if borders must be drawn around the cell. The value can be a number:
                    • 0: no border (default)
                    • 1: frame
                    or a string containing some or all of the following characters (in any order):
                    • L: left
                    • T: top
                    • R: right
                    • B: bottom
                    or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) + * @param int $ln Indicates where the current position should go after the call. Possible values are:
                    • 0: to the right (or left for RTL language)
                    • 1: to the beginning of the next line
                    • 2: below
                    Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. + * @param boolean $fill Indicates if the cell background must be painted (true) or transparent (false). + * @param boolean $reseth if true reset the last cell height (default true). + * @param string $align Allows to center or align the text. Possible values are:
                    • L : left align
                    • C : center
                    • R : right align
                    • '' : empty string : left for LTR or right for RTL
                    + * @param boolean $autopadding if true, uses internal padding and automatically adjust it to account for line width. * @see Multicell(), writeHTML() * @public */ @@ -17166,12 +17308,12 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: * IMPORTANT: The HTML must be well formatted - try to clean-up it using an application like HTML-Tidy before submitting. * Supported tags are: a, b, blockquote, br, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, img, li, ol, p, pre, small, span, strong, sub, sup, table, tcpdf, td, th, thead, tr, tt, u, ul * NOTE: all the HTML attributes must be enclosed in double-quote. - * @param $html (string) text to display - * @param $ln (boolean) if true add a new line after text (default = true) - * @param $fill (boolean) Indicates if the background must be painted (true) or transparent (false). - * @param $reseth (boolean) if true reset the last cell height (default false). - * @param $cell (boolean) if true add the current left (or right for RTL) padding to each Write (default false). - * @param $align (string) Allows to center or align the text. Possible values are:
                    • L : left align
                    • C : center
                    • R : right align
                    • '' : empty string : left for LTR or right for RTL
                    + * @param string $html text to display + * @param boolean $ln if true add a new line after text (default = true) + * @param boolean $fill Indicates if the background must be painted (true) or transparent (false). + * @param boolean $reseth if true reset the last cell height (default false). + * @param boolean $cell if true add the current left (or right for RTL) padding to each Write (default false). + * @param string $align Allows to center or align the text. Possible values are:
                    • L : left align
                    • C : center
                    • R : right align
                    • '' : empty string : left for LTR or right for RTL
                    * @public */ public function writeHTML($html, $ln=true, $fill=false, $reseth=false, $cell=false, $align='') { @@ -17282,6 +17424,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: ++$key; } } + if ($key == $maxel) break; if ($dom[$key]['tag'] AND isset($dom[$key]['attribute']['pagebreak'])) { // check for pagebreak if (($dom[$key]['attribute']['pagebreak'] == 'true') OR ($dom[$key]['attribute']['pagebreak'] == 'left') OR ($dom[$key]['attribute']['pagebreak'] == 'right')) { @@ -17561,7 +17704,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->cell_height_ratio = $dom[$key]['line-height']; $fontaligned = true; } - $this->SetFont($fontname, $fontstyle, $fontsize); + $this->setFont($fontname, $fontstyle, $fontsize); // reset row height $this->resetLastH(); $curfontname = $fontname; @@ -17588,16 +17731,16 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: // get current position on page buffer $curpos = $this->pagelen[$startlinepage]; if (isset($dom[$key]['bgcolor']) AND ($dom[$key]['bgcolor'] !== false)) { - $this->SetFillColorArray($dom[$key]['bgcolor']); + $this->setFillColorArray($dom[$key]['bgcolor']); $wfill = true; } else { $wfill = $fill | false; } if (isset($dom[$key]['fgcolor']) AND ($dom[$key]['fgcolor'] !== false)) { - $this->SetTextColorArray($dom[$key]['fgcolor']); + $this->setTextColorArray($dom[$key]['fgcolor']); } if (isset($dom[$key]['strokecolor']) AND ($dom[$key]['strokecolor'] !== false)) { - $this->SetDrawColorArray($dom[$key]['strokecolor']); + $this->setDrawColorArray($dom[$key]['strokecolor']); } if (isset($dom[$key]['align'])) { $lalign = $dom[$key]['align']; @@ -17655,7 +17798,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $pend = ''; } } - if ((isset($plalign) AND ((($plalign == 'C') OR ($plalign == 'J') OR (($plalign == 'R') AND (!$this->rtl)) OR (($plalign == 'L') AND ($this->rtl)))))) { + if ((((($plalign == 'C') OR ($plalign == 'J') OR (($plalign == 'R') AND (!$this->rtl)) OR (($plalign == 'L') AND ($this->rtl)))))) { // calculate shifting amount $tw = $w; if (($plalign == 'J') AND $this->isRTLTextDir() AND ($this->num_columns > 1)) { @@ -18056,9 +18199,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if (!($dom[$key]['tag'] AND !$dom[$key]['opening'] AND ($dom[$key]['value'] == 'table') AND (isset($this->emptypagemrk[$this->page])) AND ($this->emptypagemrk[$this->page] == $this->pagelen[$this->page]))) { - $this->SetFont($fontname, $fontstyle, $fontsize); + $this->setFont($fontname, $fontstyle, $fontsize); if ($wfill) { - $this->SetFillColorArray($this->bgcolor); + $this->setFillColorArray($this->bgcolor); } } } // end newline @@ -18261,7 +18404,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $dom[$trid]['cellpos'][($cellid - 1)]['bgcolor'] = $dom[$parentid]['bgcolor']; } // store border info - if (isset($tdborder) AND !empty($tdborder)) { + if (!empty($tdborder)) { $dom[$trid]['cellpos'][($cellid - 1)]['border'] = $tdborder; } $prevLastH = $this->lasth; @@ -18358,14 +18501,14 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } elseif (strlen($dom[$key]['value']) > 0) { // print list-item if (!TCPDF_STATIC::empty_string($this->lispacer) AND ($this->lispacer != '^')) { - $this->SetFont($pfontname, $pfontstyle, $pfontsize); + $this->setFont($pfontname, $pfontstyle, $pfontsize); $this->resetLastH(); $minstartliney = $this->y; $maxbottomliney = ($startliney + $this->getCellHeight($this->FontSize)); if (is_numeric($pfontsize) AND ($pfontsize > 0)) { $this->putHtmlListBullet($this->listnum, $this->lispacer, $pfontsize); } - $this->SetFont($curfontname, $curfontstyle, $curfontsize); + $this->setFont($curfontname, $curfontstyle, $curfontsize); $this->resetLastH(); if (is_numeric($pfontsize) AND ($pfontsize > 0) AND is_numeric($curfontsize) AND ($curfontsize > 0) AND ($pfontsize != $curfontsize)) { $pfontascent = $this->getFontAscent($pfontname, $pfontstyle, $pfontsize); @@ -18497,7 +18640,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $strrest = $this->Write($this->lasth, $dom[$key]['value'], '', $wfill, '', false, 0, true, $firstblock, 0, $wadj); // restore default direction if ($reverse_dir AND ($wadj == 0)) { - $this->x = $xws; + $this->x = $xws; // @phpstan-ignore-line $this->rtl = !$this->rtl; $reverse_dir = false; } @@ -18606,7 +18749,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $pend = ''; } } - if ((isset($plalign) AND ((($plalign == 'C') OR (($plalign == 'R') AND (!$this->rtl)) OR (($plalign == 'L') AND ($this->rtl)))))) { + if ((((($plalign == 'C') OR (($plalign == 'R') AND (!$this->rtl)) OR (($plalign == 'L') AND ($this->rtl)))))) { // calculate shifting amount $tw = $w; if ($this->lMargin != $prevlMargin) { @@ -18726,10 +18869,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Process opening tags. - * @param $dom (array) html dom array - * @param $key (int) current element id - * @param $cell (boolean) if true add the default left (or right if RTL) padding to each new line (default false). - * @return $dom array + * @param array $dom html dom array + * @param int $key current element id + * @param boolean $cell if true add the default left (or right if RTL) padding to each new line (default false). + * @return array $dom * @protected */ protected function openHTMLTagHandler($dom, $key, $cell) { @@ -18823,7 +18966,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $dom[$key]['old_cell_padding'] = $this->cell_padding; if (isset($tag['attribute']['cellpadding'])) { $pad = $this->getHTMLUnitToUnits($tag['attribute']['cellpadding'], 1, 'px'); - $this->SetCellPadding($pad); + $this->setCellPadding($pad); } elseif (isset($tag['padding'])) { $this->cell_padding = $tag['padding']; } @@ -18864,9 +19007,37 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $hrWidth = $wtmp; } $prevlinewidth = $this->GetLineWidth(); - $this->SetLineWidth($hrHeight); - $this->Line($x, $y, $x + $hrWidth, $y); - $this->SetLineWidth($prevlinewidth); + $this->setLineWidth($hrHeight); + + $lineStyle = array(); + if (isset($tag['fgcolor'])) { + $lineStyle['color'] = $tag['fgcolor']; + } + + if (isset($tag['fgcolor'])) { + $lineStyle['color'] = $tag['fgcolor']; + } + + if (isset($tag['style']['cap'])) { + $lineStyle['cap'] = $tag['style']['cap']; + } + + if (isset($tag['style']['join'])) { + $lineStyle['join'] = $tag['style']['join']; + } + + if (isset($tag['style']['dash'])) { + $lineStyle['dash'] = $tag['style']['dash']; + } + + if (isset($tag['style']['phase'])) { + $lineStyle['phase'] = $tag['style']['phase']; + } + + $lineStyle = array_filter($lineStyle); + + $this->Line($x, $y, $x + $hrWidth, $y, $lineStyle); + $this->setLineWidth($prevlinewidth); $this->addHTMLVertSpace(max($hbc, ($hrHeight / 2)), 0, $cell, !isset($dom[($key + 1)])); break; } @@ -18884,7 +19055,17 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if ($imgsrc[0] === '@') { // data stream $imgsrc = '@'.base64_decode(substr($imgsrc, 1)); - $type = ''; + $type = preg_match('/]*[^>]*>.*<\/svg>/is', $imgsrc) ? 'svg' : ''; + } else if (preg_match('@^data:image/([^;]*);base64,(.*)@', $imgsrc, $reg)) { + $imgsrc = '@'.base64_decode($reg[2]); + $type = $reg[1]; + } elseif (strpos($imgsrc, '../') !== false) { + // accessing parent folders is not allowed + break; + } elseif ( $this->allowLocalFiles && substr($imgsrc, 0, 7) === 'file://') { + // get image type from a local file path + $imgsrc = substr($imgsrc, 7); + $type = TCPDF_IMAGES::getImageFileType($imgsrc); } else { if (($imgsrc[0] === '/') AND !empty($_SERVER['DOCUMENT_ROOT']) AND ($_SERVER['DOCUMENT_ROOT'] != '/')) { // fix image path @@ -18957,7 +19138,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $lnky = 0; } $imglink = $this->AddLink(); - $this->SetLink($imglink, $lnky, $page); + $this->setLink($imglink, $lnky, $page); } } } @@ -19111,11 +19292,11 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } case 'sup': { - $this->SetXY($this->GetX(), $this->GetY() - ((0.7 * $this->FontSizePt) / $this->k)); + $this->setXY($this->GetX(), $this->GetY() - ((0.7 * $this->FontSizePt) / $this->k)); break; } case 'sub': { - $this->SetXY($this->GetX(), $this->GetY() + ((0.3 * $this->FontSizePt) / $this->k)); + $this->setXY($this->GetX(), $this->GetY() + ((0.3 * $this->FontSizePt) / $this->k)); break; } case 'h1': @@ -19374,17 +19555,14 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: case 'tcpdf': { if (defined('K_TCPDF_CALLS_IN_HTML') AND (K_TCPDF_CALLS_IN_HTML === true)) { // Special tag used to call TCPDF methods - if (isset($tag['attribute']['method'])) { - $tcpdf_method = $tag['attribute']['method']; - if (method_exists($this, $tcpdf_method)) { - if (isset($tag['attribute']['params']) AND (!empty($tag['attribute']['params']))) { - $params = $this->unserializeTCPDFtagParameters($tag['attribute']['params']); - call_user_func_array(array($this, $tcpdf_method), $params); - } else { - $this->$tcpdf_method(); - } - $this->newline = true; + // This tag is disabled by default by the K_TCPDF_CALLS_IN_HTML constant on TCPDF configuration file. + // Please use this feature only if you are in control of the HTML content and you are sure that it does not contain any harmful code. + if (!empty($tag['attribute']['data'])) { + $tcpdf_tag_data = $this->unserializeTCPDFtag($tag['attribute']['data']); + if ($this->allowedTCPDFtag($tcpdf_tag_data['m'])) { + call_user_func_array(array($this, $tcpdf_tag_data['m']), $tcpdf_tag_data['p']); } + $this->newline = true; } } break; @@ -19417,11 +19595,11 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Process closing tags. - * @param $dom (array) html dom array - * @param $key (int) current element id - * @param $cell (boolean) if true add the default left (or right if RTL) padding to each new line (default false). - * @param $maxbottomliney (int) maximum y value of current line - * @return $dom array + * @param array $dom html dom array + * @param int $key current element id + * @param boolean $cell if true add the default left (or right if RTL) padding to each new line (default false). + * @param int $maxbottomliney maximum y value of current line + * @return array $dom * @protected */ protected function closeHTMLTagHandler($dom, $key, $cell, $maxbottomliney=0) { @@ -19594,7 +19772,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $table_el = $dom[($dom[$key]['parent'])]; } // for each row - if (count($table_el['trids']) > 0) { + if (!empty($table_el['trids'])) { unset($xmax); } foreach ($table_el['trids'] as $j => $trkey) { @@ -19626,7 +19804,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $border = $cellpos['border']; } if (isset($cellpos['bgcolor']) AND ($cellpos['bgcolor']) !== false) { - $this->SetFillColorArray($cellpos['bgcolor']); + $this->setFillColorArray($cellpos['bgcolor']); $fill = true; } else { $fill = false; @@ -19807,7 +19985,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } } if (!$in_table_head) { // we are not inside a thead section - $this->cell_padding = $table_el['old_cell_padding']; + $this->cell_padding = isset($table_el['old_cell_padding']) ? $table_el['old_cell_padding'] : null; // reset row height $this->resetLastH(); if (($this->page == ($this->numpages - 1)) AND ($this->pageopen[$this->numpages])) { @@ -19843,11 +20021,11 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } case 'sup': { - $this->SetXY($this->GetX(), $this->GetY() + ((0.7 * $parent['fontsize']) / $this->k)); + $this->setXY($this->GetX(), $this->GetY() + ((0.7 * $parent['fontsize']) / $this->k)); break; } case 'sub': { - $this->SetXY($this->GetX(), $this->GetY() - ((0.3 * $parent['fontsize']) / $this->k)); + $this->setXY($this->GetX(), $this->GetY() - ((0.3 * $parent['fontsize']) / $this->k)); break; } case 'div': { @@ -19964,11 +20142,11 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Add vertical spaces if needed. - * @param $hbz (string) Distance between current y and line bottom. - * @param $hb (string) The height of the break. - * @param $cell (boolean) if true add the default left (or right if RTL) padding to each new line (default false). - * @param $firsttag (boolean) set to true when the tag is the first. - * @param $lasttag (boolean) set to true when the tag is the last. + * @param string $hbz Distance between current y and line bottom. + * @param string $hb The height of the break. + * @param boolean $cell if true add the default left (or right if RTL) padding to each new line (default false). + * @param boolean $firsttag set to true when the tag is the first. + * @param boolean $lasttag set to true when the tag is the last. * @protected */ protected function addHTMLVertSpace($hbz=0, $hb=0, $cell=false, $firsttag=false, $lasttag=false) { @@ -20008,8 +20186,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Draw an HTML block border and fill - * @param $tag (array) array of tag properties. - * @param $xmax (int) end X coordinate for border. + * @param array $tag array of tag properties. + * @param int $xmax end X coordinate for border. * @protected * @since 5.7.000 (2010-08-03) */ @@ -20035,7 +20213,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if (isset($tag['bgcolor']) AND ($tag['bgcolor'] !== false)) { // get background color $old_bgcolor = $this->bgcolor; - $this->SetFillColorArray($tag['bgcolor']); + $this->setFillColorArray($tag['bgcolor']); $fill = true; } if (!$border AND !$fill) { @@ -20201,7 +20379,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->page_regions = $temp_page_regions; if (isset($old_bgcolor)) { // restore background color - $this->SetFillColorArray($old_bgcolor); + $this->setFillColorArray($old_bgcolor); } // restore pointer position $this->x = $prev_x; @@ -20211,7 +20389,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set the default bullet to be used as LI bullet symbol - * @param $symbol (string) character or string to be used (legal values are: '' = automatic, '!' = auto bullet, '#' = auto numbering, 'disc', 'disc', 'circle', 'square', '1', 'decimal', 'decimal-leading-zero', 'i', 'lower-roman', 'I', 'upper-roman', 'a', 'lower-alpha', 'lower-latin', 'A', 'upper-alpha', 'upper-latin', 'lower-greek', 'img|type|width|height|image.ext') + * @param string $symbol character or string to be used (legal values are: '' = automatic, '!' = auto bullet, '#' = auto numbering, 'disc', 'disc', 'circle', 'square', '1', 'decimal', 'decimal-leading-zero', 'i', 'lower-roman', 'I', 'upper-roman', 'a', 'lower-alpha', 'lower-latin', 'A', 'upper-alpha', 'upper-latin', 'lower-greek', 'img|type|width|height|image.ext') * @public * @since 4.0.028 (2008-09-26) */ @@ -20232,13 +20410,13 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set the booklet mode for double-sided pages. - * @param $booklet (boolean) true set the booklet mode on, false otherwise. - * @param $inner (float) Inner page margin. - * @param $outer (float) Outer page margin. + * @param boolean $booklet true set the booklet mode on, false otherwise. + * @param float $inner Inner page margin. + * @param float $outer Outer page margin. * @public * @since 4.2.000 (2008-10-29) */ - public function SetBooklet($booklet=true, $inner=-1, $outer=-1) { + public function setBooklet($booklet=true, $inner=-1, $outer=-1) { $this->booklet = $booklet; if ($inner >= 0) { $this->lMargin = $inner; @@ -20250,7 +20428,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Swap the left and right margins. - * @param $reverse (boolean) if true swap left and right margins. + * @param boolean $reverse if true swap left and right margins. * @protected * @since 4.2.000 (2008-10-29) */ @@ -20274,7 +20452,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: * the second level contains 0 for opening tags or 1 for closing tags, * the third level contains the vertical space unit (h) and the number spaces to add (n). * If the h parameter is not specified, default values are used. - * @param $tagvs (array) array of tags and relative vertical spaces. + * @param array $tagvs array of tags and relative vertical spaces. * @public * @since 4.2.001 (2008-10-30) */ @@ -20284,7 +20462,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set custom width for list indentation. - * @param $width (float) width of the indentation. Use negative value to disable it. + * @param float $width width of the indentation. Use negative value to disable it. * @public * @since 4.2.007 (2008-11-12) */ @@ -20294,7 +20472,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set the top/bottom cell sides to be open or closed when the cell cross the page. - * @param $isopen (boolean) if true keeps the top/bottom border open for the cell sides that cross the page. + * @param boolean $isopen if true keeps the top/bottom border open for the cell sides that cross the page. * @public * @since 4.2.010 (2008-11-14) */ @@ -20304,8 +20482,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set the color and font style for HTML links. - * @param $color (array) RGB array of colors - * @param $fontstyle (string) additional font styles to add + * @param array $color RGB array of colors + * @param string $fontstyle additional font styles to add * @public * @since 4.4.003 (2008-12-09) */ @@ -20316,10 +20494,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Convert HTML string containing value and unit of measure to user's units or points. - * @param $htmlval (string) String containing values and unit. - * @param $refsize (string) Reference value in points. - * @param $defaultunit (string) Default unit (can be one of the following: %, em, ex, px, in, mm, pc, pt). - * @param $points (boolean) If true returns points, otherwise returns value in user's units. + * @param string $htmlval String containing values and unit. + * @param string $refsize Reference value in points. + * @param string $defaultunit Default unit (can be one of the following: %, em, ex, px, in, mm, pc, pt). + * @param boolean $points If true returns points, otherwise returns value in user's units. * @return float value in user's unit or point if $points=true * @public * @since 4.4.004 (2008-12-10) @@ -20402,9 +20580,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Output an HTML list bullet or ordered item symbol - * @param $listdepth (int) list nesting level - * @param $listtype (string) type of list - * @param $size (float) current font size + * @param int $listdepth list nesting level + * @param string $listtype type of list + * @param float $size current font size * @protected * @since 4.4.004 (2008-12-10) */ @@ -20599,9 +20777,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->x = $tmpx; $this->lispacer = '^'; // restore colors - $this->SetFillColorArray($bgcolor); - $this->SetDrawColorArray($strokecolor); - $this->SettextColorArray($color); + $this->setFillColorArray($bgcolor); + $this->setDrawColorArray($strokecolor); + $this->settextColorArray($color); } /** @@ -20666,8 +20844,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set graphic variables. - * @param $gvars (array) array of graphic variablesto restore - * @param $extended (boolean) if true restore extended graphic variables + * @param array $gvars array of graphic variablesto restore + * @param boolean $extended if true restore extended graphic variables * @protected * @since 4.2.010 (2008-11-14) */ @@ -20727,7 +20905,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } $this->_out(''.$this->linestyleWidth.' '.$this->linestyleCap.' '.$this->linestyleJoin.' '.$this->linestyleDash.' '.$this->DrawColor.' '.$this->FillColor.''); if (!TCPDF_STATIC::empty_string($this->FontFamily)) { - $this->SetFont($this->FontFamily, $this->FontStyle, $this->FontSizePt); + $this->setFont($this->FontFamily, $this->FontStyle, $this->FontSizePt); } } @@ -20749,7 +20927,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set buffer content (always append data). - * @param $data (string) data + * @param string $data data * @protected * @since 4.5.000 (2009-01-02) */ @@ -20760,7 +20938,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Replace the buffer content - * @param $data (string) data + * @param string $data data * @protected * @since 5.5.000 (2010-06-22) */ @@ -20781,9 +20959,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set page buffer content. - * @param $page (int) page number - * @param $data (string) page data - * @param $append (boolean) if true append data, false replace. + * @param int $page page number + * @param string $data page data + * @param boolean $append if true append data, false replace. * @protected * @since 4.5.000 (2008-12-31) */ @@ -20802,7 +20980,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Get page buffer content. - * @param $page (int) page number + * @param int $page page number * @return string page buffer content or false in case of error * @protected * @since 4.5.000 (2008-12-31) @@ -20816,8 +20994,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set image buffer content. - * @param $image (string) image key - * @param $data (array) image data + * @param string $image image key + * @param array $data image data * @return int image index number * @protected * @since 4.5.000 (2008-12-31) @@ -20834,9 +21012,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set image buffer content for a specified sub-key. - * @param $image (string) image key - * @param $key (string) image sub-key - * @param $data (array) image data + * @param string $image image key + * @param string $key image sub-key + * @param array $data image data * @protected * @since 4.5.000 (2008-12-31) */ @@ -20849,8 +21027,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Get image buffer content. - * @param $image (string) image key - * @return string image buffer content or false in case of error + * @param string $image image key + * @return string|false image buffer content or false in case of error * @protected * @since 4.5.000 (2008-12-31) */ @@ -20863,8 +21041,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set font buffer content. - * @param $font (string) font key - * @param $data (array) font data + * @param string $font font key + * @param array $data font data * @protected * @since 4.5.000 (2009-01-02) */ @@ -20881,9 +21059,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set font buffer content. - * @param $font (string) font key - * @param $key (string) font sub-key - * @param $data (array) font data + * @param string $font font key + * @param string $key font sub-key + * @param mixed $data font data * @protected * @since 4.5.000 (2009-01-02) */ @@ -20896,8 +21074,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Get font buffer content. - * @param $font (string) font key - * @return string font buffer content or false in case of error + * @param string $font font key + * @return string|false font buffer content or false in case of error * @protected * @since 4.5.000 (2009-01-02) */ @@ -20910,9 +21088,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Move a page to a previous position. - * @param $frompage (int) number of the source page - * @param $topage (int) number of the destination page (must be less than $frompage) - * @return true in case of success, false in case of error. + * @param int $frompage number of the source page + * @param int $topage number of the destination page (must be less than $frompage) + * @return bool true in case of success, false in case of error. * @public * @since 4.5.000 (2009-01-02) */ @@ -21082,8 +21260,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Remove the specified page. - * @param $page (int) page to remove - * @return true in case of success, false in case of error. + * @param int $page page to remove + * @return bool true in case of success, false in case of error. * @public * @since 4.6.004 (2009-04-23) */ @@ -21272,8 +21450,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Clone the specified page to a new page. - * @param $page (int) number of page to copy (0 = current page) - * @return true in case of success, false in case of error. + * @param int $page number of page to copy (0 = current page) + * @return bool true in case of success, false in case of error. * @public * @since 4.9.015 (2010-04-20) */ @@ -21343,18 +21521,18 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: * Before calling this method you have to open the page using the addTOCPage() method. * After calling this method you have to call endTOCPage() to close the TOC page. * You can override this method to achieve different styles. - * @param $page (int) page number where this TOC should be inserted (leave empty for current page). - * @param $numbersfont (string) set the font for page numbers (please use monospaced font for better alignment). - * @param $filler (string) string used to fill the space between text and page number. - * @param $toc_name (string) name to use for TOC bookmark. - * @param $style (string) Font style for title: B = Bold, I = Italic, BI = Bold + Italic. - * @param $color (array) RGB color array for bookmark title (values from 0 to 255). + * @param int|null $page page number where this TOC should be inserted (leave empty for current page). + * @param string $numbersfont set the font for page numbers (please use monospaced font for better alignment). + * @param string $filler string used to fill the space between text and page number. + * @param string $toc_name name to use for TOC bookmark. + * @param string $style Font style for title: B = Bold, I = Italic, BI = Bold + Italic. + * @param array $color RGB color array for bookmark title (values from 0 to 255). * @public * @author Nicola Asuni * @since 4.5.000 (2009-01-02) * @see addTOCPage(), endTOCPage(), addHTMLTOC() */ - public function addTOC($page='', $numbersfont='', $filler='.', $toc_name='TOC', $style='', $color=array(0,0,0)) { + public function addTOC($page=null, $numbersfont='', $filler='.', $toc_name='TOC', $style='', $color=array(0,0,0)) { $fontsize = $this->FontSizePt; $fontfamily = $this->FontFamily; $fontstyle = $this->FontStyle; @@ -21382,7 +21560,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $page = 1; } } - $this->SetFont($numbersfont, $fontstyle, $fontsize); + $this->setFont($numbersfont, $fontstyle, $fontsize); $numwidth = $this->GetStringWidth('00000'); $maxpage = 0; //used for pages on attached documents foreach ($this->outlines as $key => $outline) { @@ -21398,11 +21576,11 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $alignnum = 'R'; } if ($outline['l'] == 0) { - $this->SetFont($fontfamily, $outline['s'].'B', $fontsize); + $this->setFont($fontfamily, $outline['s'].'B', $fontsize); } else { - $this->SetFont($fontfamily, $outline['s'], $fontsize - $outline['l']); + $this->setFont($fontfamily, $outline['s'], $fontsize - $outline['l']); } - $this->SetTextColorArray($outline['c']); + $this->setTextColorArray($outline['c']); // check for page break $this->checkPageBreak(2 * $this->getCellHeight($this->FontSize)); // set margins and X position @@ -21422,7 +21600,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $current_page = $this->page; $current_column = $this->current_column; } - $this->SetX($x_start); + $this->setX($x_start); $indent = ($spacer * $outline['l']); if ($this->rtl) { $this->x -= $indent; @@ -21432,7 +21610,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $this->lMargin = $this->x; } $link = $this->AddLink(); - $this->SetLink($link, $outline['y'], $outline['p']); + $this->setLink($link, $outline['y'], $outline['p']); // write the text if ($this->rtl) { $txt = ' '.$outline['t']; @@ -21445,7 +21623,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } else { $tw = $this->w - $this->rMargin - $this->x; } - $this->SetFont($numbersfont, $fontstyle, $fontsize); + $this->setFont($numbersfont, $fontstyle, $fontsize); if (TCPDF_STATIC::empty_string($page)) { $pagenum = $outline['p']; } else { @@ -21553,18 +21731,18 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: * This method must be called after all Bookmarks were set. * Before calling this method you have to open the page using the addTOCPage() method. * After calling this method you have to call endTOCPage() to close the TOC page. - * @param $page (int) page number where this TOC should be inserted (leave empty for current page). - * @param $toc_name (string) name to use for TOC bookmark. - * @param $templates (array) array of html templates. Use: "#TOC_DESCRIPTION#" for bookmark title, "#TOC_PAGE_NUMBER#" for page number. - * @param $correct_align (boolean) if true correct the number alignment (numbers must be in monospaced font like courier and right aligned on LTR, or left aligned on RTL) - * @param $style (string) Font style for title: B = Bold, I = Italic, BI = Bold + Italic. - * @param $color (array) RGB color array for title (values from 0 to 255). + * @param int|null $page page number where this TOC should be inserted (leave empty for current page). + * @param string $toc_name name to use for TOC bookmark. + * @param array $templates array of html templates. Use: "#TOC_DESCRIPTION#" for bookmark title, "#TOC_PAGE_NUMBER#" for page number. + * @param boolean $correct_align if true correct the number alignment (numbers must be in monospaced font like courier and right aligned on LTR, or left aligned on RTL) + * @param string $style Font style for title: B = Bold, I = Italic, BI = Bold + Italic. + * @param array $color RGB color array for title (values from 0 to 255). * @public * @author Nicola Asuni * @since 5.0.001 (2010-05-06) * @see addTOCPage(), endTOCPage(), addTOC() */ - public function addHTMLTOC($page='', $toc_name='TOC', $templates=array(), $correct_align=true, $style='', $color=array(0,0,0)) { + public function addHTMLTOC($page=null, $toc_name='TOC', $templates=array(), $correct_align=true, $style='', $color=array(0,0,0)) { $filler = ' '; $prev_htmlLinkColorArray = $this->htmlLinkColorArray; $prev_htmlLinkFontStyle = $this->htmlLinkFontStyle; @@ -21580,12 +21758,12 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $dom = $this->getHtmlDomArray($html); foreach ($dom as $key => $value) { if ($value['value'] == '#TOC_PAGE_NUMBER#') { - $this->SetFont($dom[($key - 1)]['fontname']); + $this->setFont($dom[($key - 1)]['fontname']); $templates['F'.$level] = $this->isUnicodeFont(); } } } - $this->SetFont($current_font); + $this->setFont($current_font); $maxpage = 0; //used for pages on attached documents foreach ($this->outlines as $key => $outline) { // get HTML template @@ -21717,42 +21895,50 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: public function commitTransaction() { if (isset($this->objcopy)) { $this->objcopy->_destroy(true, true); + /* The unique file_id should not be used during cleanup again */ + $this->objcopy->file_id = NULL; unset($this->objcopy); } } /** * This method allows to undo the latest transaction by returning the latest saved TCPDF object with startTransaction(). - * @param $self (boolean) if true restores current class object to previous state without the need of reassignment via the returned value. + * @param boolean $self if true restores current class object to previous state without the need of reassignment via the returned value. * @return TCPDF object. * @public * @since 4.5.029 (2009-03-19) */ public function rollbackTransaction($self=false) { - if (isset($this->objcopy)) { - $this->_destroy(true, true); - if ($self) { - $objvars = get_object_vars($this->objcopy); - foreach ($objvars as $key => $value) { - $this->$key = $value; - } - } - return $this->objcopy; + if (!isset($this->objcopy)) { + return $this; } - return $this; + $file_id = $this->file_id; + $objcopy = $this->objcopy; + $this->_destroy(true, true); + if ($self) { + $objvars = get_object_vars($objcopy); + foreach ($objvars as $key => $value) { + $this->$key = $value; + } + $objcopy->_destroy(true, true); + unset($objcopy); + return $this; + } + $this->file_id = $file_id; + return $objcopy; } // --- MULTI COLUMNS METHODS ----------------------- /** * Set multiple columns of the same size - * @param $numcols (int) number of columns (set to zero to disable columns mode) - * @param $width (int) column width - * @param $y (int) column starting Y position (leave empty for current Y position) + * @param int $numcols number of columns (set to zero to disable columns mode) + * @param int $width column width + * @param int|null $y column starting Y position (leave empty for current Y position) * @public * @since 4.9.001 (2010-03-28) */ - public function setEqualColumns($numcols=0, $width=0, $y='') { + public function setEqualColumns($numcols=0, $width=0, $y=null) { $this->columns = array(); if ($numcols < 2) { $numcols = 0; @@ -21793,7 +21979,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set columns array. * Each column is represented by an array of arrays with the following keys: (w = width, s = space between columns, y = column top position). - * @param $columns (array) + * @param array $columns * @public * @since 4.9.001 (2010-03-28) */ @@ -21807,12 +21993,12 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set position at a given column - * @param $col (int) column number (from 0 to getNumberOfColumns()-1); empty string = current column. + * @param int|null $col column number (from 0 to getNumberOfColumns()-1); empty string = current column. * @public * @since 4.9.001 (2010-03-28) */ - public function selectColumn($col='') { - if (is_string($col)) { + public function selectColumn($col=null) { + if (TCPDF_STATIC::empty_string($col)) { $col = $this->current_column; } elseif ($col >= $this->num_columns) { $col = 0; @@ -21906,16 +22092,16 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set Text rendering mode. - * @param $stroke (int) outline size in user units (0 = disable). - * @param $fill (boolean) if true fills the text (default). - * @param $clip (boolean) if true activate clipping mode + * @param int $stroke outline size in user units (0 = disable). + * @param boolean $fill if true fills the text (default). + * @param boolean $clip if true activate clipping mode * @public * @since 4.9.008 (2009-04-02) */ public function setTextRenderingMode($stroke=0, $fill=true, $clip=false) { // Ref.: PDF 32000-1:2008 - 9.3.6 Text Rendering Mode // convert text rendering parameters - if ($stroke < 0) { + if ($stroke < 0 || !is_numeric($stroke)) { $stroke = 0; } if ($fill === true) { @@ -21963,7 +22149,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set parameters for drop shadow effect for text. - * @param $params (array) Array of parameters: enabled (boolean) set to true to enable shadow; depth_w (float) shadow width in user units; depth_h (float) shadow height in user units; color (array) shadow color or false to use the stroke color; opacity (float) Alpha value: real value from 0 (transparent) to 1 (opaque); blend_mode (string) blend mode, one of the following: Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity. + * @param array $params Array of parameters: enabled (boolean) set to true to enable shadow; depth_w (float) shadow width in user units; depth_h (float) shadow height in user units; color (array) shadow color or false to use the stroke color; opacity (float) Alpha value: real value from 0 (transparent) to 1 (opaque); blend_mode (string) blend mode, one of the following: Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity. * @since 5.9.174 (2012-07-25) * @public */ @@ -22005,7 +22191,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Return the text shadow parameters array. - * @return Array of parameters. + * @return array array of parameters. * @since 5.9.174 (2012-07-25) * @public */ @@ -22015,13 +22201,13 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Returns an array of chars containing soft hyphens. - * @param $word (array) array of chars - * @param $patterns (array) Array of hypenation patterns. - * @param $dictionary (array) Array of words to be returned without applying the hyphenation algorithm. - * @param $leftmin (int) Minimum number of character to leave on the left of the word without applying the hyphens. - * @param $rightmin (int) Minimum number of character to leave on the right of the word without applying the hyphens. - * @param $charmin (int) Minimum word length to apply the hyphenation algorithm. - * @param $charmax (int) Maximum length of broken piece of word. + * @param array $word array of chars + * @param array $patterns Array of hypenation patterns. + * @param array $dictionary Array of words to be returned without applying the hyphenation algorithm. + * @param int $leftmin Minimum number of character to leave on the left of the word without applying the hyphens. + * @param int $rightmin Minimum number of character to leave on the right of the word without applying the hyphens. + * @param int $charmin Minimum word length to apply the hyphenation algorithm. + * @param int $charmax Maximum length of broken piece of word. * @return array text with soft hyphens * @author Nicola Asuni * @since 4.9.012 (2010-04-12) @@ -22095,14 +22281,14 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Returns text with soft hyphens. - * @param $text (string) text to process - * @param $patterns (mixed) Array of hypenation patterns or a TEX file containing hypenation patterns. TEX patterns can be downloaded from http://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/ - * @param $dictionary (array) Array of words to be returned without applying the hyphenation algorithm. - * @param $leftmin (int) Minimum number of character to leave on the left of the word without applying the hyphens. - * @param $rightmin (int) Minimum number of character to leave on the right of the word without applying the hyphens. - * @param $charmin (int) Minimum word length to apply the hyphenation algorithm. - * @param $charmax (int) Maximum length of broken piece of word. - * @return array text with soft hyphens + * @param string $text text to process + * @param mixed $patterns Array of hypenation patterns or a TEX file containing hypenation patterns. TEX patterns can be downloaded from http://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/ + * @param array $dictionary Array of words to be returned without applying the hyphenation algorithm. + * @param int $leftmin Minimum number of character to leave on the left of the word without applying the hyphens. + * @param int $rightmin Minimum number of character to leave on the right of the word without applying the hyphens. + * @param int $charmin Minimum word length to apply the hyphenation algorithm. + * @param int $charmax Maximum length of broken piece of word. + * @return string text with soft hyphens * @author Nicola Asuni * @since 4.9.012 (2010-04-12) * @public @@ -22167,7 +22353,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Enable/disable rasterization of vector images using ImageMagick library. - * @param $mode (boolean) if true enable rasterization, false otherwise. + * @param boolean $mode if true enable rasterization, false otherwise. * @public * @since 5.0.000 (2010-04-27) */ @@ -22177,7 +22363,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Enable or disable default option for font subsetting. - * @param $enable (boolean) if true enable font subsetting by default. + * @param boolean $enable if true enable font subsetting by default. * @author Nicola Asuni * @public * @since 5.3.002 (2010-06-07) @@ -22192,7 +22378,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Return the default option for font subsetting. - * @return boolean default font subsetting state. + * @return bool default font subsetting state. * @author Nicola Asuni * @public * @since 5.3.002 (2010-06-07) @@ -22203,9 +22389,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Left trim the input string - * @param $str (string) string to trim - * @param $replace (string) string that replace spaces. - * @return left trimmed string + * @param string $str string to trim + * @param string $replace string that replace spaces. + * @return string left trimmed string * @author Nicola Asuni * @public * @since 5.8.000 (2010-08-11) @@ -22216,9 +22402,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Right trim the input string - * @param $str (string) string to trim - * @param $replace (string) string that replace spaces. - * @return right trimmed string + * @param string $str string to trim + * @param string $replace string that replace spaces. + * @return string right trimmed string * @author Nicola Asuni * @public * @since 5.8.000 (2010-08-11) @@ -22229,9 +22415,9 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Trim the input string - * @param $str (string) string to trim - * @param $replace (string) string that replace spaces. - * @return trimmed string + * @param string $str string to trim + * @param string $replace string that replace spaces. + * @return string trimmed string * @author Nicola Asuni * @public * @since 5.8.000 (2010-08-11) @@ -22244,7 +22430,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Return true if the current font is unicode type. - * @return true for unicode font, false otherwise. + * @return bool true for unicode font, false otherwise. * @author Nicola Asuni * @public * @since 5.8.002 (2010-08-14) @@ -22255,7 +22441,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Return normalized font name - * @param $fontfamily (string) property string containing font family names + * @param string $fontfamily property string containing font family names * @return string normalized font name * @author Nicola Asuni * @public @@ -22296,10 +22482,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: * An XObject Template is a PDF block that is a self-contained description of any sequence of graphics objects (including path objects, text objects, and sampled images). * An XObject Template may be painted multiple times, either on several pages or at several locations on the same page and produces the same results each time, subject only to the graphics state at the time it is invoked. * Note: X,Y coordinates will be reset to 0,0. - * @param $w (int) Template width in user units (empty string or zero = page width less margins). - * @param $h (int) Template height in user units (empty string or zero = page height less margins). - * @param $group (mixed) Set transparency group. Can be a boolean value or an array specifying optional parameters: 'CS' (solour space name), 'I' (boolean flag to indicate isolated group) and 'K' (boolean flag to indicate knockout group). - * @return int the XObject Template ID in case of success or false in case of error. + * @param int $w Template width in user units (empty string or zero = page width less margins). + * @param int $h Template height in user units (empty string or zero = page height less margins). + * @param mixed $group Set transparency group. Can be a boolean value or an array specifying optional parameters: 'CS' (solour space name), 'I' (boolean flag to indicate isolated group) and 'K' (boolean flag to indicate knockout group). + * @return string|false the XObject Template ID in case of success or false in case of error. * @author Nicola Asuni * @public * @since 5.8.017 (2010-08-24) @@ -22332,7 +22518,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: // set new environment $this->num_columns = 1; $this->current_column = 0; - $this->SetAutoPageBreak(false); + $this->setAutoPageBreak(false); if (($w === '') OR ($w <= 0)) { $w = $this->w - $this->lMargin - $this->rMargin; } @@ -22364,7 +22550,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: * End the current XObject Template started with startTemplate() and restore the previous graphic state. * An XObject Template is a PDF block that is a self-contained description of any sequence of graphics objects (including path objects, text objects, and sampled images). * An XObject Template may be painted multiple times, either on several pages or at several locations on the same page and produces the same results each time, subject only to the graphics state at the time it is invoked. - * @return int the XObject Template ID in case of success or false in case of error. + * @return string|false the XObject Template ID in case of success or false in case of error. * @author Nicola Asuni * @public * @since 5.8.017 (2010-08-24) @@ -22386,20 +22572,20 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: * You can print an XObject Template inside the currently opened Template. * An XObject Template is a PDF block that is a self-contained description of any sequence of graphics objects (including path objects, text objects, and sampled images). * An XObject Template may be painted multiple times, either on several pages or at several locations on the same page and produces the same results each time, subject only to the graphics state at the time it is invoked. - * @param $id (string) The ID of XObject Template to print. - * @param $x (int) X position in user units (empty string = current x position) - * @param $y (int) Y position in user units (empty string = current y position) - * @param $w (int) Width in user units (zero = remaining page width) - * @param $h (int) Height in user units (zero = remaining page height) - * @param $align (string) Indicates the alignment of the pointer next to template insertion relative to template height. The value can be:
                    • T: top-right for LTR or top-left for RTL
                    • M: middle-right for LTR or middle-left for RTL
                    • B: bottom-right for LTR or bottom-left for RTL
                    • N: next line
                    - * @param $palign (string) Allows to center or align the template on the current line. Possible values are:
                    • L : left align
                    • C : center
                    • R : right align
                    • '' : empty string : left for LTR or right for RTL
                    - * @param $fitonpage (boolean) If true the template is resized to not exceed page dimensions. + * @param string $id The ID of XObject Template to print. + * @param float|null $x X position in user units (empty string = current x position) + * @param float|null $y Y position in user units (empty string = current y position) + * @param float $w Width in user units (zero = remaining page width) + * @param float $h Height in user units (zero = remaining page height) + * @param string $align Indicates the alignment of the pointer next to template insertion relative to template height. The value can be:
                    • T: top-right for LTR or top-left for RTL
                    • M: middle-right for LTR or middle-left for RTL
                    • B: bottom-right for LTR or bottom-left for RTL
                    • N: next line
                    + * @param string $palign Allows to center or align the template on the current line. Possible values are:
                    • L : left align
                    • C : center
                    • R : right align
                    • '' : empty string : left for LTR or right for RTL
                    + * @param boolean $fitonpage If true the template is resized to not exceed page dimensions. * @author Nicola Asuni * @public * @since 5.8.017 (2010-08-24) * @see startTemplate(), endTemplate() */ - public function printTemplate($id, $x='', $y='', $w=0, $h=0, $align='', $palign='', $fitonpage=false) { + public function printTemplate($id, $x=null, $y=null, $w=0, $h=0, $align='', $palign='', $fitonpage=false) { if ($this->state != 2) { return; } @@ -22416,10 +22602,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } } // set default values - if ($x === '') { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if ($y === '') { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } // check page for no-write regions and adapt page margins if necessary @@ -22516,7 +22702,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } case 'N': { - $this->SetY($rb_y); + $this->setY($rb_y); break; } default:{ @@ -22527,7 +22713,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set the percentage of character stretching. - * @param $perc (int) percentage of stretching (100 = no stretching) + * @param int $perc percentage of stretching (100 = no stretching) * @author Nicola Asuni * @public * @since 5.9.000 (2010-09-29) @@ -22549,7 +22735,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Set the amount to increase or decrease the space between characters in a text. - * @param $spacing (float) amount to increase or decrease the space between characters in a text (0 = default spacing) + * @param float $spacing amount to increase or decrease the space between characters in a text (0 = default spacing) * @author Nicola Asuni * @public * @since 5.9.000 (2010-09-29) @@ -22586,7 +22772,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: * A no-write region is a portion of the page with a rectangular or trapezium shape that will not be covered when writing text or html code. * A region is always aligned on the left or right side of the page ad is defined using a vertical segment. * You can set multiple regions for the same page. - * @param $regions (array) array of no-write regions. For each region you can define an array as follow: ('page' => page number or empy for current page, 'xt' => X top, 'yt' => Y top, 'xb' => X bottom, 'yb' => Y bottom, 'side' => page side 'L' = left or 'R' = right). Omit this parameter to remove all regions. + * @param array $regions array of no-write regions. For each region you can define an array as follow: ('page' => page number or empy for current page, 'xt' => X top, 'yt' => Y top, 'xb' => X bottom, 'yb' => Y bottom, 'side' => page side 'L' = left or 'R' = right). Omit this parameter to remove all regions. * @author Nicola Asuni * @public * @since 5.9.003 (2010-10-13) @@ -22606,7 +22792,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: * A no-write region is a portion of the page with a rectangular or trapezium shape that will not be covered when writing text or html code. * A region is always aligned on the left or right side of the page ad is defined using a vertical segment. * You can set multiple regions for the same page. - * @param $region (array) array of a single no-write region array: ('page' => page number or empy for current page, 'xt' => X top, 'yt' => Y top, 'xb' => X bottom, 'yb' => Y bottom, 'side' => page side 'L' = left or 'R' = right). + * @param array $region array of a single no-write region array: ('page' => page number or empy for current page, 'xt' => X top, 'yt' => Y top, 'xb' => X bottom, 'yb' => Y bottom, 'side' => page side 'L' = left or 'R' = right). * @author Nicola Asuni * @public * @since 5.9.003 (2010-10-13) @@ -22625,7 +22811,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Remove a single no-write region. - * @param $key (int) region key + * @param int $key region key * @author Nicola Asuni * @public * @since 5.9.003 (2010-10-13) @@ -22641,10 +22827,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: * Check page for no-write regions and adapt current coordinates and page margins if necessary. * A no-write region is a portion of the page with a rectangular or trapezium shape that will not be covered when writing text or html code. * A region is always aligned on the left or right side of the page ad is defined using a vertical segment. - * @param $h (float) height of the text/image/object to print in user units - * @param $x (float) current X coordinate in user units - * @param $y (float) current Y coordinate in user units - * @return array($x, $y) + * @param float $h height of the text/image/object to print in user units + * @param float $x current X coordinate in user units + * @param float $y current Y coordinate in user units + * @return float[] array($x, $y) * @author Nicola Asuni * @protected * @since 5.9.003 (2010-10-13) @@ -22738,21 +22924,21 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Embedd a Scalable Vector Graphics (SVG) image. * NOTE: SVG standard is not yet fully implemented, use the setRasterizeVectorImages() method to enable/disable rasterization of vector images using ImageMagick library. - * @param $file (string) Name of the SVG file or a '@' character followed by the SVG data string. - * @param $x (float) Abscissa of the upper-left corner. - * @param $y (float) Ordinate of the upper-left corner. - * @param $w (float) Width of the image in the page. If not specified or equal to zero, it is automatically calculated. - * @param $h (float) Height of the image in the page. If not specified or equal to zero, it is automatically calculated. - * @param $link (mixed) URL or identifier returned by AddLink(). - * @param $align (string) Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:
                    • T: top-right for LTR or top-left for RTL
                    • M: middle-right for LTR or middle-left for RTL
                    • B: bottom-right for LTR or bottom-left for RTL
                    • N: next line
                    If the alignment is an empty string, then the pointer will be restored on the starting SVG position. - * @param $palign (string) Allows to center or align the image on the current line. Possible values are:
                    • L : left align
                    • C : center
                    • R : right align
                    • '' : empty string : left for LTR or right for RTL
                    - * @param $border (mixed) Indicates if borders must be drawn around the cell. The value can be a number:
                    • 0: no border (default)
                    • 1: frame
                    or a string containing some or all of the following characters (in any order):
                    • L: left
                    • T: top
                    • R: right
                    • B: bottom
                    or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) - * @param $fitonpage (boolean) if true the image is resized to not exceed page dimensions. + * @param string $file Name of the SVG file or a '@' character followed by the SVG data string. + * @param float|null $x Abscissa of the upper-left corner. + * @param float|null $y Ordinate of the upper-left corner. + * @param float $w Width of the image in the page. If not specified or equal to zero, it is automatically calculated. + * @param float $h Height of the image in the page. If not specified or equal to zero, it is automatically calculated. + * @param mixed $link URL or identifier returned by AddLink(). + * @param string $align Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:
                    • T: top-right for LTR or top-left for RTL
                    • M: middle-right for LTR or middle-left for RTL
                    • B: bottom-right for LTR or bottom-left for RTL
                    • N: next line
                    If the alignment is an empty string, then the pointer will be restored on the starting SVG position. + * @param string $palign Allows to center or align the image on the current line. Possible values are:
                    • L : left align
                    • C : center
                    • R : right align
                    • '' : empty string : left for LTR or right for RTL
                    + * @param mixed $border Indicates if borders must be drawn around the cell. The value can be a number:
                    • 0: no border (default)
                    • 1: frame
                    or a string containing some or all of the following characters (in any order):
                    • L: left
                    • T: top
                    • R: right
                    • B: bottom
                    or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) + * @param boolean $fitonpage if true the image is resized to not exceed page dimensions. * @author Nicola Asuni * @since 5.0.000 (2010-05-02) * @public */ - public function ImageSVG($file, $x='', $y='', $w=0, $h=0, $link='', $align='', $palign='', $border=0, $fitonpage=false) { + public function ImageSVG($file, $x=null, $y=null, $w=0, $h=0, $link='', $align='', $palign='', $border=0, $fitonpage=false) { if ($this->state != 2) { return; } @@ -22776,15 +22962,15 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $svgdata = substr($file, 1); } else { // SVG file $this->svgdir = dirname($file); - $svgdata = TCPDF_STATIC::fileGetContents($file); + $svgdata = $this->getCachedFileContents($file); } if ($svgdata === FALSE) { $this->Error('SVG file not found: '.$file); } - if ($x === '') { + if (TCPDF_STATIC::empty_string($x)) { $x = $this->x; } - if ($y === '') { + if (TCPDF_STATIC::empty_string($y)) { $y = $this->y; } // check page for no-write regions and adapt page margins if necessary @@ -22975,8 +23161,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $page_break_mode = $this->AutoPageBreak; $page_break_margin = $this->getBreakMargin(); $cell_padding = $this->cell_padding; - $this->SetCellPadding(0); - $this->SetAutoPageBreak(false); + $this->setCellPadding(0); + $this->setAutoPageBreak(false); // save the current graphic state $this->_out('q'.$this->epsmarker); // set initial clipping mask @@ -22986,22 +23172,24 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $f = ($this->h - $oy) * $this->k * (1 - $svgscale_y); $this->_out(sprintf('%F %F %F %F %F %F cm', $svgscale_x, 0, 0, $svgscale_y, ($e + $svgoffset_x), ($f + $svgoffset_y))); // creates a new XML parser to be used by the other XML functions - $this->parser = xml_parser_create('UTF-8'); - // the following function allows to use parser inside object - xml_set_object($this->parser, $this); + $parser = xml_parser_create('UTF-8'); // disable case-folding for this XML parser - xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); // sets the element handler functions for the XML parser - xml_set_element_handler($this->parser, 'startSVGElementHandler', 'endSVGElementHandler'); + xml_set_element_handler($parser, [$this, 'startSVGElementHandler'], [$this, 'endSVGElementHandler']); // sets the character data handler function for the XML parser - xml_set_character_data_handler($this->parser, 'segSVGContentHandler'); + xml_set_character_data_handler($parser, [$this, 'segSVGContentHandler']); // start parsing an XML document - if (!xml_parse($this->parser, $svgdata)) { - $error_message = sprintf('SVG Error: %s at line %d', xml_error_string(xml_get_error_code($this->parser)), xml_get_current_line_number($this->parser)); + if (!xml_parse($parser, $svgdata)) { + $error_message = sprintf('SVG Error: %s at line %d', xml_error_string(xml_get_error_code($parser)), xml_get_current_line_number($parser)); $this->Error($error_message); } // free this XML parser - xml_parser_free($this->parser); + xml_parser_free($parser); + + // >= PHP 7.0.0 "explicitly unset the reference to parser to avoid memory leaks" + unset($parser); + // restore previous graphic state $this->_out($this->epsmarker.'Q'); // restore graphic vars @@ -23040,7 +23228,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } case 'N':{ - $this->SetY($this->img_rb_y); + $this->setY($this->img_rb_y); break; } default:{ @@ -23062,13 +23250,13 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } $this->endlinex = $this->img_rb_x; // restore page break - $this->SetAutoPageBreak($page_break_mode, $page_break_margin); + $this->setAutoPageBreak($page_break_mode, $page_break_margin); $this->cell_padding = $cell_padding; } /** * Convert SVG transformation matrix to PDF. - * @param $tm (array) original SVG transformation matrix + * @param array $tm original SVG transformation matrix * @return array transformation matrix * @protected * @since 5.0.000 (2010-05-02) @@ -23089,7 +23277,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Apply SVG graphic transformation matrix. - * @param $tm (array) original SVG transformation matrix + * @param array $tm original SVG transformation matrix * @protected * @since 5.0.000 (2010-05-02) */ @@ -23099,15 +23287,15 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Apply the requested SVG styles (*** TO BE COMPLETED ***) - * @param $svgstyle (array) array of SVG styles to apply - * @param $prevsvgstyle (array) array of previous SVG style - * @param $x (int) X origin of the bounding box - * @param $y (int) Y origin of the bounding box - * @param $w (int) width of the bounding box - * @param $h (int) height of the bounding box - * @param $clip_function (string) clip function - * @param $clip_params (array) array of parameters for clipping function - * @return object style + * @param array $svgstyle array of SVG styles to apply + * @param array $prevsvgstyle array of previous SVG style + * @param int $x X origin of the bounding box + * @param int $y Y origin of the bounding box + * @param int $w width of the bounding box + * @param int $h height of the bounding box + * @param string $clip_function clip function + * @param array $clip_params array of parameters for clipping function + * @return string style * @author Nicola Asuni * @since 5.0.000 (2010-05-02) * @protected @@ -23135,12 +23323,12 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } // color $fill_color = TCPDF_COLORS::convertHTMLColorToDec($svgstyle['color'], $this->spot_colors); - $this->SetFillColorArray($fill_color); + $this->setFillColorArray($fill_color); // text color $text_color = TCPDF_COLORS::convertHTMLColorToDec($svgstyle['text-color'], $this->spot_colors); - $this->SetTextColorArray($text_color); + $this->setTextColorArray($text_color); // clip - if (preg_match('/rect\(([a-z0-9\-\.]*)[\s]*([a-z0-9\-\.]*)[\s]*([a-z0-9\-\.]*)[\s]*([a-z0-9\-\.]*)\)/si', $svgstyle['clip'], $regs)) { + if (preg_match('/rect\(([a-z0-9\-\.]*+)[\s]*+([a-z0-9\-\.]*+)[\s]*+([a-z0-9\-\.]*+)[\s]*+([a-z0-9\-\.]*+)\)/si', $svgstyle['clip'], $regs)) { $top = (isset($regs[1])?$this->getHTMLUnitToUnits($regs[1], 0, $this->svgunit, false):0); $right = (isset($regs[2])?$this->getHTMLUnitToUnits($regs[2], 0, $this->svgunit, false):0); $bottom = (isset($regs[3])?$this->getHTMLUnitToUnits($regs[3], 0, $this->svgunit, false):0); @@ -23257,15 +23445,15 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $cy -= $h; } $this->_out(sprintf('%F 0 0 %F %F %F cm', ($w * $this->k), ($h * $this->k), ($x * $this->k), ($cy * $this->k))); - if (count($gradient['stops']) > 1) { - $this->Gradient($gradient['type'], $gradient['coords'], $gradient['stops'], array(), false); + if ((is_array($gradient['stops']) || $gradient['stops'] instanceof Countable) && count($gradient['stops']) > 1) { + $this->Gradient($gradient['type'], $gradient['coords'], $gradient['stops']); } } elseif ($svgstyle['fill'] != 'none') { $fill_color = TCPDF_COLORS::convertHTMLColorToDec($svgstyle['fill'], $this->spot_colors); if ($svgstyle['fill-opacity'] != 1) { $this->setAlpha($this->alpha['CA'], 'Normal', $svgstyle['fill-opacity'], false); } - $this->SetFillColorArray($fill_color); + $this->setFillColorArray($fill_color); if ($svgstyle['fill-rule'] == 'evenodd') { $objstyle .= 'F*'; } else { @@ -23288,7 +23476,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: if (isset($svgstyle['stroke-dasharray']) AND !empty($svgstyle['stroke-dasharray']) AND ($svgstyle['stroke-dasharray'] != 'none')) { $stroke_style['dash'] = $svgstyle['stroke-dasharray']; } - $this->SetLineStyle($stroke_style); + $this->setLineStyle($stroke_style); $objstyle .= 'D'; } // font @@ -23383,7 +23571,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } } - $this->SetFont($font_family, $font_style, $font_size); + $this->setFont($font_family, $font_style, $font_size); $this->setFontStretching($font_stretch); $this->setFontSpacing($font_spacing); return $objstyle; @@ -23391,8 +23579,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Draws an SVG path - * @param $d (string) attribute d of the path SVG element - * @param $style (string) Style of rendering. Possible values are: + * @param string $d attribute d of the path SVG element + * @param string $style Style of rendering. Possible values are: *
                      *
                    • D or empty string: Draw (default).
                    • *
                    • F: Fill.
                    • @@ -23418,6 +23606,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } $paths = array(); $d = preg_replace('/([0-9ACHLMQSTVZ])([\-\+])/si', '\\1 \\2', $d); + $d = preg_replace('/(\.[0-9]+)(\.)/s', '\\1 \\2', $d); preg_match_all('/([ACHLMQSTVZ])[\s]*([^ACHLMQSTVZ\"]*)/si', $d, $paths, PREG_SET_ORDER); $x = 0; $y = 0; @@ -23451,7 +23640,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: $params = array(); if (isset($val[2])) { // get curve parameters - $rawparams = preg_split('/([\,\s]+)/si', trim($val[2])); + preg_match_all('/-?\d*\.?\d+/', trim($val[2]), $matches); + $rawparams = $matches[0]; $params = array(); foreach ($rawparams as $ck => $cp) { $params[$ck] = $this->getHTMLUnitToUnits($cp, 0, $this->svgunit, false); @@ -23759,15 +23949,13 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: } $firstcmd = false; } // end foreach - if (!empty($op)) { - $this->_out($op); - } + $this->_out($op); return array($xmin, $ymin, ($xmax - $xmin), ($ymax - $ymin)); } /** * Return the tag name without the namespace - * @param $name (string) Tag name + * @param string $name Tag name * @protected */ protected function removeTagNamespace($name) { @@ -23780,10 +23968,10 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Sets the opening SVG element handler function for the XML parser. (*** TO BE COMPLETED ***) - * @param $parser (resource) The first parameter, parser, is a reference to the XML parser calling the handler. - * @param $name (string) The second parameter, name, contains the name of the element for which this handler is called. If case-folding is in effect for this parser, the element name will be in uppercase letters. - * @param $attribs (array) The third parameter, attribs, contains an associative array with the element's attributes (if any). The keys of this array are the attribute names, the values are the attribute values. Attribute names are case-folded on the same criteria as element names. Attribute values are not case-folded. The original order of the attributes can be retrieved by walking through attribs the normal way, using each(). The first key in the array was the first attribute, and so on. - * @param $ctm (array) tranformation matrix for clipping mode (starting transformation matrix). + * @param resource|string $parser The first parameter, parser, is a reference to the XML parser calling the handler. + * @param string $name The second parameter, name, contains the name of the element for which this handler is called. If case-folding is in effect for this parser, the element name will be in uppercase letters. + * @param array $attribs The third parameter, attribs, contains an associative array with the element's attributes (if any). The keys of this array are the attribute names, the values are the attribute values. Attribute names are case-folded on the same criteria as element names. Attribute values are not case-folded. The original order of the attributes can be retrieved by walking through attribs the normal way, using each(). The first key in the array was the first attribute, and so on. + * @param array $ctm tranformation matrix for clipping mode (starting transformation matrix). * @author Nicola Asuni * @since 5.0.000 (2010-05-02) * @protected @@ -23978,7 +24166,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } case 'linearGradient': { - if ($this->pdfa_mode) { + if ($this->pdfa_mode && $this->pdfa_version < 2) { break; } if (!isset($attribs['id'])) { @@ -24018,7 +24206,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: break; } case 'radialGradient': { - if ($this->pdfa_mode) { + if ($this->pdfa_mode && $this->pdfa_version < 2) { break; } if (!isset($attribs['id'])) { @@ -24452,8 +24640,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Sets the closing SVG element handler function for the XML parser. - * @param $parser (resource) The first parameter, parser, is a reference to the XML parser calling the handler. - * @param $name (string) The second parameter, name, contains the name of the element for which this handler is called. If case-folding is in effect for this parser, the element name will be in uppercase letters. + * @param resource|string $parser The first parameter, parser, is a reference to the XML parser calling the handler. + * @param string $name The second parameter, name, contains the name of the element for which this handler is called. If case-folding is in effect for this parser, the element name will be in uppercase letters. * @author Nicola Asuni * @since 5.0.000 (2010-05-02) * @protected @@ -24559,8 +24747,8 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: /** * Sets the character data handler function for the XML parser. - * @param $parser (resource) The first parameter, parser, is a reference to the XML parser calling the handler. - * @param $data (string) The second parameter, data, contains the character data as a string. + * @param resource $parser The first parameter, parser, is a reference to the XML parser calling the handler. + * @param string $data The second parameter, data, contains the character data as a string. * @author Nicola Asuni * @since 5.0.000 (2010-05-02) * @protected @@ -24571,6 +24759,33 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: // --- END SVG METHODS ----------------------------------------------------- + /** + * Keeps files in memory, so it doesn't need to downloaded everytime in a loop + * @param string $file + * @return string + */ + protected function getCachedFileContents($file) + { + if (!isset($this->fileContentCache[$file])) { + $this->fileContentCache[$file] = TCPDF_STATIC::fileGetContents($file); + } + return $this->fileContentCache[$file]; + } + + /** + * Avoid multiple calls to an external server to see if a file exists + * @param string $file + * @return bool + */ + protected function fileExists($file) + { + if (isset($this->fileContentCache[$file]) || false !== $this->getImageBuffer($file)) { + return true; + } + + return TCPDF_STATIC::file_exists($file); + } + } // END OF TCPDF CLASS //============================================================+ diff --git a/tools/tcpdf/tcpdf_autoconfig.php b/tools/tcpdf/tcpdf_autoconfig.php index 6ec9ce83b..2bcfccb82 100644 --- a/tools/tcpdf/tcpdf_autoconfig.php +++ b/tools/tcpdf/tcpdf_autoconfig.php @@ -228,6 +228,10 @@ if (!defined('K_TCPDF_CALLS_IN_HTML')) { define('K_TCPDF_CALLS_IN_HTML', false); } +if (!defined('K_ALLOWED_TCPDF_TAGS')) { + define('K_ALLOWED_TCPDF_TAGS', ''); +} + if (!defined('K_TCPDF_THROW_EXCEPTION_ERROR')) { define('K_TCPDF_THROW_EXCEPTION_ERROR', false); } diff --git a/tools/tcpdf/tcpdf_barcodes_1d.php b/tools/tcpdf/tcpdf_barcodes_1d.php index 78bfc5b5b..45d35616c 100644 --- a/tools/tcpdf/tcpdf_barcodes_1d.php +++ b/tools/tcpdf/tcpdf_barcodes_1d.php @@ -53,7 +53,7 @@ class TCPDFBarcode { * Array representation of barcode. * @protected */ - protected $barcode_array; + protected $barcode_array = array(); /** * This is the class constructor. @@ -66,8 +66,8 @@ class TCPDFBarcode { *
                    • $arrcode['bcode'][$k]['w'] bar width in units.
                    • *
                    • $arrcode['bcode'][$k]['h'] bar height in units.
                    • *
                    • $arrcode['bcode'][$k]['p'] bar top position (0 = top, 1 = middle)
                    - * @param $code (string) code to print - * @param $type (string) type of barcode:
                    • C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
                    • C39+ : CODE 39 with checksum
                    • C39E : CODE 39 EXTENDED
                    • C39E+ : CODE 39 EXTENDED + CHECKSUM
                    • C93 : CODE 93 - USS-93
                    • S25 : Standard 2 of 5
                    • S25+ : Standard 2 of 5 + CHECKSUM
                    • I25 : Interleaved 2 of 5
                    • I25+ : Interleaved 2 of 5 + CHECKSUM
                    • C128 : CODE 128
                    • C128A : CODE 128 A
                    • C128B : CODE 128 B
                    • C128C : CODE 128 C
                    • EAN2 : 2-Digits UPC-Based Extension
                    • EAN5 : 5-Digits UPC-Based Extension
                    • EAN8 : EAN 8
                    • EAN13 : EAN 13
                    • UPCA : UPC-A
                    • UPCE : UPC-E
                    • MSI : MSI (Variation of Plessey code)
                    • MSI+ : MSI + CHECKSUM (modulo 11)
                    • POSTNET : POSTNET
                    • PLANET : PLANET
                    • RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
                    • KIX : KIX (Klant index - Customer index)
                    • IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200
                    • CODABAR : CODABAR
                    • CODE11 : CODE 11
                    • PHARMA : PHARMACODE
                    • PHARMA2T : PHARMACODE TWO-TRACKS
                    + * @param string $code code to print + * @param string $type type of barcode:
                    • C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
                    • C39+ : CODE 39 with checksum
                    • C39E : CODE 39 EXTENDED
                    • C39E+ : CODE 39 EXTENDED + CHECKSUM
                    • C93 : CODE 93 - USS-93
                    • S25 : Standard 2 of 5
                    • S25+ : Standard 2 of 5 + CHECKSUM
                    • I25 : Interleaved 2 of 5
                    • I25+ : Interleaved 2 of 5 + CHECKSUM
                    • C128 : CODE 128
                    • C128A : CODE 128 A
                    • C128B : CODE 128 B
                    • C128C : CODE 128 C
                    • EAN2 : 2-Digits UPC-Based Extension
                    • EAN5 : 5-Digits UPC-Based Extension
                    • EAN8 : EAN 8
                    • EAN13 : EAN 13
                    • UPCA : UPC-A
                    • UPCE : UPC-E
                    • MSI : MSI (Variation of Plessey code)
                    • MSI+ : MSI + CHECKSUM (modulo 11)
                    • POSTNET : POSTNET
                    • PLANET : PLANET
                    • RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
                    • KIX : KIX (Klant index - Customer index)
                    • IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200
                    • CODABAR : CODABAR
                    • CODE11 : CODE 11
                    • PHARMA : PHARMACODE
                    • PHARMA2T : PHARMACODE TWO-TRACKS
                    * @public */ public function __construct($code, $type) { @@ -85,9 +85,9 @@ class TCPDFBarcode { /** * Send barcode as SVG image object to the standard output. - * @param $w (int) Minimum width of a single bar in user units. - * @param $h (int) Height of barcode in user units. - * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent). + * @param int $w Minimum width of a single bar in user units. + * @param int $h Height of barcode in user units. + * @param string $color Foreground color (in SVG format) for bar elements (background is transparent). * @public */ public function getBarcodeSVG($w=2, $h=30, $color='black') { @@ -105,9 +105,9 @@ class TCPDFBarcode { /** * Return a SVG string representation of barcode. - * @param $w (int) Minimum width of a single bar in user units. - * @param $h (int) Height of barcode in user units. - * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent). + * @param int $w Minimum width of a single bar in user units. + * @param int $h Height of barcode in user units. + * @param string $color Foreground color (in SVG format) for bar elements (background is transparent). * @return string SVG code. * @public */ @@ -138,9 +138,9 @@ class TCPDFBarcode { /** * Return an HTML representation of barcode. - * @param $w (int) Width of a single bar element in pixels. - * @param $h (int) Height of a single bar element in pixels. - * @param $color (string) Foreground color for bar elements (background is transparent). + * @param int $w Width of a single bar element in pixels. + * @param int $h Height of a single bar element in pixels. + * @param string $color Foreground color for bar elements (background is transparent). * @return string HTML code. * @public */ @@ -164,9 +164,9 @@ class TCPDFBarcode { /** * Send a PNG image representation of barcode (requires GD or Imagick library). - * @param $w (int) Width of a single bar element in pixels. - * @param $h (int) Height of a single bar element in pixels. - * @param $color (array) RGB (0-255) foreground color for bar elements (background is transparent). + * @param int $w Width of a single bar element in pixels. + * @param int $h Height of a single bar element in pixels. + * @param array $color RGB (0-255) foreground color for bar elements (background is transparent). * @public */ public function getBarcodePNG($w=2, $h=30, $color=array(0,0,0)) { @@ -183,10 +183,10 @@ class TCPDFBarcode { /** * Return a PNG image representation of barcode (requires GD or Imagick library). - * @param $w (int) Width of a single bar element in pixels. - * @param $h (int) Height of a single bar element in pixels. - * @param $color (array) RGB (0-255) foreground color for bar elements (background is transparent). - * @return image or false in case of error. + * @param int $w Width of a single bar element in pixels. + * @param int $h Height of a single bar element in pixels. + * @param array $color RGB (0-255) foreground color for bar elements (background is transparent). + * @return string|Imagick|false image or false in case of error. * @public */ public function getBarcodePngData($w=2, $h=30, $color=array(0,0,0)) { @@ -241,9 +241,9 @@ class TCPDFBarcode { /** * Set the barcode. - * @param $code (string) code to print - * @param $type (string) type of barcode:
                    • C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
                    • C39+ : CODE 39 with checksum
                    • C39E : CODE 39 EXTENDED
                    • C39E+ : CODE 39 EXTENDED + CHECKSUM
                    • C93 : CODE 93 - USS-93
                    • S25 : Standard 2 of 5
                    • S25+ : Standard 2 of 5 + CHECKSUM
                    • I25 : Interleaved 2 of 5
                    • I25+ : Interleaved 2 of 5 + CHECKSUM
                    • C128 : CODE 128
                    • C128A : CODE 128 A
                    • C128B : CODE 128 B
                    • C128C : CODE 128 C
                    • EAN2 : 2-Digits UPC-Based Extension
                    • EAN5 : 5-Digits UPC-Based Extension
                    • EAN8 : EAN 8
                    • EAN13 : EAN 13
                    • UPCA : UPC-A
                    • UPCE : UPC-E
                    • MSI : MSI (Variation of Plessey code)
                    • MSI+ : MSI + CHECKSUM (modulo 11)
                    • POSTNET : POSTNET
                    • PLANET : PLANET
                    • RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
                    • KIX : KIX (Klant index - Customer index)
                    • IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200
                    • IMBPRE: Pre-processed Intelligent Mail Barcode - Onecode - USPS-B-3200, using only F,A,D,T letters
                    • CODABAR : CODABAR
                    • CODE11 : CODE 11
                    • PHARMA : PHARMACODE
                    • PHARMA2T : PHARMACODE TWO-TRACKS
                    - * @return array barcode array + * @param string $code code to print + * @param string $type type of barcode:
                    • C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
                    • C39+ : CODE 39 with checksum
                    • C39E : CODE 39 EXTENDED
                    • C39E+ : CODE 39 EXTENDED + CHECKSUM
                    • C93 : CODE 93 - USS-93
                    • S25 : Standard 2 of 5
                    • S25+ : Standard 2 of 5 + CHECKSUM
                    • I25 : Interleaved 2 of 5
                    • I25+ : Interleaved 2 of 5 + CHECKSUM
                    • C128 : CODE 128
                    • C128A : CODE 128 A
                    • C128B : CODE 128 B
                    • C128C : CODE 128 C
                    • EAN2 : 2-Digits UPC-Based Extension
                    • EAN5 : 5-Digits UPC-Based Extension
                    • EAN8 : EAN 8
                    • EAN13 : EAN 13
                    • UPCA : UPC-A
                    • UPCE : UPC-E
                    • MSI : MSI (Variation of Plessey code)
                    • MSI+ : MSI + CHECKSUM (modulo 11)
                    • POSTNET : POSTNET
                    • PLANET : PLANET
                    • RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
                    • KIX : KIX (Klant index - Customer index)
                    • IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200
                    • IMBPRE: Pre-processed Intelligent Mail Barcode - Onecode - USPS-B-3200, using only F,A,D,T letters
                    • CODABAR : CODABAR
                    • CODE11 : CODE 11
                    • PHARMA : PHARMACODE
                    • PHARMA2T : PHARMACODE TWO-TRACKS
                    + * @return void * @public */ public function setBarcode($code, $type) { @@ -373,7 +373,7 @@ class TCPDFBarcode { break; } default: { - $this->barcode_array = false; + $this->barcode_array = array(); $arrcode = false; break; } @@ -384,9 +384,9 @@ class TCPDFBarcode { /** * CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9. * General-purpose code in very wide use world-wide - * @param $code (string) code to represent. - * @param $extended (boolean) if true uses the extended mode. - * @param $checksum (boolean) if true add a checksum to the code. + * @param string $code code to represent. + * @param boolean $extended if true uses the extended mode. + * @param boolean $checksum if true add a checksum to the code. * @return array barcode representation. * @protected */ @@ -479,8 +479,8 @@ class TCPDFBarcode { /** * Encode a string to be used for CODE 39 Extended mode. - * @param $code (string) code to represent. - * @return encoded string. + * @param string $code code to represent. + * @return string encoded string. * @protected */ protected function encode_code39_ext($code) { @@ -530,8 +530,8 @@ class TCPDFBarcode { /** * Calculate CODE 39 checksum (modulo 43). - * @param $code (string) code to represent. - * @return char checksum. + * @param string $code code to represent. + * @return string char checksum. * @protected */ protected function checksum_code39($code) { @@ -553,7 +553,7 @@ class TCPDFBarcode { /** * CODE 93 - USS-93 * Compact code similar to Code 39 - * @param $code (string) code to represent. + * @param string $code code to represent. * @return array barcode representation. * @protected */ @@ -681,7 +681,7 @@ class TCPDFBarcode { /** * Calculate CODE 93 checksum (modulo 47). - * @param $code (string) code to represent. + * @param string $code code to represent. * @return string checksum code. * @protected */ @@ -730,7 +730,7 @@ class TCPDFBarcode { /** * Checksum for standard 2 of 5 barcodes. - * @param $code (string) code to process. + * @param string $code code to process. * @return int checksum. * @protected */ @@ -755,8 +755,8 @@ class TCPDFBarcode { * MSI. * Variation of Plessey code, with similar applications * Contains digits (0 to 9) and encodes the data only in the width of bars. - * @param $code (string) code to represent. - * @param $checksum (boolean) if true add a checksum to the code (modulo 11) + * @param string $code code to represent. + * @param boolean $checksum if true add a checksum to the code (modulo 11) * @return array barcode representation. * @protected */ @@ -814,8 +814,8 @@ class TCPDFBarcode { * Standard 2 of 5 barcodes. * Used in airline ticket marking, photofinishing * Contains digits (0 to 9) and encodes the data only in the width of bars. - * @param $code (string) code to represent. - * @param $checksum (boolean) if true add a checksum to the code + * @param string $code code to represent. + * @param boolean $checksum if true add a checksum to the code * @return array barcode representation. * @protected */ @@ -828,7 +828,7 @@ class TCPDFBarcode { $chr['5'] = '11101011101010'; $chr['6'] = '10111011101010'; $chr['7'] = '10101011101110'; - $chr['8'] = '10101110111010'; + $chr['8'] = '11101010111010'; $chr['9'] = '10111010111010'; if ($checksum) { // add checksum @@ -838,7 +838,7 @@ class TCPDFBarcode { // add leading zero if code-length is odd $code = '0'.$code; } - $seq = '11011010'; + $seq = '1110111010'; $clen = strlen($code); for ($i = 0; $i < $clen; ++$i) { $digit = $code[$i]; @@ -848,16 +848,15 @@ class TCPDFBarcode { } $seq .= $chr[$digit]; } - $seq .= '1101011'; + $seq .= '111010111'; $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); return $this->binseq_to_array($seq, $bararray); } /** - * Convert binary barcode sequence to TCPDF barcode array. - * @param $seq (string) barcode as binary sequence. - * @param $bararray (array) barcode array. - * òparam array $bararray TCPDF barcode array to fill up + * Convert binary barcode sequence to WarnockPDF barcode array. + * @param string $seq barcode as binary sequence. + * @param array $bararray barcode array to fill up * @return array barcode representation. * @protected */ @@ -886,8 +885,8 @@ class TCPDFBarcode { * Interleaved 2 of 5 barcodes. * Compact numeric code, widely used in industry, air cargo * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces. - * @param $code (string) code to represent. - * @param $checksum (boolean) if true add a checksum to the code + * @param string $code code to represent. + * @param boolean $checksum if true add a checksum to the code * @return array barcode representation. * @protected */ @@ -938,7 +937,7 @@ class TCPDFBarcode { } else { $t = false; // space } - $w = $seq[$j]; + $w = (float)$seq[$j]; $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); $bararray['maxw'] += $w; ++$k; @@ -950,8 +949,8 @@ class TCPDFBarcode { /** * C128 barcodes. * Very capable code, excellent density, high reliability; in very wide use world-wide - * @param $code (string) code to represent. - * @param $type (string) barcode type: A, B, C or empty for automatic switch (AUTO mode) + * @param string $code code to represent. + * @param string $type barcode type: A, B, C or empty for automatic switch (AUTO mode) * @return array barcode representation. * @protected */ @@ -1271,7 +1270,7 @@ class TCPDFBarcode { } else { $t = false; // space } - $w = $seq[$j]; + $w = (float)$seq[$j]; $bararray['bcode'][] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); $bararray['maxw'] += $w; } @@ -1281,7 +1280,7 @@ class TCPDFBarcode { /** * Split text code in A/B sequence for 128 code - * @param $code (string) code to split. + * @param string $code code to split. * @return array sequence * @protected */ @@ -1319,8 +1318,8 @@ class TCPDFBarcode { * EAN13: European Article Numbering international retail product code * UPC-A: Universal product code seen on almost all retail products in the USA and Canada * UPC-E: Short version of UPC symbol - * @param $code (string) code to represent. - * @param $len (string) barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A + * @param string $code code to represent. + * @param string $len barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A * @return array barcode representation. * @protected */ @@ -1512,8 +1511,8 @@ class TCPDFBarcode { * UPC-Based Extensions * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers * 5-Digit Ext.: Used to mark suggested retail price of books - * @param $code (string) code to represent. - * @param $len (string) barcode type: 2 = 2-Digit, 5 = 5-Digit + * @param string $code code to represent. + * @param string $len barcode type: 2 = 2-Digit, 5 = 5-Digit * @return array barcode representation. * @protected */ @@ -1587,8 +1586,8 @@ class TCPDFBarcode { /** * POSTNET and PLANET barcodes. * Used by U.S. Postal Service for automated mail sorting - * @param $code (string) zip code to represent. Must be a string containing a zip code of the form DDDDD or DDDDD-DDDD. - * @param $planet (boolean) if true print the PLANET barcode, otherwise print POSTNET + * @param string $code zip code to represent. Must be a string containing a zip code of the form DDDDD or DDDDD-DDDD. + * @param boolean $planet if true print the PLANET barcode, otherwise print POSTNET * @return array barcode representation. * @protected */ @@ -1660,8 +1659,8 @@ class TCPDFBarcode { * RMS4CC - CBC - KIX * RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index) * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service. - * @param $code (string) code to print - * @param $kix (boolean) if true prints the KIX variation (doesn't use the start and end symbols, and the checksum) - in this case the house number must be sufficed with an X and placed at the end of the code. + * @param string $code code to print + * @param boolean $kix if true prints the KIX variation (doesn't use the start and end symbols, and the checksum) - in this case the house number must be sufficed with an X and placed at the end of the code. * @return array barcode representation. * @protected */ @@ -1812,7 +1811,7 @@ class TCPDFBarcode { /** * CODABAR barcodes. * Older code often used in library systems, sometimes in blood banks - * @param $code (string) code to represent. + * @param string $code code to represent. * @return array barcode representation. * @protected */ @@ -1856,7 +1855,7 @@ class TCPDFBarcode { } else { $t = false; // space } - $w = $seq[$j]; + $w = (float)$seq[$j]; $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); $bararray['maxw'] += $w; ++$k; @@ -1868,7 +1867,7 @@ class TCPDFBarcode { /** * CODE11 barcodes. * Used primarily for labeling telecommunications equipment - * @param $code (string) code to represent. + * @param string $code code to represent. * @return array barcode representation. * @protected */ @@ -1947,7 +1946,7 @@ class TCPDFBarcode { } else { $t = false; // space } - $w = $seq[$j]; + $w = (float)$seq[$j]; $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); $bararray['maxw'] += $w; ++$k; @@ -1959,7 +1958,7 @@ class TCPDFBarcode { /** * Pharmacode * Contains digits (0 to 9) - * @param $code (string) code to represent. + * @param string $code code to represent. * @return array barcode representation. * @protected */ @@ -1985,7 +1984,7 @@ class TCPDFBarcode { /** * Pharmacode two-track * Contains digits (0 to 9) - * @param $code (string) code to represent. + * @param string $code code to represent. * @return array barcode representation. * @protected */ @@ -2047,7 +2046,7 @@ class TCPDFBarcode { * (requires PHP bcmath extension) * Intelligent Mail barcode is a 65-bar code for use on mail in the United States. * The fields are described as follows:
                    • The Barcode Identifier shall be assigned by USPS to encode the presort identification that is currently printed in human readable form on the optional endorsement line (OEL) as well as for future USPS use. This shall be two digits, with the second digit in the range of 0–4. The allowable encoding ranges shall be 00–04, 10–14, 20–24, 30–34, 40–44, 50–54, 60–64, 70–74, 80–84, and 90–94.
                    • The Service Type Identifier shall be assigned by USPS for any combination of services requested on the mailpiece. The allowable encoding range shall be 000http://it2.php.net/manual/en/function.dechex.php–999. Each 3-digit value shall correspond to a particular mail class with a particular combination of service(s). Each service program, such as OneCode Confirm and OneCode ACS, shall provide the list of Service Type Identifier values.
                    • The Mailer or Customer Identifier shall be assigned by USPS as a unique, 6 or 9 digit number that identifies a business entity. The allowable encoding range for the 6 digit Mailer ID shall be 000000- 899999, while the allowable encoding range for the 9 digit Mailer ID shall be 900000000-999999999.
                    • The Serial or Sequence Number shall be assigned by the mailer for uniquely identifying and tracking mailpieces. The allowable encoding range shall be 000000000–999999999 when used with a 6 digit Mailer ID and 000000-999999 when used with a 9 digit Mailer ID. e. The Delivery Point ZIP Code shall be assigned by the mailer for routing the mailpiece. This shall replace POSTNET for routing the mailpiece to its final delivery point. The length may be 0, 5, 9, or 11 digits. The allowable encoding ranges shall be no ZIP Code, 00000–99999, 000000000–999999999, and 00000000000–99999999999.
                    - * @param $code (string) code to print, separate the ZIP (routing code) from the rest using a minus char '-' (BarcodeID_ServiceTypeID_MailerID_SerialNumber-RoutingCode) + * @param string $code code to print, separate the ZIP (routing code) from the rest using a minus char '-' (BarcodeID_ServiceTypeID_MailerID_SerialNumber-RoutingCode) * @return array barcode representation. * @protected */ @@ -2171,8 +2170,8 @@ class TCPDFBarcode { /** * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200 - * - * @param $code (string) pre-formatted IMB barcode (65 chars "FADT") + * + * @param string $code pre-formatted IMB barcode (65 chars "FADT") * @return array barcode representation. * @protected */ @@ -2223,7 +2222,7 @@ class TCPDFBarcode { /** * Convert large integer number to hexadecimal representation. * (requires PHP bcmath extension) - * @param $number (string) number to convert specified as a string + * @param string $number number to convert specified as a string * @return string hexadecimal representation */ public function dec_to_hex($number) { @@ -2247,7 +2246,7 @@ class TCPDFBarcode { /** * Convert large hexadecimal number to decimal representation (string). * (requires PHP bcmath extension) - * @param $hex (string) hexadecimal number to convert specified as a string + * @param string $hex hexadecimal number to convert specified as a string * @return string hexadecimal representation */ public function hex_to_dec($hex) { @@ -2263,7 +2262,7 @@ class TCPDFBarcode { /** * Intelligent Mail Barcode calculation of Frame Check Sequence - * @param $code_arr (string) array of hexadecimal values (13 bytes holding 102 bits right justified). + * @param string $code_arr array of hexadecimal values (13 bytes holding 102 bits right justified). * @return int 11 bit Frame Check Sequence as integer (decimal base) * @protected */ @@ -2299,7 +2298,7 @@ class TCPDFBarcode { /** * Reverse unsigned short value - * @param $num (int) value to reversr + * @param int $num value to reversr * @return int reversed value * @protected */ @@ -2315,8 +2314,8 @@ class TCPDFBarcode { /** * generate Nof13 tables used for Intelligent Mail Barcode - * @param $n (int) is the type of table: 2 for 2of13 table, 5 for 5of13table - * @param $size (int) size of table (78 for n=2 and 1287 for n=5) + * @param int $n is the type of table: 2 for 2of13 table, 5 for 5of13table + * @param int $size size of table (78 for n=2 and 1287 for n=5) * @return array requested table * @protected */ diff --git a/tools/tcpdf/tcpdf_barcodes_2d.php b/tools/tcpdf/tcpdf_barcodes_2d.php index 13e236552..730361bd8 100644 --- a/tools/tcpdf/tcpdf_barcodes_2d.php +++ b/tools/tcpdf/tcpdf_barcodes_2d.php @@ -53,7 +53,7 @@ class TCPDF2DBarcode { * Array representation of barcode. * @protected */ - protected $barcode_array = false; + protected $barcode_array = array(); /** * This is the class constructor. @@ -62,8 +62,8 @@ class TCPDF2DBarcode { *
                  • $arrcode['num_rows'] required number of rows
                  • *
                  • $arrcode['num_cols'] required number of columns
                  • *
                  • $arrcode['bcode'][$r][$c] value of the cell is $r row and $c column (0 = transparent, 1 = black)
                  - * @param $code (string) code to print - * @param $type (string) type of barcode:
                  • DATAMATRIX : Datamatrix (ISO/IEC 16022)
                  • PDF417 : PDF417 (ISO/IEC 15438:2006)
                  • PDF417,a,e,t,s,f,o0,o1,o2,o3,o4,o5,o6 : PDF417 with parameters: a = aspect ratio (width/height); e = error correction level (0-8); t = total number of macro segments; s = macro segment index (0-99998); f = file ID; o0 = File Name (text); o1 = Segment Count (numeric); o2 = Time Stamp (numeric); o3 = Sender (text); o4 = Addressee (text); o5 = File Size (numeric); o6 = Checksum (numeric). NOTES: Parameters t, s and f are required for a Macro Control Block, all other parametrs are optional. To use a comma character ',' on text options, replace it with the character 255: "\xff".
                  • QRCODE : QRcode Low error correction
                  • QRCODE,L : QRcode Low error correction
                  • QRCODE,M : QRcode Medium error correction
                  • QRCODE,Q : QRcode Better error correction
                  • QRCODE,H : QR-CODE Best error correction
                  • RAW: raw mode - comma-separad list of array rows
                  • RAW2: raw mode - array rows are surrounded by square parenthesis.
                  • TEST : Test matrix
                  + * @param string $code code to print + * @param string $type type of barcode:
                  • DATAMATRIX : Datamatrix (ISO/IEC 16022)
                  • PDF417 : PDF417 (ISO/IEC 15438:2006)
                  • PDF417,a,e,t,s,f,o0,o1,o2,o3,o4,o5,o6 : PDF417 with parameters: a = aspect ratio (width/height); e = error correction level (0-8); t = total number of macro segments; s = macro segment index (0-99998); f = file ID; o0 = File Name (text); o1 = Segment Count (numeric); o2 = Time Stamp (numeric); o3 = Sender (text); o4 = Addressee (text); o5 = File Size (numeric); o6 = Checksum (numeric). NOTES: Parameters t, s and f are required for a Macro Control Block, all other parameters are optional. To use a comma character ',' on text options, replace it with the character 255: "\xff".
                  • QRCODE : QRcode Low error correction
                  • QRCODE,L : QRcode Low error correction
                  • QRCODE,M : QRcode Medium error correction
                  • QRCODE,Q : QRcode Better error correction
                  • QRCODE,H : QR-CODE Best error correction
                  • RAW: raw mode - comma-separad list of array rows
                  • RAW2: raw mode - array rows are surrounded by square parenthesis.
                  • TEST : Test matrix
                  */ public function __construct($code, $type) { $this->setBarcode($code, $type); @@ -79,9 +79,9 @@ class TCPDF2DBarcode { /** * Send barcode as SVG image object to the standard output. - * @param $w (int) Width of a single rectangle element in user units. - * @param $h (int) Height of a single rectangle element in user units. - * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent). + * @param int $w Width of a single rectangle element in user units. + * @param int $h Height of a single rectangle element in user units. + * @param string $color Foreground color (in SVG format) for bar elements (background is transparent). * @public */ public function getBarcodeSVG($w=3, $h=3, $color='black') { @@ -99,9 +99,9 @@ class TCPDF2DBarcode { /** * Return a SVG string representation of barcode. - * @param $w (int) Width of a single rectangle element in user units. - * @param $h (int) Height of a single rectangle element in user units. - * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent). + * @param int $w Width of a single rectangle element in user units. + * @param int $h Height of a single rectangle element in user units. + * @param string $color Foreground color (in SVG format) for bar elements (background is transparent). * @return string SVG code. * @public */ @@ -135,9 +135,9 @@ class TCPDF2DBarcode { /** * Return an HTML representation of barcode. - * @param $w (int) Width of a single rectangle element in pixels. - * @param $h (int) Height of a single rectangle element in pixels. - * @param $color (string) Foreground color for bar elements (background is transparent). + * @param int $w Width of a single rectangle element in pixels. + * @param int $h Height of a single rectangle element in pixels. + * @param string $color Foreground color for bar elements (background is transparent). * @return string HTML code. * @public */ @@ -164,9 +164,9 @@ class TCPDF2DBarcode { /** * Send a PNG image representation of barcode (requires GD or Imagick library). - * @param $w (int) Width of a single rectangle element in pixels. - * @param $h (int) Height of a single rectangle element in pixels. - * @param $color (array) RGB (0-255) foreground color for bar elements (background is transparent). + * @param int $w Width of a single rectangle element in pixels. + * @param int $h Height of a single rectangle element in pixels. + * @param array $color RGB (0-255) foreground color for bar elements (background is transparent). * @public */ public function getBarcodePNG($w=3, $h=3, $color=array(0,0,0)) { @@ -184,10 +184,10 @@ class TCPDF2DBarcode { /** * Return a PNG image representation of barcode (requires GD or Imagick library). - * @param $w (int) Width of a single rectangle element in pixels. - * @param $h (int) Height of a single rectangle element in pixels. - * @param $color (array) RGB (0-255) foreground color for bar elements (background is transparent). - * @return image or false in case of error. + * @param int $w Width of a single rectangle element in pixels. + * @param int $h Height of a single rectangle element in pixels. + * @param array $color RGB (0-255) foreground color for bar elements (background is transparent). + * @return string|Imagick|false image or false in case of error. * @public */ public function getBarcodePngData($w=3, $h=3, $color=array(0,0,0)) { @@ -245,9 +245,9 @@ class TCPDF2DBarcode { /** * Set the barcode. - * @param $code (string) code to print - * @param $type (string) type of barcode:
                  • DATAMATRIX : Datamatrix (ISO/IEC 16022)
                  • PDF417 : PDF417 (ISO/IEC 15438:2006)
                  • PDF417,a,e,t,s,f,o0,o1,o2,o3,o4,o5,o6 : PDF417 with parameters: a = aspect ratio (width/height); e = error correction level (0-8); t = total number of macro segments; s = macro segment index (0-99998); f = file ID; o0 = File Name (text); o1 = Segment Count (numeric); o2 = Time Stamp (numeric); o3 = Sender (text); o4 = Addressee (text); o5 = File Size (numeric); o6 = Checksum (numeric). NOTES: Parameters t, s and f are required for a Macro Control Block, all other parametrs are optional. To use a comma character ',' on text options, replace it with the character 255: "\xff".
                  • QRCODE : QRcode Low error correction
                  • QRCODE,L : QRcode Low error correction
                  • QRCODE,M : QRcode Medium error correction
                  • QRCODE,Q : QRcode Better error correction
                  • QRCODE,H : QR-CODE Best error correction
                  • RAW: raw mode - comma-separad list of array rows
                  • RAW2: raw mode - array rows are surrounded by square parenthesis.
                  • TEST : Test matrix
                  - * @return array + * @param string $code code to print + * @param string $type type of barcode:
                  • DATAMATRIX : Datamatrix (ISO/IEC 16022)
                  • PDF417 : PDF417 (ISO/IEC 15438:2006)
                  • PDF417,a,e,t,s,f,o0,o1,o2,o3,o4,o5,o6 : PDF417 with parameters: a = aspect ratio (width/height); e = error correction level (0-8); t = total number of macro segments; s = macro segment index (0-99998); f = file ID; o0 = File Name (text); o1 = Segment Count (numeric); o2 = Time Stamp (numeric); o3 = Sender (text); o4 = Addressee (text); o5 = File Size (numeric); o6 = Checksum (numeric). NOTES: Parameters t, s and f are required for a Macro Control Block, all other parameters are optional. To use a comma character ',' on text options, replace it with the character 255: "\xff".
                  • QRCODE : QRcode Low error correction
                  • QRCODE,L : QRcode Low error correction
                  • QRCODE,M : QRcode Medium error correction
                  • QRCODE,Q : QRcode Better error correction
                  • QRCODE,H : QR-CODE Best error correction
                  • RAW: raw mode - comma-separad list of array rows
                  • RAW2: raw mode - array rows are surrounded by square parenthesis.
                  • TEST : Test matrix
                  + * @return void */ public function setBarcode($code, $type) { $mode = explode(',', $type); @@ -338,7 +338,7 @@ class TCPDF2DBarcode { break; } default: { - $this->barcode_array = false; + $this->barcode_array = array(); } } } diff --git a/tools/tcpdf/tcpdf_import.php b/tools/tcpdf/tcpdf_import.php index 09d726ba0..57f9f4f4b 100644 --- a/tools/tcpdf/tcpdf_import.php +++ b/tools/tcpdf/tcpdf_import.php @@ -60,8 +60,8 @@ class TCPDF_IMPORT extends TCPDF { /** * Import an existing PDF document - * @param $filename (string) Filename of the PDF document to import. - * @return true in case of success, false otherwise + * @param string $filename Filename of the PDF document to import. + * @return void * @public * @since 1.0.000 (2011-05-24) */ diff --git a/tools/tcpdf/tcpdf_parser.php b/tools/tcpdf/tcpdf_parser.php index bd3d719c7..4156230a3 100644 --- a/tools/tcpdf/tcpdf_parser.php +++ b/tools/tcpdf/tcpdf_parser.php @@ -91,8 +91,8 @@ class TCPDF_PARSER { /** * Parse a PDF document an return an array of objects. - * @param $data (string) PDF data to parse. - * @param $cfg (array) Array of configuration parameters: + * @param string $data PDF data to parse. + * @param array $cfg Array of configuration parameters: * 'die_for_errors' : if true termitate the program execution in case of error, otherwise thows an exception; * 'ignore_filter_decoding_errors' : if true ignore filter decoding errors; * 'ignore_missing_filter_decoders' : if true ignore missing filter decoding errors. @@ -130,7 +130,7 @@ class TCPDF_PARSER { /** * Set the configuration parameters. - * @param $cfg (array) Array of configuration parameters: + * @param array $cfg Array of configuration parameters: * 'die_for_errors' : if true termitate the program execution in case of error, otherwise thows an exception; * 'ignore_filter_decoding_errors' : if true ignore filter decoding errors; * 'ignore_missing_filter_decoders' : if true ignore missing filter decoding errors. @@ -150,7 +150,7 @@ class TCPDF_PARSER { /** * Return an array of parsed PDF document objects. - * @return (array) Array of parsed PDF document objects. + * @return array Array of parsed PDF document objects. * @public * @since 1.0.000 (2011-06-26) */ @@ -160,9 +160,9 @@ class TCPDF_PARSER { /** * Get Cross-Reference (xref) table and trailer data from PDF document data. - * @param $offset (int) xref offset (if know). - * @param $xref (array) previous xref array (if any). - * @return Array containing xref and trailer data. + * @param int $offset xref offset (if know). + * @param array $xref previous xref array (if any). + * @return array containing xref and trailer data. * @protected * @since 1.0.000 (2011-05-24) */ @@ -202,9 +202,9 @@ class TCPDF_PARSER { /** * Decode the Cross-Reference section - * @param $startxref (int) Offset at which the xref section starts (position of the 'xref' keyword). - * @param $xref (array) Previous xref array (if any). - * @return Array containing xref and trailer data. + * @param int $startxref Offset at which the xref section starts (position of the 'xref' keyword). + * @param array $xref Previous xref array (if any). + * @return array containing xref and trailer data. * @protected * @since 1.0.000 (2011-06-20) */ @@ -274,9 +274,9 @@ class TCPDF_PARSER { /** * Decode the Cross-Reference Stream section - * @param $startxref (int) Offset at which the xref section starts. - * @param $xref (array) Previous xref array (if any). - * @return Array containing xref and trailer data. + * @param int $startxref Offset at which the xref section starts. + * @param array $xref Previous xref array (if any). + * @return array containing xref and trailer data. * @protected * @since 1.0.003 (2013-03-16) */ @@ -489,7 +489,7 @@ class TCPDF_PARSER { /** * Get object type, raw value and offset to next object - * @param $offset (int) Object offset. + * @param int $offset Object offset. * @return array containing object type, raw value and offset to next object * @protected * @since 1.0.000 (2011-06-20) @@ -667,9 +667,9 @@ class TCPDF_PARSER { /** * Get content of indirect object. - * @param $obj_ref (string) Object number and generation number separated by underscore character. - * @param $offset (int) Object offset. - * @param $decoding (boolean) If true decode streams. + * @param string $obj_ref Object number and generation number separated by underscore character. + * @param int $offset Object offset. + * @param boolean $decoding If true decode streams. * @return array containing object data. * @protected * @since 1.0.000 (2011-05-24) @@ -712,7 +712,7 @@ class TCPDF_PARSER { /** * Get the content of object, resolving indect object reference if necessary. - * @param $obj (string) Object value. + * @param string $obj Object value. * @return array containing object data. * @protected * @since 1.0.000 (2011-06-26) @@ -734,8 +734,8 @@ class TCPDF_PARSER { /** * Decode the specified stream. - * @param $sdic (array) Stream's dictionary array. - * @param $stream (string) Stream to decode. + * @param array $sdic Stream's dictionary array. + * @param string $stream Stream to decode. * @return array containing decoded stream data and remaining filters. * @protected * @since 1.0.000 (2011-06-22) @@ -796,7 +796,7 @@ class TCPDF_PARSER { /** * Throw an exception or print an error message and die if the K_TCPDF_PARSER_THROW_EXCEPTION_ERROR constant is set to true. - * @param $msg (string) The error message + * @param string $msg The error message * @public * @since 1.0.000 (2011-05-23) */ diff --git a/tools/tcpdf/tools/.htaccess b/tools/tcpdf/tools/.htaccess index 224784069..9996e3bde 100644 --- a/tools/tcpdf/tools/.htaccess +++ b/tools/tcpdf/tools/.htaccess @@ -1,10 +1,10 @@ -# Apache 2.2 - - Order deny,allow - Deny from all - - # Apache 2.4 Require all denied - \ No newline at end of file + + +# Apache 2.2 + + Order Deny,Allow + Deny from all + diff --git a/tools/tcpdf/tools/index.php b/tools/tcpdf/tools/index.php deleted file mode 100644 index aca71cfae..000000000 --- a/tools/tcpdf/tools/index.php +++ /dev/null @@ -1,35 +0,0 @@ - -* @copyright 2007-2017 PrestaShop SA -* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) -* International Registered Trademark & Property of PrestaShop SA -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../'); -exit;